Skip to content

Installation guide

Add Suppy chat to your website

Install a floating support chat with one asynchronous script. Visitors stay on your website while your team handles their conversations in the Suppy dashboard.

1. Find your project’s embed code

Sign in to Suppy with Google or GitHub. If you do not already belong to a project, Suppy creates one for you during sign-in. Open Settings and select the project that should receive your website’s conversations.

Open Settings → Widget → Embed code. Select the correct project in Settings first, then copy its generated snippet. The Project page lets you review the project name and saved slug. The widget accepts a project slug or project ID; use the value from the generated code instead of guessing it.

This project identifier is public configuration, not an account credential. You do not need a secret API key in your website’s HTML.

2. Add the script to your pages

Paste the snippet before the closing </body> tag on every page where chat should appear, or into a shared site template. Replace the example project slug below with your own. Keep async so downloading the widget does not block HTML parsing.

<script
  src="https://suppy.chat/widget.js"
  data-project="your-project-slug"
  async
></script>

Install one snippet per page. The launcher appears on the right by default. Choose its primary color in Settings; add data-position="left" to place it on the left. An optional data-source="main-site" labels conversations from this installation. Without a source label, the page’s hostname is used.

The widget’s own texts (order cards, voice calls) follow the page language: add data-lang="uk" (uk, ru, pl or en), or leave it out and the page’s <html lang> is used, then the visitor’s device language. A native app that opens the widget URL directly can append &lang=uk.

Optional: let an AI coding assistant install it

If you build with Claude Code, Cursor, GitHub Copilot, Windsurf or ChatGPT, paste one of the prompts below into the assistant that has your website’s code open. Each one is self-contained: it carries the script tag, the attributes and the rules that matter, so the assistant works from this guide instead of from memory.

Replace your-project-slug with the value from Settings → Widget → Embed code before you send the prompt. That slug is public configuration. Nothing else about your account belongs in a prompt: keep API keys, database credentials and dashboard passwords out of it.

Add the widget to a website

For a site that does not have the chat yet. Covers the shared layout, async loading, single-page apps and content security policies.

Add the Suppy support chat widget to this website.
Docs: https://suppy.chat/docs/install

1. Render this tag once, in the shared layout or template that
   every page uses, directly before </body>:
   <script src="https://suppy.chat/widget.js"
           data-project="your-project-slug" async></script>
2. Keep the async attribute and that exact URL. There is no npm
   package: do not bundle, self-host or proxy widget.js.
3. data-project is public configuration, not a credential. Leave
   it in the markup; no secret or API key belongs in this tag.
4. In a single-page app, mount the tag once for the whole app
   rather than per route. Re-running the script replaces the
   widget instead of stacking a second launcher.
5. Optional attributes, only if I ask: data-position="left",
   data-color="#00A3FF", data-source="marketing-site",
   data-launcher="false".
6. If this site sends a Content-Security-Policy, allow
   https://suppy.chat in script-src and frame-src.

Then list the files you changed and how I can check the launcher
on a page.

Open the chat from your own buttons

For a site where the script is already installed and your own support controls should open the panel, including the startup queue for early JavaScript API calls.

Wire this site's own support buttons to the Suppy chat widget
that is already installed.
Docs: https://suppy.chat/docs/install

1. Existing "Contact support" controls should open the chat: add
   data-suppy-chat to a <button>, or link to #suppy-chat. The
   attribute takes "open" (default), "close" or "toggle". Keep
   them real buttons and links so they stay reachable by keyboard.
2. To rely on our own controls only, add data-launcher="false" to
   the widget script tag - then every page needs a visible
   support button of its own.
3. Any SuppyChat call that can run before the async script
   finishes must go through the queue stub, defined before the
   widget tag:
   window.SuppyChat = window.SuppyChat || function () {
     (window.SuppyChat.q = window.SuppyChat.q || []).push(arguments)
   }
   Queued calls replay on init and cannot return a value.
4. After load the API is window.SuppyChat.open(), close(),
   toggle(), isOpen(), unreadCount(), destroy(),
   on('open' | 'close' | 'unread', callback) and
   identify(email, name). Read isOpen() and unreadCount() only
   after load.
5. Call identify() only with an email our own backend has
   authenticated. An email typed into a form or read from a URL
   is not proof of ownership.

Show me the diff before applying it.

Review an existing installation

Asks for findings before changes: duplicated loaders, triggers that reload the script, calls made before the widget is ready and identify() used as if it were authentication.

Review how the Suppy chat widget is installed in this codebase
and report concrete fixes.
Docs: https://suppy.chat/docs/install

Check that:
- exactly one widget.js tag renders per page, carrying
  data-project and async;
- a single-page app does not re-inject the tag on every route
  change;
- custom triggers use data-suppy-chat or #suppy-chat instead of a
  second copy of the script, and sit on real buttons or links;
- data-launcher="false" appears only where our own support button
  is visible;
- SuppyChat calls made before load go through the queue stub, and
  isOpen() and unreadCount() are read only after load;
- identify() receives only an email our backend authenticated;
- no Content-Security-Policy, consent gate or tag manager blocks
  https://suppy.chat.

Report findings as a list with file and line, then propose a
diff. Change nothing until I approve it.

Read the assistant’s diff before you accept it. The common mistakes are a second copy of the loader on one page, a bundled or self-hosted widget.js and a script tag injected on every route change of a single-page app. Whatever the assistant reports, confirm the result yourself with the test below.

3. Connect your own support button

A button with data-suppy-chat or a link to #suppy-chat opens the panel after the widget loads. These controls also work when your application adds them later. Use a real button or link so visitors can reach it with a keyboard.

<button type="button" data-suppy-chat>Chat with us</button>
<a href="#suppy-chat">Contact support</a>
<button type="button" data-suppy-chat="toggle">Toggle chat</button>

To use only your own controls, add data-launcher="false" to the script. This hides the floating launcher, so keep a visible support button on the page. The close and toggle attribute values are also supported.

Optional: call the JavaScript API safely

An asynchronous script may finish after your page’s next script runs. For calls made before loading completes, define this queue first and use the callable form shown below. The widget replays queued calls when its API initializes. Use this example in place of the basic embed, not as a second installation.

<script>
  window.SuppyChat = window.SuppyChat || function () {
    (window.SuppyChat.q = window.SuppyChat.q || []).push(arguments);
  };

  window.SuppyChat('on', 'open', function () {
    console.log('Support chat opened');
  });
</script>
<script
  src="https://suppy.chat/widget.js"
  data-project="your-project-slug"
  async
></script>

Once loaded, window.SuppyChat.open(), close() and toggle() control the panel. isOpen() returns its open state and unreadCount() returns the unread count. Read these values only after loading; the startup queue cannot return their eventual results.

The optional identify(email, name) method updates visitor details and reloads the chat frame. Call it after loading, or use the same queue with SuppyChat('identify', email, name). An email passed by browser code is not authentication or proof of ownership. Do not use this method as authorization to access another person’s conversation history.

4. Test a complete conversation

  1. Open a page containing the snippet and check the launcher or your custom button.
  2. Open chat, follow the visitor prompts and send a clearly labeled test message.
  3. Find that conversation in the selected project’s dashboard and send a reply.
  4. Confirm the visitor receives it, then close and reopen the panel.
  5. Repeat on a narrow mobile screen and on another page with the same snippet.

Adding the script does not activate every optional module. For the next steps, read about AI support and human handoff, live translation and available plans and modules.

If the widget does not appear

  • Check the browser console for “Missing data-project” and confirm the script URL loads. An absent project attribute stops initialization.
  • Check for data-launcher="false" or "none". Both intentionally hide the launcher; try your custom trigger.
  • Inspect blocked script, frame or network requests in developer tools. Your website’s content security policy or browser extensions may block the embed.
  • If the panel opens but cannot load the project, recopy its current snippet. A changed slug or deleted project can leave an old embed pointing nowhere.