Widget Integration

Como embeber el widget de Rivelko en tu sitio web / How to embed the Rivelko widget

The Rivelko widget is a standalone JavaScript bundle (~28KB) that renders a floating chat bubble or classic form on any website. It uses Shadow DOM for complete style isolation -- it will never conflict with your CSS.

Embed Snippet

Add this before </body> on any page:

html
<script
  src="https://app.rivelko.com/api/widget"
  data-form-id="YOUR_FORM_ID"
></script>
AttributeRequiredDescription
data-form-idYesYour form's unique ID (found in the dashboard)
data-base-urlNoOverride the API base URL (for self-hosting)

How It Works

  1. The script loads and reads data-form-id from the <script> tag
  2. Fetches the form configuration from GET /api/forms/:id/config
  3. Checks if the current domain is in the form's allowedDomains list
  4. Renders the appropriate UI based on formType:
    • CONVERSATIONAL -- AI chat that asks questions one by one
    • CLASSIC -- Traditional form with all fields visible at once
  5. Submits responses via the public API (/api/chat or /api/forms/:id/submit)

Domain Setup

Your website's domain must be in the form's Allowed Domains list. Configure this in the form editor under Settings > Allowed Domains.

Tu dominio debe estar en la lista de dominios permitidos del formulario.

Domain configuredAllows
example.comexample.com, www.example.com, sub.example.com
localhost:3000localhost:3000 only
(empty list)Blocked everywhere -- must add at least one domain

Subdomains are automatically allowed when you add the root domain. Protocols (https://) are stripped automatically.

Widget Behavior

Conversational (Chat)

  • Floating bubble button appears at the configured position
  • Click opens a chat panel with the welcome message
  • AI asks questions one at a time based on your form config
  • Conversation state is persisted in localStorage (survives page reloads)
  • After completion, shows the goodbye message

Classic (Form)

  • Same floating bubble button
  • Click opens a panel with all form fields visible
  • Client-side validation for required fields and field types
  • After submission, shows the goodbye message and a "Submit another" option
  • Panel auto-closes 3 seconds after successful submission

Blocked

If the requesting domain is not in the form's Allowed Domains, the widget shows an informative message explaining that the domain is not allowed.

Domain enforcement is applied server-side: GET /api/forms/:id/config checks the request Origin and only returns the form content (name, welcome/goodbye messages, questions) to allowed origins. Unauthorized origins receive a minimal projection with those fields stripped, so no form data is exposed. The POST /api/chat and POST /api/forms/:id/submit endpoints reject unauthorized origins with 403 Domain not allowed.

An empty Allowed Domains list blocks the widget on every domain — you must add at least one domain for the form to serve.

Customization

Style options are configured in the form editor under Design:

OptionValuesDescription
primaryColorAny hex color (default #E11D62)Accent color for bubble and UI
avatarUrlImage URL or nullAvatar shown in chat header
positionbottom-right, bottom-leftWhere the bubble appears
bubbleIconIcon name or nullCustom icon for the bubble button

Custom Integration (Without Widget)

If you need full control over the UI, you can skip the widget and call the APIs directly.

Si necesitas control total sobre la interfaz, puedes usar las APIs directamente sin el widget.

Conversational Form

javascript
// 1. Fetch form config
const config = await fetch(
  "https://app.rivelko.com/api/forms/YOUR_FORM_ID/config"
).then((r) => r.json());

// 2. Start a conversation
const response = await fetch("https://app.rivelko.com/api/chat", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    formId: "YOUR_FORM_ID",
    message: "Hello",
  }),
});

const conversationId = response.headers.get("X-Conversation-Id");

// Read the streaming response
const reader = response.body.getReader();
const decoder = new TextDecoder();
let assistantMessage = "";

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  assistantMessage += decoder.decode(value, { stream: true });
  // Update your UI with the progressive text
}

// 3. Continue the conversation
const next = await fetch("https://app.rivelko.com/api/chat", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    formId: "YOUR_FORM_ID",
    conversationId: conversationId,
    message: "My name is Juan",
  }),
});
// ... read stream again

Classic Form

javascript
// 1. Fetch form config to get questions
const config = await fetch(
  "https://app.rivelko.com/api/forms/YOUR_FORM_ID/config"
).then((r) => r.json());

// 2. Render your own form using config.questions
// Each question has: text, type, required, options

// 3. Submit answers
const result = await fetch(
  "https://app.rivelko.com/api/forms/YOUR_FORM_ID/submit",
  {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      answers: {
        "What is your name?": "Juan Perez",
        "Email": "juan@example.com",
      },
    }),
  }
).then((r) => r.json());

console.log(result.conversationId); // Store for reference

Troubleshooting

IssueCauseSolution
Widget shows "Domain not allowed"Domain not in allowedDomainsAdd your domain in form Settings
Widget doesn't appearForm not publishedPublish the form in the editor
Widget doesn't appearWrong form IDCheck the data-form-id attribute
Chat doesn't respondForm type is CLASSICCLASSIC forms use the submit endpoint, not chat
"Account inactive" errorSubscription expired (paid plans)Renew subscription in Settings > Billing