Skip to content

Install the website widget

The website widget is one script tag. It loads the widget from Caplo, shows the published design you applied to the channel, and connects visitors to the agent release the channel serves.

  • Create a website channel (Live chat widget) for a published agent. See Channels.
  • Publish a widget design and apply a revision to the channel. The console only gives you embed code once a design is applied, because the code depends on whether the design is a popup or an inline container. See Design the widget.
  • Know the exact origin of every site that will show the widget, for example https://www.example.com.
  1. In Channels, open the website channel and select Configure & install on its website entry point.

  2. On the General tab, check Allowed website origin. Add every origin that will show the widget, then select Save entry point.

  3. Open the Install tab and select Copy embed code.

If Copy embed code is disabled, the hint next to it says why: no design is applied, there are unsaved edits, the entry point is disabled, or the channel is paused.

The Widget ID on the Install tab is a public identifier. The snippet contains no credentials, and you never need to add any.

A popup design (a launcher button in a corner of the page):

<script
src="https://api.caplo.si/v1/messaging/widget/loader.js"
data-widget-id="<WIDGET_ID>"
async
></script>

An inline design (the conversation sits inside an element on your page) adds a container and points the script at it:

<div id="caplo-<WIDGET_ID>"></div>
<script
src="https://api.caplo.si/v1/messaging/widget/loader.js"
data-widget-id="<WIDGET_ID>"
data-container="#caplo-<WIDGET_ID>"
async
></script>

Always copy the code from the console rather than typing it: the console escapes the container selector when the widget ID contains a dot.

Attribute Required What it does
src Yes The widget loader. Load it from Caplo; a self-hosted copy cannot reach the widget service.
data-widget-id Yes The widget ID from the Install tab.
data-container Inline designs A CSS selector for the element the widget renders into. The element must exist on the page when the loader runs.
data-persistence No By default the widget restores the visitor’s conversation after a reload in the same browser tab. Set data-persistence="none" to start fresh on every page load.
nonce When your CSP uses nonces Add your page’s nonce. The widget applies it to the styles it adds.
async Recommended Loads the widget without blocking your page.

The widget ID stays the same when you apply a new design revision, so you do not need to change your site when the appearance changes. Switching a design between popup and inline is the exception: inline needs the container element and data-container.

The widget only works on the origins listed on the entry point.

  • List exact origins: scheme and host, plus the port if it is not the default. No paths and no wildcards.
  • https://example.com and https://www.example.com are different origins. List both if you use both.
  • Use HTTPS. HTTP is accepted only for localhost, 127.0.0.1 and .localhost hosts, which is useful for local development.
  • You can list up to 10 origins per entry point.

On any other site, including a staging host you have not listed, the widget shows a Chat unavailable · Try again button instead of the chat. Removing an origin closes open conversations on that site.

Paste the code just before the closing </body> tag on every page that should show the widget. For an inline design, place the <div> where the conversation should appear and keep the script after it.

<!-- your page content -->
<script
src="https://api.caplo.si/v1/messaging/widget/loader.js"
data-widget-id="<WIDGET_ID>"
async
></script>
</body>
</html>

If your site sends a Content-Security-Policy header, add these sources to the matching directives and keep your existing sources:

script-src https://api.caplo.si;
connect-src https://api.caplo.si;
font-src https://api.caplo.si;
img-src blob:;
worker-src blob:;

The console shows the same list under Content Security Policy additions on the Install tab. Brand logos and avatars render from blob: URLs, and map results start a worker from a blob: URL.

If the channel allows voice, the browser also connects to Caplo’s media server for the call. Add it to connect-src:

connect-src https://api.caplo.si wss://livekit.caplo.si;

Caplo never changes your site’s policy. See Troubleshoot the website widget for how CSP errors show up.

  • The loader runs once per script element. Calling it again with the same widget ID on the same page does nothing until the widget is unmounted.
  • A popup widget stays mounted across client-side route changes. To remove it on some routes, call unmount() from the JavaScript API; add the script again to bring it back.
  • An inline widget unmounts itself when its container is removed from the page.
  • On a full page unload the widget closes its connection. With the default persistence, the conversation resumes when the visitor returns in the same tab.
  1. Open a page on an allowed origin. The launcher appears in the corner you chose, or the conversation appears in its container.

  2. Send a message and check that the agent replies. The conversation appears in Conversations in the console.

  3. If you see Chat unavailable · Try again, or nothing, see Troubleshoot the website widget.

AI prompt

Add the Caplo widget to my website

Adds the website widget embed code to a plain HTML site, updates the Content Security Policy if there is one, and checks that it loads.

Show prompt
Goal: add the Caplo website widget to this website so visitors can chat with our agent.

Read these pages first:
- https://docs.caplo.si/channels/website-widget/install.md
- https://docs.caplo.si/channels/website-widget/troubleshooting.md

Values I will give you:
- Widget ID: <WIDGET_ID> (from the Install tab of the website entry point in the Caplo console)
- Display mode: <POPUP_OR_INLINE>
- For an inline design, where the conversation should appear: <PAGE_AND_POSITION>

Steps:
1. Find the HTML templates or layout files that render every page that should show the widget. Prefer one shared layout or footer include over editing each page.
2. For a popup design, add this just before `</body>`:
   ```html
   <script
     src="https://api.caplo.si/v1/messaging/widget/loader.js"
     data-widget-id="<WIDGET_ID>"
     async
   ></script>
   ```
   For an inline design, add `<div id="caplo-<WIDGET_ID>"></div>` where the conversation should appear, and the script after it with `data-container="#caplo-<WIDGET_ID>"`. If the widget ID contains a dot, escape it in the selector (`\.`).
3. Look for a Content-Security-Policy, in server config, a meta tag or framework headers. If there is one, add `https://api.caplo.si` to `script-src`, `connect-src` and `font-src`, add `blob:` to `img-src` and `worker-src`, and keep every existing source. If the policy uses nonces, add the page's nonce attribute to the script tag. If voice is enabled for this channel, also add `wss://livekit.caplo.si` to `connect-src`.
4. Do not add any API key, token or credential. The widget ID is public and is the only value the snippet needs.

Verify:
- Serve the site on an origin that is listed as an allowed origin of the entry point (for local testing, ask me to add `http://localhost:<PORT>` in the console).
- Open a page and confirm the launcher or inline conversation appears, and the browser console shows no CSP errors.
- If you see "Chat unavailable · Try again", check the POST to `/v1/messaging/widget/presentation` in the Network tab and use the troubleshooting page to explain the cause to me.

Rules:
- Only change the website's files. Ask me before changing allowed origins, designs or channels in the Caplo console; you cannot do that from the code.
- Ask before deploying or publishing the site.
AI prompt

Add the Caplo widget to my Next.js app

Adds the website widget to a Next.js App Router project with next/script or a client component, updates the CSP, and checks that it loads.

Show prompt
Goal: add the Caplo website widget to this Next.js (App Router) app.

Read these pages first:
- https://docs.caplo.si/channels/website-widget/install.md
- https://docs.caplo.si/channels/website-widget/javascript-api.md
- https://docs.caplo.si/channels/website-widget/troubleshooting.md

Values I will give you:
- Widget ID: <WIDGET_ID> (from the Install tab of the website entry point in the Caplo console)
- Display mode: <POPUP_OR_INLINE>
- For an inline design, the route and position for the conversation: <ROUTE_AND_POSITION>

Steps:
1. Put the widget ID in configuration that is safe to expose to the browser, for example `NEXT_PUBLIC_CAPLO_WIDGET_ID`. It is a public identifier, not a secret.
2. For a popup design, add to `app/layout.tsx`, inside `<body>` after `{children}`:
   ```tsx
   <Script
     src="https://api.caplo.si/v1/messaging/widget/loader.js"
     data-widget-id={process.env.NEXT_PUBLIC_CAPLO_WIDGET_ID}
     strategy="afterInteractive"
   />
   ```
   with `import Script from 'next/script'`.
3. For an inline design, do not use `next/script` (it loads a script only once per session, so the widget would not return after navigation). Create a client component (`'use client'`) that renders a `div` whose id is `caplo-` followed by the widget ID and, in a `useEffect`, appends a script element with `src` set to the loader URL, `async = true`, `dataset.widgetId` and `dataset.container = '#' + CSS.escape(containerId)`, and removes the script element on cleanup. Render it on <ROUTE_AND_POSITION>.
4. If the app sets a Content-Security-Policy (middleware, `next.config` headers or a meta tag), add `https://api.caplo.si` to `script-src`, `connect-src` and `font-src`, add `blob:` to `img-src` and `worker-src`, and keep every existing source. If it uses a per-request nonce, pass it to `<Script nonce={nonce} />` or set `script.nonce` in the component. If voice is enabled for this channel, also add `wss://livekit.caplo.si` to `connect-src`.
5. Optionally, if I have a "Help" or "Chat with us" button, open the widget from it with `window.CaploWidget.get('<WIDGET_ID>').open()` once the loader has loaded.

Verify:
- Run the dev server on an origin listed as an allowed origin of the entry point (ask me to add `http://localhost:<PORT>` in the console if needed).
- Load the page, navigate to another route and back, and confirm the widget stays (popup) or comes back (inline). The browser console must show no CSP errors.
- If you see "Chat unavailable · Try again", inspect the POST to `/v1/messaging/widget/presentation` in the Network tab and explain the cause using the troubleshooting page.

Rules:
- No API keys, tokens or credentials in code, environment files or chat. The widget needs none.
- Ask me before changing anything in the Caplo console, and before deploying.