Skip to main content
The live chat widget lets customers contact your team from your website or application. It uses a workspace public key and a widget API route to create and continue conversations.

Install the widget

Add the snippet to pages where chat should be available.
<script>
  window.Woes =
    window.Woes ||
    function () {
      (window.Woes.q = window.Woes.q || []).push(arguments);
    };
</script>
<script
  async
  src="https://cdn.woes.dev/widget.js"
  data-public-key="YOUR_WIDGET_PUBLIC_KEY"
  data-api="https://YOUR_APP_ORIGIN/api/widget/messages">
</script>
AttributeRequiredPurpose
srcYesLoads the hosted Woes widget script.
data-public-keyYesIdentifies the workspace for public widget requests.
data-apiYesPoints the widget at the Woes widget message route for your deployment.
The widget public key is intentionally public. It identifies the workspace but does not grant general table, admin, or authenticated workspace access.

Identify signed-in customers

When your app knows the customer, pass stable identity and display context.
<script>
  window.Woes("identify", {
    externalId: "user_123",
    email: "customer@example.com",
    name: "Ada Lovelace",
    company: "Example Co",
    plan: "Pro"
  });
</script>
Send only fields that help support. Avoid secrets, payment details, unnecessary personal data, and unrelated account information.

Add page context

Context helps operators understand where the question came from.
<script>
  window.Woes("setContext", {
    page: window.location.pathname,
    environment: "production",
    apiVersion: "2026-06-01"
  });
</script>
Good context is:
  • Short.
  • Operational.
  • Safe for operators to see.
  • Helpful for reproducing the issue.

Conversation history

Conversation history requires the per-conversation history secret issued for that conversation. Verified customer identity does not replace that secret. This separation protects customers from one public workspace key being enough to read arbitrary conversation history.

Test the installation

1

Load the page

Open the page with the widget installed. Use a private browser session for a clean first-run test.
2

Send a message

Open the widget and send a short test message.
3

Check the inbox

Confirm the conversation appears in Woes with the expected channel, identity, and page context.
4

Reply as an operator

Send a reply and confirm the browser receives it.
5

Refresh and continue

Refresh the browser and confirm conversation continuity works as expected.

Security model

The public widget route is narrower than authenticated workspace routes. It should:
  • Accept requests for the workspace identified by the public key.
  • Validate payloads and route controls.
  • Avoid broad database access.
  • Avoid returning internal notes, secrets, or unrelated workspace data.
  • Keep operator-only diagnostics out of customer responses.

Troubleshooting

Confirm the script URL is reachable, data-public-key is present, data-api is correct, and your content security policy allows the script.
Confirm the workspace public key is correct, the widget API route is deployed, the origin is allowed, and the payload is within route limits.
Confirm window.Woes("identify", ...) runs after the shim is loaded and before or near the first customer message.
Confirm the browser has the conversation state and that the per-conversation history secret is present and valid.