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.
First, include the Boei initialization code in your script:
window.BQ=window.BQ||[];window.Boei=window.Boei||function(u){BQ.push(u)};
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'});
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.
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.
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 IDemail, name, phone, company — visitor contact fieldscustom — 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');
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.
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.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 {{...}}.
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:
custom object is merged, not replaced. In the example above, school_id from t=8s survives the t=15s update.?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.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.
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-set tags to filter chatbot knowledge base content (skips the pre-chat tag question flow):
Boei({tags: 'tag-slug-1,tag-slug-2'});
Use Boei() to modify global settings:
Boei({brand_background: 'green'});
brand_background: Set the background color of the widgetbrandcolor: Set the primary brand colorbrandcolor_text: Set the text color for brand elementsbutton_hover_label: Set the label that appears on button hoverposition: Set the widget position ('bottom_left', 'bottom_right', 'top_left', 'top_right')shape: Set the widget shape ('circle', 'square')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
}});
type: Channel type (e.g., "link", "form", "chat")title: Display title for the channelurl: URL for link channelsoptions: Additional settings (optional)new_window: Open link in new window (boolean)custom_conversion_label: Custom label for conversion trackingposition: Position in the widget (integer)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.
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.
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();
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 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.
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.).
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.
Here's a comprehensive list of variables you can edit using Boei SDK:
brand_background: Background color or gradient for the widgetbrandcolor: Primary brand colorbrandcolor_text: Text color for brand elementsbutton_hover_label: Label that appears on button hoverposition: 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 iconbutton_width: Width of the buttonbutton_height: Height of the buttonbutton_margin_x: Horizontal margin for the buttonbutton_margin_y: Vertical margin for the buttontrigger_after_seconds: Time in seconds before triggering the widgettrigger_message: Message to display when widget is triggeredtrigger_message_only_new_visitor: Show trigger message only for new visitors (boolean)close_trigger_after_seconds: Time in seconds before closing the trigger messageauto_open_after_seconds: Time in seconds before automatically opening the widgetauto_open_only_new_visitor: Auto-open only for new visitors (boolean)notification_badge_after_seconds: Time in seconds before showing a notification badgeglow_after_seconds: Time in seconds before applying a glow effectglow_duration_seconds: Duration of the glow effect in secondsglow_color: Color of the glow effectcustom_css: Custom CSS to apply to the widgeticon_svg: Custom SVG icon for the widget buttonbutton_image: Custom image for the widget buttonclose_src: Custom image for the close buttonloading_src: Custom loading imagedebug_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 timerhide_on_pages: List of pages to hide the widget onis_spa: Treat as Single Page Application (boolean)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)name: Pre-fill visitor nameemail: Pre-fill visitor emailphone: Pre-fill visitor phonecompany: Pre-fill visitor companyid: Pre-fill visitor ID (for CRM integration)notes: Pre-fill visitor noteslocale: Force chatbot AI into this language (ISO code, e.g. nl, de), overrides browser Accept-Languagetags: Comma-separated tag slugs for KB filteringcustom: Object of arbitrary string values available to AI Action webhooks as {{context.custom.KEY}} or {{custom.KEY}}add_channel)type: Channel type (e.g., "link", "form", "chat")title: Display title for the channelurl: URL for link channelsoptions: Additional channel-specific optionsnew_window: Open link in new window (boolean)custom_conversion_label: Custom label for conversion trackingRemember, not all variables may be applicable to every use case.