ruLog in to Senler

Embedding in a container

First include the loader script. The embedded mode places chat in your website container; popup shows a separate window. button_only is incompatible with embedded.

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",
    display_mode: "embedded",
    container: "#senler-widget",
    theme: {
      border_radius: 18,
    },
    features: {
      element_selection: true,
    },
  });
</script>

This example places chat in #senler-widget and enables page element selection. Take the loader URL and real channel_id from the embed code in the cabinet. Only include an authenticated visitor's data together with a server signature.

Widget Inside a Hideable Panel

If your site hides an embedded widget inside its own panel or tab, report whether the visitor can see the chat. For an initially hidden panel, pass surfaceVisible: false during init, then update it whenever the panel is shown or hidden:

<button onclick="setChatPanelVisible(true)">Open chat</button>
<div id="chat-panel" hidden>
  <button onclick="setChatPanelVisible(false)">Close chat</button>
  <div id="senler-widget" style="height: 600px"></div>
</div>
<script>
  // Load the script from the channel's embed code before this example.
  SenlerWidget.init({
    channel_id: "xxx",
    display_mode: "embedded",
    container: "#senler-widget",
    surfaceVisible: false,
  });

  function setChatPanelVisible(visible) {
    document.getElementById("chat-panel").hidden = !visible;
    SenlerWidget.updateRuntime({ surfaceVisible: visible });
  }
</script>

surfaceVisible controls read receipts, not layout: it does not hide or open the container on its own. Messages are not marked as read inside a hidden panel or a background browser tab. Authentication, explicitly sent requests, and WebMCP continue to work. Built-in popup opening and closing, as well as open() and close() calls, are handled automatically.

In React, pass current visibility through runtime={{ surfaceVisible: panelIsVisible }}; there is no need to change config or recreate the widget. React integration example.

Collapsing an embedded widget

Popup mode already has a close button in its header. It hides the window, and the floating button reopens the same instance.

In embedded mode, enable shell.collapse_button: true when the user needs a collapse button in the header. The button only tells the site that the user wants to collapse the widget; the site calls SenlerWidget.close() or closes its outer panel.

SenlerWidget.init({
  channel_id: "xxx",
  display_mode: "embedded",
  container: "#senler-widget",
  shell: {
    collapse_button: true,
  },
  onCollapse(detail) {
    console.log("The user requested collapse", detail);
    SenlerWidget.close();
  },
});

Instead of onCollapse, subscribe once to the event:

window.addEventListener("senler-widget:collapse-request", (event) => {
  if (event.detail.display_mode === "embedded") {
    SenlerWidget.close();
  }
});

detail contains channel_id and display_mode. If both the callback and event listener are configured, both handlers run. Normally choose one to avoid collapsing twice.

CLOSE_WIDGET and COLLAPSE_WIDGET are internal iframe protocol messages. The site must not send them through postMessage.

Mobile gesture

shell.mobile_edge_swipe: true enables a left-edge swipe inside the widget. The loader does not close the interface; it dispatches senler-widget:mobile-edge-swipe.

window.addEventListener("senler-widget:mobile-edge-swipe", (event) => {
  if (event.detail.side === "left") {
    closeMobilePanel();
  }
});

detail contains channel_id, display_mode, and side: "left". This is a navigation signal for the site, not a replacement for the collapse button.

Use SenlerWidget.close() for ordinary hiding: it also hides the embedded wrapper while preserving state. SenlerWidget.open() shows the same instance. SenlerWidget.destroy() removes the widget and requires another init afterwards. Method reference.