Installation

Slack Bubble connects each website chat widget to one Slack channel. A Slack workspace can have multiple widgets, and a website can embed several of them.

Create a widget

  1. Click Add to Slack and connect your workspace.
  2. Open the dashboard and click Create widget.
  3. Enter a name, select a Slack channel, and choose the welcome message, color, and icon.
  4. Save the widget and invite Bubble to its channel using /invite @Bubble (use your development app's name when testing).
  5. Copy its embed code into your website before the closing </body> tag.
<script src="https://slack-bubble.com/bubble.js?widget_id=WIDGET_ID" async></script>

Replace WIDGET_ID with the ID from the dashboard. Each channel can have one widget. You can embed that widget on more than one website.

Multiple widgets on a page

Include each widget's snippet:

<script src="https://slack-bubble.com/bubble.js?widget_id=SALES_WIDGET_ID" async></script>
<script src="https://slack-bubble.com/bubble.js?widget_id=SUPPORT_WIDGET_ID" async></script>

The launchers stack automatically. Each widget has its own saved draft, conversation, unread count, and position. Opening a chat closes the other open panel. Give widgets distinct names, colors, or icons so visitors can tell them apart.

Customer identity

Anonymous visitors get a session for each widget. To identify a logged-in customer across widgets in the same Slack workspace, set the user before loading the embeds:

<script>
  window.bubble = {
    user: {
      name: "Customer name",
      email: "[email protected]",
      external_id: "YOUR_CUSTOMER_ID",
      signature: "SERVER_GENERATED_SIGNATURE"
    }
  };
</script>

Generate the signature on your server using the team's signature secret:

import { createHash } from "node:crypto";

const signature = createHash("sha256")
  .update(externalId + signatureSecret)
  .digest("base64url");

Keep the signature secret on your server. The same signed identity works across that team's widgets, while conversation history and access tokens remain scoped to each widget.

For different identities or widgets belonging to different teams, provide settings per widget:

<script>
  window.bubble = {
    widgets: {
      SALES_WIDGET_ID: { user: { external_id: "123", signature: "SALES_SIGNATURE" } },
      SUPPORT_WIDGET_ID: { user: { external_id: "456", signature: "SUPPORT_SIGNATURE" } }
    }
  };
</script>

Per-widget user settings take precedence over window.bubble.user.

Widget callbacks

The callback receives both the widget controller and its ID:

window.onSlackBubbleReady = function (widget, widgetId) {
  // For example, open Support from your own button.
  if (widgetId === "SUPPORT_WIDGET_ID") {
    document.getElementById("contact-support").onclick = () => widget.onOpen();
  }
};

Controllers are also available in window.slackBubbleWidgets[widgetId] after initialization. Including the same widget twice does not create a second instance.

Manage widgets

Select a widget in the dashboard to update its settings or disable it. Disabling prevents new loads and blocks messaging and realtime delivery for existing sessions. Changing its channel affects new conversations; existing conversations stay in their original Slack threads.

Working-hours and offline-message fields are reserved in the widget data model; scheduling is not yet implemented. Domain restrictions are not currently supported.

Verify installation

  1. Open the website and send a message from each widget.
  2. Confirm each message reaches the correct Slack channel.
  3. Reply in each Slack thread and confirm only the corresponding widget receives it.
  4. Reload the page and verify each widget restores its own conversation.

If a widget does not load, check its ID and enabled setting. If messages do not reach Slack, verify the app has been invited to the selected channel and that the channel is available.

API and development

Visitor login takes widget_id instead of team_id. The server resolves the owning team. Use the WebSocket method get_widget for public widget configuration. All authenticated operations use the widget associated with the visitor's token.

This release requires a fresh database and new widget-based embeds. No existing-data migration or old team-based embed alias is provided. To show a widget on the app's own pages, set DEMO_WIDGET_ID to an enabled widget ID.