Widget Initialization Parameters
First create a channel and obtain the code in Embed Code. If the cabinet settings are sufficient, paste the generated code unchanged. This page is for developers who embed the chat in their own container, pass authenticated visitor data, or control configuration from code.
Where to Start
Decide two things:
- Where the chat belongs: over the page (
popup) or inside your own block (embedded). - Where appearance and features come from: saved channel settings (
remote) or site code (local).
For most sites, popup with config_source: "remote" is the simplest choice: saved cabinet changes appear without replacing the code. Use local when the site itself versions and controls the settings.
Placement Mode
popupopens over the page from a floating button;embeddedoccupies the suppliedcontainerand has no floating button.
For embedded, pass an existing CSS selector or DOM Element. Initialization fails if the container cannot be found. open(), close(), and toggle() work in both modes.
button_only: true renders only the floating-button appearance without a chat iframe. The button is not interactive, open(), close(), and toggle() open nothing, and isOpen() returns false. This mode is intended for a standalone button preview and cannot be combined with embedded. Because no iframe is created and remote channel settings are not loaded, define its appearance through theme.button in the site code.
Configuration Source
- Dynamic in the cabinet corresponds to
config_source: "remote": theme and features load from saved channel settings. Language and placement remain in the site's code. Change persistentthemeandfeaturessettings in the cabinet; on initial load, onlytheme_modefrom a suppliedthemeobject is used as a light, dark, or system-theme override. - Static corresponds to
config_source: "local":themeandfeaturesare included in the code. After changing persistent settings, copy the new code and update it on the site.
Choose the mode in Embed code. In the screenshot, 1 marks Static, 2 marks Dynamic, and 3 marks visitor identity linking. The generated code appears below this selector.

The cabinet preview may show unsaved changes, but it does not change the configuration of the live site.
Embed the Widget in a Container
This step applies only to embedded mode. The container must have actual dimensions: the widget occupies 100% of its width and height. theme.width and theme.height size the popup window and do not replace the container dimensions.
<div id="senler-widget" style="width: 100%; height: 600px"></div>
<!-- Load the loader script from the generated channel code before this block. -->
<script>
SenlerWidget.init({
channel_id: "xxx",
config_source: "local",
display_mode: "embedded",
container: "#senler-widget",
theme: {
border_radius: 18,
},
features: {
element_selection: true,
},
});
</script>
This example places the chat in #senler-widget and enables page-element selection. Take the loader-script URL and the real channel_id from the generated cabinet code. Add authenticated visitor data only with the server-side signature described below.
Visitor Data
user contains the data Senler uses to create or update the widget lead. Pass only information about the current visitor that your data-processing policy allows.
| Field | What to pass and how it is used |
|---|---|
external_id | A stable authenticated-user ID from your system. When it is present, user_hash is required. |
user_hash | An HMAC-SHA256 signature of external_id, calculated by the site backend with the channel secret and encoded as 64 hexadecimal characters. |
email | The lead email. A non-empty value is saved on creation and updates an existing lead. |
phone | The loader and API accept a string, but the current version does not save it to the lead profile. Do not rely on this field until the server contract changes. |
first_name, last_name | The lead's first and last name. Non-empty values are saved on creation and update. |
avatar_url | A public HTTPS URL without embedded credentials. An explicitly passed empty, invalid, or local value means no avatar and removes the existing lead's previously saved avatar. |
data | A plain JSON-compatible object with additional data. On repeat initialization, a non-empty object is shallow-merged into saved data; omitted keys are not deleted. |
Always pass external_id together with user_hash: initialization is rejected without the signature. The cabinet identity-linking switch adds these fields to generated code and exposes the secret and backend examples; it does not enable or disable the verification itself. Never put the secret in HTML, loader configuration, or any other browser code. Linking to an Authorized User shows the complete setup.
For example, a Node.js backend signs the exact external_id value as follows:
import { createHmac } from "node:crypto";
const userHash = createHmac("sha256", channelSecret)
.update(externalId)
.digest("hex");
Send only the externalId and resulting userHash values to the browser as external_id and user_hash. Keep channelSecret on the server.
With a signed identity link, history belongs to the same account across devices. Without external_id, Senler creates an anonymous browser session, so previous history is unavailable after switching browser or device.
To avoid assembling user manually, click the gear button next to the generated code. It is marked 1 in the screenshot and opens Code building example.

In the dialog, select the required fields and copy the result. For user.data, enter a key in 9 and a value in 10; add a row with 11, remove a row with 12, and copy the generated example with 13. The builder demonstrates the accepted data shape but does not change the channel's primary code. phone is present even though the current backend does not persist it.

Appearance
theme supports:
| Key | What the visitor sees |
|---|---|
chat_title | Chat heading. |
default_dialog_title | Name of a new dialog. |
theme_mode | Light, dark, or system theme: light, dark, auto. |
position | Popup position: bottom-right, bottom-left, top-right, top-left. |
width, height | Window size: width 200–800, height 300–1000 pixels. |
border_radius | Corner radius from 0 to 50 pixels. |
shadow_enabled | Window shadow. |
welcome_message | Placeholder in the message input. The technical key name is retained for compatibility. |
empty_state_message | Greeting in an empty new dialog. |
welcome_buttons | Quick questions before the conversation starts. |
button | Floating-button position and colors. |
Localized text accepts { ru?: string, en?: string }. Each welcome_buttons array may contain up to 8 non-empty unique strings of no more than 120 characters. Clicking a button immediately sends its text.
SenlerWidget.init({
channel_id: "xxx",
config_source: "local",
theme: {
empty_state_message: {
ru: "Здравствуйте! Чем помочь?",
en: "Hello! How can I help?",
},
welcome_buttons: {
ru: ["Узнать цену", "Связаться с оператором"],
en: ["Check the price", "Contact an operator"],
},
},
});
theme.button.position accepts the same four positions plus hidden. Use theme.button.position: "hidden" to hide the floating button; theme.position: "hidden" is invalid. Set theme.button.light.background, theme.button.light.icon, theme.button.dark.background, and theme.button.dark.icon in #RRGGBB format.
welcome_buttons cannot be changed through updateRuntime. In remote mode, save them in the cabinet. In local mode, update the code and initialize the widget again.
Chat Features
features key | What it enables | Default |
|---|---|---|
file_upload | File attachments. | true |
voice_messages | Voice-message recording. | false |
emoji | Emoji picker. | true |
split_view | At widths of 640 pixels and above, shows the dialog list beside the current chat. | true |
element_selection | Selecting an element on the host page for a question. | false |
The element_selection flag alone is not enough for stable references. Add data-ai-* markup so labels remain clear and elements can be found again.
init Parameter Reference
The loader accepts only supported top-level keys:
| Key | Type | Required / default | Purpose |
|---|---|---|---|
channel_id | string | Required | Widget channel ID from the generated code. |
user | object | Optional | Visitor data. Whenever external_id is supplied, it must have a server-generated user_hash. |
theme | object | Optional | Appearance, popup dimensions, text, and floating button for config_source: "local". With remote, only the initial theme_mode is read from this object. |
features | object | Optional | Chat features for config_source: "local". |
lang | "ru" | "en" | "auto" | "auto" | Interface language. |
config_source | "local" | "remote" | "remote" | Settings in code or saved channel settings. |
display_mode | "popup" | "embedded" | "popup" | Chat placement mode. |
button_only | boolean | false | A non-interactive floating button without a chat iframe. Incompatible with embedded. |
container | CSS selector or DOM Element | Required for embedded | Embedded-widget container. Pass it at popup startup as well if you will switch modes through the Public API later. |
shell | object | Empty object | collapse_button and mobile_edge_swipe; both are off until set to true. |
onCollapse | function | Optional | Callback for an embedded-widget collapse request. |
contextProvider | function | Optional | Synchronous provider of persistent page context. |
customActions | object | Empty set | Site buttons and actions available in chat. |
customActionsLanguage | "ru" | "en" | Not set | Description language for customActions. |
debug | boolean | false | Additional loader console messages. |
Other top-level keys are errors. Calling SenlerWidget.init(...) again destroys the current instance and creates a new one, so use Public API methods for temporary changes.
If Loading Is Delayed
The progress indicator appears when loading exceeds 4 seconds. After 10 seconds, the loader displays “Loading is taking longer. We are still retrying.” and a Copy for Support button. This is informational: automatic retries continue.
The report contains loader and protocol versions, attempt number, duration and failure stage, network state, and resource checks. Query parameters, request contents, channel and user IDs, and tokens are excluded.
The external report covers iframe startup. If an error occurs inside an already loaded chat, use the action shown in that particular interface message. Do not promise a retry button when a specific state does not provide one.
What to Configure Next
After initialization works, follow Page and Message Context to pass the current screen and relevant business object to the agent. Start marking buttons and fields only after an ordinary message and context work independently.