Embed Chat Widget
Add your AI chatbot to any website with a floating chat bubble or iframe embed.
Add your Chipp AI chatbot to any website using either a floating chat bubble widget or an embedded iframe. Choose the option that best fits your site’s design.
Embed Options
| Option | Best For |
|---|---|
| Chat Widget | Floating bubble in corner, doesn’t take page space |
| Iframe | Dedicated chat section embedded in your page |
Option 1: Chat Widget (Floating Bubble)
The chat widget adds a floating chat bubble to the corner of your page. When clicked, it opens your chatbot in an overlay. It’s lightweight (~5KB gzipped), uses Shadow DOM for CSS isolation, and works on any website.
Quick Start
Add a single <script> tag before the closing </body> tag on your website:
<script src="https://your-app.on.chipp.ai/w/chat/chipp-widget.js"></script>That’s it. The widget auto-detects your app from the subdomain and renders a floating chat bubble in the bottom-right corner.
Getting the Widget Code
1
Open your app and click Publish > Share in the navigation.
2
Look for the Widget card on the Share page.
3
Click the code snippet to copy it to your clipboard:
<script src="https://your-app.on.chipp.ai/w/chat/chipp-widget.js"></script>4
Paste the code before the closing </body> tag on your website.
Customizing with Data Attributes
You can customize the widget by adding data-* attributes to the script tag:
<script
src="https://your-app.on.chipp.ai/w/chat/chipp-widget.js"
data-position="bottom-left"
data-greeting="Hey! How can I help?"
data-greeting-delay="3000"
data-color="#ff6600"
data-bubble-size="64"
></script>Attribute Reference
| Attribute | Default | Description |
|---|---|---|
data-app-id | (auto-detected from subdomain) | App slug, e.g. my-app. Required when hosting the script from a different domain |
data-position | bottom-right | Widget position: bottom-right, bottom-left, top-right, top-left |
data-theme | auto | Color theme: light, dark, auto (follows user’s OS preference) |
data-greeting | (none) | Greeting message shown as a preview bubble above the chat button |
data-greeting-delay | 2000 | Delay in milliseconds before the greeting appears (0-30000) |
data-auto-open | (disabled) | Automatically open the chat after this many milliseconds (e.g. 5000 for 5 seconds) |
data-color | (app brand color) | Bubble background color as a hex value (e.g. #2563EB) |
data-bubble-size | 60 | Bubble diameter in pixels (48-80) |
data-bubble-shape | circle | Bubble shape: circle or rounded (rounded rectangle) |
data-icon-url | (app logo) | Custom icon URL for the bubble (falls back to app logo, then a chat icon) |
data-z-index | 2147483646 | CSS z-index for the widget container |
data-hide-on-mobile | false | Set to true to hide the widget on mobile viewports |
Config Priority
Data attributes take the highest priority. If you set a value via data-*, it overrides the server-side configuration. The full priority order is:
- Data attributes on the
<script>tag (highest) - Builder widget config (saved in the Widget tab)
- App brand styles (logo, primary color)
- Defaults (lowest)
Configuring in the Builder
You can also configure the widget visually in the Builder:
- Open your app in the Builder
- Go to Publish > Widget
- Adjust position, size, greeting, and other settings
- See changes reflected in the live preview
- Changes save automatically and update the widget in real-time
The Builder Widget tab lets you configure all the same options as the data attributes, plus a live preview showing exactly how the widget will look on your site.
Widget Features
- CSS isolation: Uses Shadow DOM so your site’s CSS won’t affect the widget and vice versa
- Instant open: Preloads the chat iframe on hover, so it opens instantly when clicked
- Greeting bubble: Optional animated preview message to encourage interaction
- Responsive: Full-screen overlay on mobile, positioned popup on desktop
- Accessible: Full keyboard navigation, ARIA labels, focus management, and reduced-motion support
- Lightweight: ~5KB gzipped (compared to 42KB for legacy widget)
JavaScript API
The widget exposes a window.ChippWidget API for programmatic control. This lets you open/close the chat, identify users, and listen for events from your own JavaScript.
Basic Controls
// Open the chat
ChippWidget.open();
// Close the chat
ChippWidget.close();
// Toggle open/closed
ChippWidget.toggle();
// Check if chat is open
if (ChippWidget.isOpen()) {
console.log("Chat is open");
}
// Remove the widget completely (cannot be undone)
ChippWidget.destroy();User Identification
Identify users so their chat history persists across sessions and you can see who’s chatting in your dashboard.
Client-Side (Simple)
Pass the user’s email and optional name directly. This is the simplest approach for sites where the chat doesn’t require authentication:
ChippWidget.setUser({
email: "jane@example.com",
name: "Jane Doe"
});Server-Side (Secure)
For apps with authentication enabled, use server-side token generation to securely identify users. This prevents spoofing and ensures the user’s identity is verified by your backend.
Step 1: Generate a token on your server
Call the Builder API from your backend to get a bearer token:
curl -X POST https://your-app.on.chipp.ai/api/v1/apps/{APP_ID}/consumers/auth \
-H "Authorization: Bearer YOUR_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "jane@example.com", "name": "Jane Doe"}'Response:
{
"data": {
"token": "eyJhbGciOi...",
"consumer": {
"id": "...",
"email": "jane@example.com",
"name": "Jane Doe"
}
}
}Step 2: Pass the token to the widget
Send the token to your frontend and pass it to setUser:
ChippWidget.setUser({
email: "jane@example.com",
name: "Jane Doe",
token: "eyJhbGciOi..." // Bearer token from your server
});The token authenticates the user’s session inside the chat iframe without cookies, which makes it work reliably in cross-origin embeds.
You need a Builder API key with write scope to call the /consumers/auth endpoint. Generate one in Settings > API Keys in the Builder.
Events
Listen for widget events to react to user interactions:
// Listen for an event (returns an unsubscribe function)
const unsubscribe = ChippWidget.on("message", (data) => {
console.log("New message:", data.role, data.content);
});
// Stop listening
unsubscribe();
// Alternative: manually remove a listener
function onOpen() { console.log("Chat opened"); }
ChippWidget.on("open", onOpen);
ChippWidget.off("open", onOpen);Event Reference
| Event | Payload | Description |
|---|---|---|
open | {} | The chat overlay was opened |
close | {} | The chat overlay was closed |
ready | {} | The chat iframe finished loading and is ready to use |
message | { role, content } | A new message was sent or received. role is "user" or "assistant" |
Full API Reference
| Method | Signature | Description |
|---|---|---|
open() | () => void | Open the chat overlay |
close() | () => void | Close the chat overlay |
toggle() | () => void | Toggle the chat open/closed |
isOpen() | () => boolean | Returns true if the chat is currently open |
setUser(user) | (user: { email: string, name?: string, token?: string }) => void | Identify the current user |
on(event, cb) | (event: string, cb: Function) => () => void | Subscribe to an event. Returns an unsubscribe function |
off(event, cb) | (event: string, cb: Function) => void | Unsubscribe a specific callback from an event |
destroy() | () => void | Remove the widget from the page entirely |
Examples
Open Chat from a Custom Button
<button onclick="ChippWidget.open()">Chat with us</button>
<script src="https://your-app.on.chipp.ai/w/chat/chipp-widget.js"></script>React Integration
import { useEffect } from "react";
function App() {
useEffect(() => {
// Load the widget script
const script = document.createElement("script");
script.src = "https://your-app.on.chipp.ai/w/chat/chipp-widget.js";
script.async = true;
document.body.appendChild(script);
return () => {
// Clean up on unmount
if (window.ChippWidget) {
window.ChippWidget.destroy();
}
script.remove();
};
}, []);
return (
<button onClick={() => window.ChippWidget?.open()}>
Ask a question
</button>
);
}Next.js Integration
"use client";
import Script from "next/script";
export default function ChatWidget() {
return (
<Script
src="https://your-app.on.chipp.ai/w/chat/chipp-widget.js"
strategy="lazyOnload"
data-position="bottom-right"
data-greeting="Need help? Ask me anything!"
/>
);
}Auto-Open After a Delay
Open the chat automatically after 5 seconds, useful for onboarding flows:
<script
src="https://your-app.on.chipp.ai/w/chat/chipp-widget.js"
data-auto-open="5000"
></script>Track Conversations in Analytics
ChippWidget.on("open", () => {
// Google Analytics
gtag("event", "chat_opened", { event_category: "engagement" });
});
ChippWidget.on("message", (data) => {
if (data.role === "user") {
gtag("event", "chat_message_sent", { event_category: "engagement" });
}
});Conditional Widget Loading
Only load the widget for certain users or pages:
if (window.location.pathname.startsWith("/support")) {
const script = document.createElement("script");
script.src = "https://your-app.on.chipp.ai/w/chat/chipp-widget.js";
script.dataset.greeting = "How can we help with your support issue?";
document.body.appendChild(script);
}Server-Side Auth with React
import { useEffect } from "react";
function ChatWidget({ user }) {
useEffect(() => {
if (!user || !window.ChippWidget) return;
// Call your backend to get a widget token
fetch("/api/chat-token", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: user.email, name: user.name }),
})
.then((res) => res.json())
.then(({ token }) => {
window.ChippWidget.setUser({
email: user.email,
name: user.name,
token,
});
});
}, [user]);
return null;
}Option 2: Iframe Embed
The iframe embeds your chatbot directly into your page layout. Use this when you want the chat to be a fixed part of the page rather than a floating overlay.
Getting the Iframe Code
1
Open your app and click Publish > Share in the navigation.
2
Look for the Iframe card on the Share page.
3
Click the code snippet to copy it:
<iframe src="https://your-app.on.chipp.ai" height="800px" width="100%" frameborder="0" allow="microphone; clipboard-write; screen-wake-lock" title="Your App Name"></iframe>The allow="microphone; clipboard-write; screen-wake-lock" attribute is required for voice mode to work properly on mobile devices. Without screen-wake-lock, the phone screen will lock during a voice call and end the conversation.
4
Paste the iframe code into your website’s HTML where you want the chat to appear.
Customizing the Iframe
Adjust dimensions:
<iframe
src="https://your-app.on.chipp.ai"
height="600px"
width="400px"
frameborder="0"
allow="microphone; clipboard-write; screen-wake-lock"
title="Chat"
></iframe>Responsive container:
<div style="width: 100%; height: 80vh; min-height: 400px;">
<iframe
src="https://your-app.on.chipp.ai"
style="width: 100%; height: 100%; border: none;"
allow="microphone; clipboard-write; screen-wake-lock"
></iframe>
</div>Platform-Specific Instructions
WordPress
For Widget:
- Go to Appearance > Theme Editor (or use a plugin like “Insert Headers and Footers”)
- Add the widget code before
</body>in your theme’s footer
For Iframe:
- Edit your page or post
- Add a Custom HTML block
- Paste the iframe code
Webflow
- Go to Project Settings > Custom Code
- For widget: Paste in “Footer Code”
- For iframe: Add an Embed element to your page
Squarespace
For Widget:
- Go to Settings > Advanced > Code Injection
- Paste in the “Footer” section
For Iframe:
- Add a Code Block to your page
- Paste the iframe code
Shopify
For Widget:
- Go to Online Store > Themes > Edit code
- Find
theme.liquidand paste before</body>
For Iframe:
- Edit the page where you want the chat
- Add a Custom Liquid section
- Paste the iframe code
Wix
For Widget:
- Go to Settings > Custom Code
- Click Add Code in the Body - End
- Paste the widget script tag
For Iframe:
- Add an HTML iframe element to your page
- Set the source URL to your app URL
Framer
For Widget:
- Go to Site Settings > Custom Code
- Add the widget script in the “End of
<body>tag” section
For Iframe:
- Add a Code component
- Paste the iframe embed code
Cookies & Cross-Origin Embeds
Chipp automatically handles cross-origin cookie restrictions for iframe and widget embeds. When your chatbot detects it’s running inside an iframe on a different domain, it sets cookies with SameSite=None so the browser allows them in the cross-site context. This means both anonymous and authenticated chat work out of the box in iframe embeds — no extra configuration needed.
Some browsers (notably Safari with Intelligent Tracking Prevention) may still block third-party cookies in certain configurations. If you notice users having trouble maintaining their chat sessions in an iframe embed, consider one of these alternatives:
- Set up a custom domain that’s a subdomain of your website (best for iframe embeds — same-site cookies just work)
- Use server-side auth with
setUser()to pass a bearer token via PostMessage (bypasses cookies entirely)
How Server-Side Auth Bypasses Cookie Issues
For apps with authentication enabled, or for maximum compatibility with strict browser privacy settings, the setUser({ token }) approach avoids cookies entirely:
- Your server calls
POST /api/v1/apps/{APP_ID}/consumers/authwith the user’s email - The API returns a bearer token
- Your frontend passes the token to
ChippWidget.setUser() - The widget sends the token to the iframe via PostMessage
- The iframe uses the bearer token for authentication instead of cookies
This works in cross-origin contexts because PostMessage is not affected by cookie restrictions.
You can configure these settings in:
- Settings page for custom domains
- Access page for authentication settings
Content Security Policy (CSP)
If your website uses a strict Content Security Policy, you’ll need to allow the widget’s script and iframe:
frame-src *.on.chipp.ai;
script-src your-app.on.chipp.ai;Replace with your custom domain if you have one configured.
If you’re using a nonce-based CSP, add the nonce to the script tag:
<script nonce="YOUR_NONCE" src="https://your-app.on.chipp.ai/w/chat/chipp-widget.js"></script>Troubleshooting
Widget Not Appearing
- Check code placement: Widget code should be before
</body>, not inside<head> - Check for conflicts: Other scripts may interfere — check browser console for errors
- Check app status: Ensure your app is published and active
- Check CSP: Your site’s Content Security Policy may block the script or iframe
- Check mobile: If
data-hide-on-mobile="true"is set, the widget won’t appear on mobile
Widget Appears But Chat Won’t Open
- Check the console: Look for network errors or CORS issues
- Check the app URL: Ensure the app is reachable at the URL in the script
src - Check authentication: If auth is enabled, use
setUser()with a token or set up a custom domain
Iframe Shows “Session Not Found” Error
This typically means the browser is blocking cookies in the cross-origin iframe context. Chipp handles this automatically, but some strict privacy settings can still interfere:
- Safari ITP: Safari aggressively blocks third-party cookies. Use a custom domain (subdomain of your site) or server-side auth with
setUser({ token }) - Chrome Incognito: Third-party cookies may be blocked by default in Incognito mode
- Browser extensions: Privacy extensions (uBlock Origin, Privacy Badger) may block cross-site cookies
Iframe Not Loading
- Check the URL: Make sure the iframe
srcmatches your app’s URL exactly - CSP headers: Your site’s Content Security Policy may block iframes
- X-Frame-Options: Some hosting providers set
X-Frame-Options: DENYby default
Styling Issues
- Z-index conflicts: Use the
data-z-indexattribute to adjust widget stacking order - Container overflow: For iframe, make sure parent elements don’t have
overflow: hidden - Mobile display: Use
data-hide-on-mobile="true"if the widget conflicts with your mobile layout - Double widget: If you see two widgets, make sure the script tag is only included once. The widget prevents double-initialization, but old v1 and new v2 scripts can coexist
User Identity Not Working
- Check
setUsertiming: CallsetUser()after the widget script has loaded. Listen for thereadyevent if needed:javascriptChippWidget.on("ready", () => { ChippWidget.setUser({ email: "user@example.com" }); }); - Check token validity: Server-side tokens expire. Generate a fresh token on each page load
- Check API key scope: The Builder API key must have write scope to call
/consumers/auth