Skip to main content

Quick test

Create an API key at Organization Settings → API → Generate Key — it is shown once. Mint yourself a token with it:
email is the only required field; name and ttl_seconds are in Step 1. Take the token from the response and open:
Once that works, drop it into any page:
The frame fills whatever you give it, so the container needs a real height. Aim for 1000px of width or more — answers open a side panel for charts and SQL, and it gets cramped below that. That token is tied to you and expires in an hour, so the chat will stop working — the three steps below replace it with one token per user, refreshed automatically.

How it works

Your user logs into your app → your frontend asks your backend for a token → your backend calls ClarityQ with your API key → your page loads the iframe, and hands it a fresh token whenever it asks for one.

Identity

The email you send is the identity. Same address next visit, same conversation history. It becomes an ordinary ClarityQ user — so if that address already uses ClarityQ, it is that person, with the history and remembered preferences they already have.

Step 1 — Mint tokens on your server

Using the same API key, expose one endpoint behind your own login:
Every field, error and a playground to try it: Mint an embed token.

Step 2 — Render the iframe and answer one message

The embed manages its own lifetime. At about 80% of its token’s lifetime it posts clarityq:token-expiring to your page. You reply with a fresh token and it swaps it in place: no reload, no timer, nothing lost. An answer that is streaming keeps streaming; text your user has typed stays typed.
If your mint endpoint fails once, do nothing special — the embed falls through to clarityq:token-expired, and the same listener answers it when your endpoint recovers. The request that failed in between is lost; the conversation is not.

Step 3 — Add a history panel (optional)

The iframe is chat only — one conversation at a time, no list, no new-chat button — so it drops into your product without bringing a second navigation with it. Skip this step and every visit starts a fresh chat. Nothing is lost: ClarityQ stores each conversation either way, and they are all still there under that user’s identity. Your users just have no route back to them. If you want that route, the split is: ClarityQ stores the conversations, you render the list. Two things to wire. 1. List themList conversations, authenticated with the token you already hold (Authorization: Bearer, not the API key). It returns only that user’s conversations, scoped server-side. Sort on last_updated; description is the title — a new conversation starts as New Chat and gets its real title a few seconds into the first answer, announced by clarityq:title so you never re-fetch for it. 2. Open them, and keep them named — switching is a postMessage into the running iframe: internal navigation, so it is instant and needs no token. A brand-new chat announces its id the same way — catch it or that conversation is orphaned — and its title arrives moments later:

Open in ClarityQ (optional)

A button in your own header that hands the conversation to the full ClarityQ app — same conversation, same user, nothing to set up:
The button works for anyone who can sign into ClarityQ. Embed users are ordinary ClarityQ users under the same email, so there are two ways in: your organization’s SSO, or an invitation sent from ClarityQ user management — either one lands them in the conversation, with their history. Users with neither hit a login screen they cannot pass, so only show the button to people who have a way in.

Troubleshooting