Javascript Sdk

JavaScript SDK


Boei's SDK allows you to dynamically configure and customize your Boei widget. Here's how to use it:

How to get there: Go to Setup → Widget in the top menu → click your widget to get your widget ID.

Setup

First, include the Boei initialization code in your script:

window.BQ=window.BQ||[];window.Boei=window.Boei||function(u){BQ.push(u)};

Pre-setting Visitor Information

Pre-fill visitor contact info so they don't have to enter it manually:

Boei({
    name: 'John Doe',
    email: 'john@example.com',
    phone: '+1234567890',
    company: 'Acme Inc',
    id: 'customer-123',
    notes: 'VIP customer'
});

You can also set fields individually:

Boei({name: 'John Doe'});
Boei({email: 'john@example.com'});

Verifying Logged-in Visitors (JWT)

The plain identity fields above are set in the browser, so a visitor can open devtools and change them. That's fine for pre-filling contact forms, but if you want the Boei inbox to trust that a message really came from a specific logged-in user, sign the identity on your backend as a short-lived JWT and pass it to Boei.

How to get there: Go to Setup → Widget in the top menu → pick your website → Integrations → SDK sub-tab.

1. Generate a signing secret

On the SDK sub-tab, click Generate signing secret. Copy the secret and store it in your backend's config (env var, secrets manager, etc.). One secret per website. Rotating the secret invalidates all outstanding tokens.

2. Mint a JWT on your backend

When a logged-in user loads a page with the Boei widget, mint an HS256 JWT signed with the secret. Keep the lifetime short (5-15 minutes is typical) and refresh it on the next page load.

Recognized claims:

  • exp — expiry timestamp (required; tokens without exp are rejected)
  • sub — your internal user ID
  • email, name, phone, company — visitor contact fields
  • custom — object of string values, same shape as the SDK's custom bag. Numbers are coerced to strings; booleans, nested objects, and arrays are dropped.

Any other top-level claim in the payload is ignored. Put anything non-standard inside custom.

Example (Node.js, using jsonwebtoken):

const jwt = require('jsonwebtoken');

const token = jwt.sign({
    sub: user.id,
    email: user.email,
    name: user.full_name,
    custom: {
        plan_tier: user.plan,
        account_id: user.account_id
    },
    exp: Math.floor(Date.now() / 1000) + 15 * 60
}, process.env.BOEI_IDENTITY_SIGNING_SECRET, { algorithm: 'HS256' });

Example (PHP, using firebase/php-jwt):

use Firebase\JWT\JWT;

$token = JWT::encode([
    'sub'    => $user->id,
    'email'  => $user->email,
    'name'   => $user->full_name,
    'custom' => ['plan_tier' => $user->plan],
    'exp'    => time() + 15 * 60,
], env('BOEI_IDENTITY_SIGNING_SECRET'), 'HS256');

3. Pass the token to Boei

Render the token into the page and hand it to Boei alongside (or instead of) the plaintext identity fields:

Boei({ jwt: '<token from your backend>' });

That's it. Boei re-verifies the signature and expiry on every message the visitor sends, stamps the thread and matched contact as verified, and shows a verified badge next to the visitor's name in the inbox metadata.

Notes

  • HS256 only for now. Symmetric signing with a shared secret. If you need RS256 / JWKS, let us know.
  • Verification runs on every message, not just once at load. An expired token stops being trusted immediately even mid-conversation. Refresh the token before it expires (e.g. on route change or a keep-alive tick).
  • Plaintext fields still work. If you pass both jwt and name/email/etc., the verified values from the JWT win for anything that gets stamped on the inbox thread; the plaintext fields are treated as best-effort pre-fill only.
  • No JWT = no verified badge. Visitors without a token still chat normally, they just don't get the verified badge and their identity fields remain browser-editable.
  • Rotate on breach. Rotating the signing secret in the dashboard invalidates every outstanding JWT. Any browser tab still holding an old token will fail verification on its next message and needs a fresh token from your backend.

Passing Custom Context to the Chatbot

Boei accepts a free-form custom object alongside the built-in identity fields. Use it to pass anything the chatbot's tools should know about the current visitor or page context (event ID, tenant ID, order number, current article, etc.):

Boei({
    email: 'jane@example.com',
    id: 'u42',
    custom: {
        event_id: 'ev-2026-08-14',
        school_id: 'sch-a',
        plan_tier: 'pro'
    }
});

Only strings and numbers are supported as values. Numbers are coerced to strings. Booleans, nested objects, and arrays are dropped with a [Boei] console warning so misconfigured values don't silently fail. Each value is capped at 500 characters; anything longer is dropped with the same warning.

Custom fields are available to your Chatbot's AI Actions as webhook placeholders:

  • {{context.custom.event_id}} (canonical form)
  • {{custom.event_id}} (short form, works the same way)

Example webhook URL configured on an AI Action:

https://api.example.com/events/{{context.custom.event_id}}?school={{context.custom.school_id}}

If a custom key is not set at the time the tool fires, the placeholder is stripped from the URL rather than sent as literal {{...}}.

Runtime Context Updates

For single-page apps where identity or context only resolves after the widget is already loaded (e.g. React apps waiting on auth, or users switching contexts mid-session), you can call Boei({...}) at any time and the currently-open chatbot conversation will pick up the new values on its next message. No reload is required:

// t=0: page loads, widget mounts with no identity
// t=3s: user login resolves
Boei({ email: 'jane@example.com' });

// t=8s: user picks an event
Boei({
    id: 'u42',
    custom: { event_id: 'ev1', school_id: 'sch-a' }
});

// t=15s: user switches to a different event mid-conversation
Boei({ custom: { event_id: 'ev2' } });

Notes:

  • The custom object is merged, not replaced. In the example above, school_id from t=8s survives the t=15s update.
  • Any message sent to the chatbot after the update includes the new context, so AI Action webhooks fire with the latest values.
  • The URL parameters passed on first paint (?name=...) are the fallback for the initial render. Runtime updates use a separate parent-to-iframe channel, so they work even after the chatbot iframe has mounted.

Verifying updates in the browser console

To confirm your Boei({...}) calls are actually reaching the chatbot, opt in to debug logging before the widget mounts:

Boei({ debug_context: true });

Every runtime context push from your page to the chatbot is then logged to the chatbot iframe's devtools console as [boei] customerInfo update, with the merged payload as the second argument. Open devtools, pick the chatbot iframe context from the top-frame dropdown, and you can watch identity/custom fields flow through in real time. Remove the line before shipping to production.

Forcing a Locale

By default, the chatbot picks the visitor's language from the browser's Accept-Language header. If your app already knows what language the visitor prefers (from their account settings, a URL segment like /nl/, etc.), you can force the chatbot into that locale:

Boei({ locale: 'nl' });

Two-letter ISO codes (en, nl, de, fr, es). BCP-47 tags like nl-NL or en_US are accepted; only the first two letters are used. This overrides browser detection for AI responses, refusal messages, and live-chat escalation strings.

Note: this only affects the chatbot AI side. The widget UI (launcher label, "Powered by Boei", pre-chat form labels, etc.) is translated by the auto-translate flow. Enable Auto-translate on the domain if you want the widget UI translated as well.

The widget UI translation is generated in the background the first time a visitor requests a new locale. That first visitor will still see the untranslated UI. Subsequent visitors on the same locale get the translated UI once the background job completes (usually within a minute). This is a one-time cost per locale per domain.

Pre-setting Chatbot Tags

Pre-set tags to filter chatbot knowledge base content (skips the pre-chat tag question flow):

Boei({tags: 'tag-slug-1,tag-slug-2'});

Widget Settings

Use Boei() to modify global settings:

Boei({brand_background: 'green'});

Key Variables:

  • brand_background: Set the background color of the widget
  • brandcolor: Set the primary brand color
  • brandcolor_text: Set the text color for brand elements
  • button_hover_label: Set the label that appears on button hover
  • position: Set the widget position ('bottom_left', 'bottom_right', 'top_left', 'top_right')
  • shape: Set the widget shape ('circle', 'square')

Adding Channels

Add new channels to your widget:

Boei({add_channel: {
    type: "link",
    title: "External Website Link",
    url: "https://boei.help",
    options: {
        new_window: true,
        custom_conversion_label: 'Custom' // Can be null for default
    },
    position: 2 // The position in the widget
}});

Channel Properties:

  • type: Channel type (e.g., "link", "form", "chat")
  • title: Display title for the channel
  • url: URL for link channels
  • options: Additional settings (optional)
    • new_window: Open link in new window (boolean)
    • custom_conversion_label: Custom label for conversion tracking
  • position: Position in the widget (integer)

Controlling the Widget Programmatically

Boei exposes a small set of methods you can call to open, close, and interact with the widget from your own JavaScript. These are useful for hooking the widget up to your own buttons, form submissions, search bars, route changes, or analytics events.

Open and close

Boei.open();              // open the widget
Boei.open('whatsapp');    // open straight into a specific channel by key
Boei.close();             // close the widget panel
Boei.isOpen();            // returns true / false

The channel key is the one you set in the channel's settings inside your widget.

Hide and show the launcher button

If you want full control over when the widget appears (for example only after a custom button is clicked), you can hide the launcher entirely and show it again later:

Boei.hideLauncher();
Boei.showLauncher();

Start a chatbot conversation with a pre-filled question

Boei.ask(message) opens the chatbot and sends message as the first user message automatically. This is great for turning a search bar, a "ask AI" link, or a help-page CTA directly into a live conversation.

Boei.ask('How do I install Boei on WordPress?');

If your widget has multiple chatbots, pass the chatbot's channel key as a second argument:

Boei.ask('How do I install Boei on WordPress?', 'support-bot');

Notes:

  • If a conversation is already in progress, the pre-filled message is ignored so it doesn't barge in mid-chat.
  • If the widget has no chatbot channel, the call is a no-op and a warning is logged to the console.

Passing visitor info before opening

If you know the visitor's name, email, etc. (for example because they're already logged in to your site), set it first and then open the widget so the chatbot and any forms have it pre-filled:

Boei({ name: 'Jane Doe', email: 'jane@example.com' });
Boei.open();
// or
Boei({ name: 'Jane Doe', email: 'jane@example.com' });
Boei.ask('What plan should I be on?');

See Pre-setting Visitor Information above for the full list of supported fields.

Advanced: full widget instance access

If you need access to internals that aren't exposed by the flat API, pass a function to Boei() to get a reference to the live widget instance:

Boei(function (widget) {
    // widget.* full access
});

The callback runs as soon as the widget is mounted, or is queued if you call it before the widget script has loaded.

See Custom Trigger for non-JS ways to open the widget (CSS class, URL parameter, etc.).

Multiple changes

You can chain multiple configurations:

Boei({brand_background: 'green'});
Boei({add_channel: {...}});
Boei({button_hover_label: 'Need Help?'});

Remember, settings are applied in the order they are called, with later calls potentially overwriting earlier ones.

List of Editable Variables

Here's a comprehensive list of variables you can edit using Boei SDK:

General Appearance

  • brand_background: Background color or gradient for the widget
  • brandcolor: Primary brand color
  • brandcolor_text: Text color for brand elements
  • button_hover_label: Label that appears on button hover
  • position: Widget position ('bottom_left', 'bottom_right', 'top_left', 'top_right')
  • shape: Widget shape ('circle', 'square')
  • opacity: Widget opacity (0 to 1)
  • button_icon_size: Size of the button icon
  • button_width: Width of the button
  • button_height: Height of the button
  • button_margin_x: Horizontal margin for the button
  • button_margin_y: Vertical margin for the button

Widget Behavior

  • trigger_after_seconds: Time in seconds before triggering the widget
  • trigger_message: Message to display when widget is triggered
  • trigger_message_only_new_visitor: Show trigger message only for new visitors (boolean)
  • close_trigger_after_seconds: Time in seconds before closing the trigger message
  • auto_open_after_seconds: Time in seconds before automatically opening the widget
  • auto_open_only_new_visitor: Auto-open only for new visitors (boolean)
  • notification_badge_after_seconds: Time in seconds before showing a notification badge
  • glow_after_seconds: Time in seconds before applying a glow effect
  • glow_duration_seconds: Duration of the glow effect in seconds
  • glow_color: Color of the glow effect

Customization

  • custom_css: Custom CSS to apply to the widget
  • icon_svg: Custom SVG icon for the widget button
  • button_image: Custom image for the widget button
  • close_src: Custom image for the close button
  • loading_src: Custom loading image

Functionality

  • debug_context: Log runtime Boei({...}) context updates to the chatbot iframe's browser console for verifying integration (boolean, dev-only)
  • test_mode: Enable test mode (boolean)
  • allow_identifiers: Allow user identifiers (boolean)
  • direct_open_when_one_channel: Directly open single channel (boolean)
  • display_button_watermark: Show button watermark (boolean)
  • display_helper_watermark: Show helper watermark (boolean)
  • display_close_trigger_message: Show close button on trigger message (boolean)
  • display_countdown_timer: Show countdown timer (boolean)
  • display_countdown_timer_seconds_left: Seconds left for countdown timer
  • hide_on_pages: List of pages to hide the widget on
  • is_spa: Treat as Single Page Application (boolean)

Analytics and Integrations

  • use_google_analytics4: Use Google Analytics 4 (boolean)
  • use_plausible_analytics: Use Plausible Analytics (boolean)
  • use_google_tag_manager: Use Google Tag Manager (boolean)
  • use_simple_analytics: Use Simple Analytics (boolean)
  • use_facebook_pixel: Use Facebook Pixel (boolean)

Chatbot / Visitor

  • name: Pre-fill visitor name
  • email: Pre-fill visitor email
  • phone: Pre-fill visitor phone
  • company: Pre-fill visitor company
  • id: Pre-fill visitor ID (for CRM integration)
  • notes: Pre-fill visitor notes
  • locale: Force chatbot AI into this language (ISO code, e.g. nl, de), overrides browser Accept-Language
  • tags: Comma-separated tag slugs for KB filtering
  • custom: Object of arbitrary string values available to AI Action webhooks as {{context.custom.KEY}} or {{custom.KEY}}

Channel-specific (used with add_channel)

  • type: Channel type (e.g., "link", "form", "chat")
  • title: Display title for the channel
  • url: URL for link channels
  • options: Additional channel-specific options
    • new_window: Open link in new window (boolean)
    • custom_conversion_label: Custom label for conversion tracking

Remember, not all variables may be applicable to every use case.