Starts Now logoStarts Now

Documentation

Widget Reference

Embed your AI chatbot on any website with one script tag. Use the JavaScript API to control the widget programmatically.

Quick Start

Copy your chatbot ID from the dashboard, paste the snippet before the closing </body> tag, and you're live.

html
<script src="https://startsnow.site/widget.js"></script>
<script>
  ChatBot.init({
    chatbotId: "YOUR_CHATBOT_ID"
  });
</script>

How it works

  • The script is tiny — it loads asynchronously and never blocks your page.
  • The chat UI renders inside a Shadow DOM root, so your site's CSS and the widget's never affect each other — and no frame-src CSP rule is required.
  • No cookies are set by default.

Allowed Domains

This is the #1 reason a widget doesn't appear. Each chatbot has a server-side list of domains it's allowed to load on, managed in your dashboard under Settings → Allowed Domains.

  • Empty list = loads everywhere. A brand-new chatbot has no domains configured, so the widget works on any site out of the box.
  • Add one domain and only listed domains load it. As soon as you add a domain, every other domain is blocked — the widget simply doesn't render (it fails silently, leaving a hint in the console rather than showing a broken bubble).
  • Use exact hostnames. The dashboard list matches the visitor's hostname exactly — wildcards are not expanded here. If you serve both example.com and www.example.com, add both.
  • localhost is always allowed. localhost, 127.0.0.1, and startsnow.site are permitted automatically for local development and dashboard previews — you never need to add them.

If your widget isn't showing, open the browser console. A message starting with [StartsNow Widget] This domain is not in the allowed list means you need to add the current domain in Settings → Allowed Domains.

Domain Lock

Optionally restrict the widget from a second angle — directly in the embed snippet — so it can't be initialised by anyone who copies your chatbot ID onto another site. This is a separate, client-side guard from the dashboard Allowed Domains list above. Pass an allowedDomains array to ChatBot.init — unlike the dashboard list, this one does support wildcard subdomains.

html
<script src="https://startsnow.site/widget.js"></script>
<script>
  ChatBot.init({
    chatbotId: "YOUR_CHATBOT_ID",
    allowedDomains: [
      "yourwebsite.com",
      "*.yourwebsite.com"
    ]
  });
</script>

Domain patterns

js
// Exact match
allowedDomains: ["yourwebsite.com"]

// All subdomains of yourwebsite.com (e.g. app.yourwebsite.com)
allowedDomains: ["*.yourwebsite.com"]

// Multiple domains
allowedDomains: ["yourwebsite.com", "*.yourwebsite.com", "staging.example.com"]

Leave allowedDomains empty (or omit it) to allow all domains.

Data Attribute

If you prefer no inline scripts, set data-chatbot-id directly on the script tag. The widget auto-initialises when the DOM is ready.

html
<script
  src="https://startsnow.site/widget.js"
  data-chatbot-id="YOUR_CHATBOT_ID"
></script>

With domain lock

Pass a comma-separated list via data-allowed-domains.

html
<script
  src="https://startsnow.site/widget.js"
  data-chatbot-id="YOUR_CHATBOT_ID"
  data-allowed-domains="yourwebsite.com,app.yourwebsite.com"
></script>

Framework Guides

The widget is plain JavaScript and works on any stack. Below are drop-in recipes for the most common ones. Replace YOUR_CHATBOT_ID with the ID from your dashboard.

Next.js — App Router

Inline <script>tags don't run reliably in JSX, and a Server Component can't use onLoad. Create a small Client Component that loads the widget and calls init from onLoad — this guarantees ChatBot exists before you call it.

tsx
// components/ChatbotWidget.tsx
"use client";

import Script from "next/script";

declare global {
  interface Window {
    ChatBot?: {
      init: (config: { chatbotId: string; allowedDomains?: string[] }) => void;
    };
  }
}

export default function ChatbotWidget() {
  return (
    <Script
      src="https://startsnow.site/widget.js"
      strategy="afterInteractive"
      onLoad={() => {
        window.ChatBot?.init({
          chatbotId: "YOUR_CHATBOT_ID",
          allowedDomains: ["yourwebsite.com", "*.yourwebsite.com"],
        });
      }}
    />
  );
}

Then render it once in your root layout:

tsx
// app/layout.tsx
import ChatbotWidget from "@/components/ChatbotWidget";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        {children}
        <ChatbotWidget />
      </body>
    </html>
  );
}

No proxy route needed

Earlier versions of this guide suggested creating a proxy /api/widget route inside your Next.js app. That is no longer required widget.js automatically calls its own origin (startsnow.site), so the standard two-tag snippet works as-is. If you added a proxy route for the widget, you can safely remove it.

Next.js — Pages Router

Add it once in _app.tsx using next/script.

tsx
// pages/_app.tsx  (Pages Router)
import Script from "next/script";
import type { AppProps } from "next/app";

export default function App({ Component, pageProps }: AppProps) {
  return (
    <>
      <Component {...pageProps} />
      <Script
        src="https://startsnow.site/widget.js"
        strategy="afterInteractive"
        onLoad={() => {
          window.ChatBot?.init({ chatbotId: "YOUR_CHATBOT_ID" });
        }}
      />
    </>
  );
}

React / Vite / CRA

No next/script here — inject the script in a useEffect and init from its onload.

tsx
// src/ChatbotWidget.tsx (React / Vite / CRA)
import { useEffect } from "react";

export default function ChatbotWidget() {
  useEffect(() => {
    const script = document.createElement("script");
    script.src = "https://startsnow.site/widget.js";
    script.async = true;
    script.onload = () => {
      window.ChatBot?.init({ chatbotId: "YOUR_CHATBOT_ID" });
    };
    document.body.appendChild(script);
    return () => script.remove();
  }, []);

  return null;
}

// Then render <ChatbotWidget /> once near your app root.

Vue 3 / Nuxt 3

Inject the script from onMounted so it only runs in the browser, then init from its onload. Place it in App.vue (or a default layout) so it loads once.

html
<!-- Vue 3 / Nuxt 3 — App.vue or a layout component -->
<script setup>
import { onMounted } from "vue";

onMounted(() => {
  const s = document.createElement("script");
  s.src = "https://startsnow.site/widget.js";
  s.async = true;
  s.onload = () => window.ChatBot?.init({ chatbotId: "YOUR_CHATBOT_ID" });
  document.body.appendChild(s);
});
</script>

WordPress

Recommended: use a header/footer plugin so a theme update never wipes your snippet.

html
Easiest (no code editing) — use a header/footer plugin:

1. Install the "WPCode" or "Insert Headers and Footers" plugin.
2. Go to Settings → Insert Headers and Footers (or WPCode → Header & Footer).
3. Paste the snippet below into the "Footer" / "Body" box and Save.

<script src="https://startsnow.site/widget.js"></script>
<script>
  ChatBot.init({ chatbotId: "YOUR_CHATBOT_ID" });
</script>

Or edit the theme directly:

html
<!-- Appearance → Theme File Editor → footer.php
     Paste just before the closing </body> tag -->
<script src="https://startsnow.site/widget.js"></script>
<script>
  ChatBot.init({
    chatbotId: "YOUR_CHATBOT_ID",
    allowedDomains: ["yourwebsite.com", "*.yourwebsite.com"]
  });
</script>

Shopify

Add the snippet to your theme's theme.liquid layout file so it loads on every storefront page.

html
<!-- Online Store → Themes → ⋯ → Edit code → Layout/theme.liquid
     Paste just before the closing </body> tag -->
<script src="https://startsnow.site/widget.js"></script>
<script>
  ChatBot.init({
    chatbotId: "YOUR_CHATBOT_ID",
    allowedDomains: ["yourstore.myshopify.com", "yourstore.com"]
  });
</script>

Google Tag Manager

If GTM is already on your site, you can deploy the widget without touching code.

html
Google Tag Manager (works on any site GTM is installed on):

1. In GTM, create a new Tag → "Custom HTML".
2. Paste the snippet below.
3. Set the trigger to "All Pages", then Submit / Publish.

<script src="https://startsnow.site/widget.js"></script>
<script>
  ChatBot.init({ chatbotId: "YOUR_CHATBOT_ID" });
</script>

Webflow, Squarespace, Wix & Framer

Every major site builder has a custom-code / code-injection slot. Paste the snippet into the footer / end-of-body section and publish.

html
Webflow:    Project Settings → Custom Code → Footer Code → paste → publish.
Squarespace: Settings → Advanced → Code Injection → Footer → paste.
Wix:         Settings → Custom Code → Add Code → "Body - end" → paste.
Framer:      Site Settings → General → Custom Code → End of <body> tag.

<script src="https://startsnow.site/widget.js"></script>
<script>
  ChatBot.init({ chatbotId: "YOUR_CHATBOT_ID" });
</script>

API Reference

ChatBot.init(options)async → Promise<boolean>

Loads chatbot config, injects the widget DOM, and returns true on success. Must be called before any other method.

OptionTypeRequiredDescription
chatbotIdstringYesYour chatbot's unique ID from the dashboard.
allowedDomainsstring[]NoList of domains allowed to embed the widget. Omit to allow all domains.
ChatBot.open()void

Opens the chat window. Does nothing if already open.

js
ChatBot.open();   // programmatically open the chat window
ChatBot.close()void

Closes the chat window. Does nothing if already closed.

js
ChatBot.close();  // programmatically close the chat window
ChatBot.toggle()void

Flips the chat window between open and closed.

js
ChatBot.toggle(); // flip between open and closed
ChatBot.sendMessage(text)void

Pre-fills a message into the chat input box. Useful for seeding context when the user arrives from a specific page or product.

js
// Pre-fill a message into the chat input box
ChatBot.sendMessage("Hi, I need help with my order");

Events

The widget dispatches native CustomEvents on window that you can listen for in your own code.

Eventdetail payloadFired when
chatflow-widget-ready{ chatbotId, version }Widget has fully initialised and the chat UI is rendered.
js
// Fired once the widget has fully initialised and is ready
window.addEventListener("chatflow-widget-ready", (event) => {
  console.log("Widget ready", event.detail.chatbotId, event.detail.version);
});

Content Security Policy

Most sites don't set a Content-Security-Policy and need nothing here. If yours does, allow our script and the API calls it makes — the same two directives you'd add for any third-party widget (analytics, support chat, etc.):

text
Content-Security-Policy:
  script-src  'self' https://startsnow.site;
  connect-src 'self' https://startsnow.site;
  • script-src — lets the browser load widget.js.
  • connect-src — lets the widget fetch() its config and send chat messages.
  • No frame-src rule is needed — the chat renders in a Shadow DOM root on your page, not in an iframe.

Debug Mode

Enable verbose [StartsNow Widget] logs in the browser console to diagnose initialization, config loading, and chat request issues.

js
// Enable verbose logging in the browser console
ChatBot.enableDebug();

// Disable debug logging
ChatBot.disableDebug();

Debug mode is persisted to window.__STARTSNOW_DEBUG__ and survives navigation within a single-page app session.

Troubleshooting

Open your browser's DevTools console and match the symptom below.

The bubble never appears

Check Allowed Domains first — this is the most common cause. Make sure the exact domain you're viewing is in the list, or that the list is empty. Also confirm both <script> tags are present and the chatbotId is correct.

Console shows "[StartsNow Widget] This domain is not in the allowed list"

Add the current domain in your dashboard under Settings → Allowed Domains. Remember it's an exact hostname match (add www. separately if you use it).

Console shows a CSP error mentioning script-src or connect-src

Your site has a strict Content-Security-Policy. Add https://startsnow.site to both the script-src and connect-src directives — see Content Security Policy. There is no frame-src requirement.

The bubble opens but messages fail

Confirm the chatbot is Activein the dashboard and hasn't hit its monthly message limit. Check the Network tab for the /api/chat request and its response.

Ready to embed?

Create a chatbot in the dashboard and copy your embed code from the chatbot detail page.

Go to Dashboard