HTML and site builders
Add the chat widget to a plain HTML site, Webflow, Framer or WordPress with one script tag.
One script tag works on any site. Get your publishable key (pk_...) from Settings → Widgets. It’s public, so it’s fine in your HTML.
Install
<script src="https://widget.ticketping.com/v2/loader.js" data-key="pk_..." async></script>Where to paste it:
| Site | Where |
|---|---|
| Plain HTML | Before </body> on every page, or in your shared layout |
| Webflow | Site settings → Custom code → Footer code. Publish the site |
| Framer | Site settings → General → Custom code → End of <body> tag. Publish the site |
| WordPress | Your theme’s footer, or a plugin that adds code to the footer (for example WPCode). Avoid page builders that strip data- attributes |
Open the site on localhost (or your published URL) and click the launcher. Messages from localhost are marked as test conversations, so you can try everything safely.
Identify signed-in users
Marketing sites usually stay anonymous, and that’s fine: visitors can still chat and leave an email for replies.
If your site has logins, render the signed-in user’s details into the page and pass a getToken function. The widget calls it to get a short-lived token from your server, which proves the user is who the page says.
<script>
window.Ticketping ||= (...args) => (Ticketping.q ||= []).push(args)
Ticketping('identify', {
userId: 'u_123',
email: 'ada@acme.com',
name: 'Ada Lovelace',
getToken: async () => {
const res = await fetch('/api/ticketping-token', { method: 'POST' })
if (!res.ok) throw new Error(`Ticketping token request failed (${res.status})`)
return res.text()
}
})
</script>When the user signs out, call Ticketping('logout'). The widget forgets them and starts a new anonymous visitor, so the next person on the device can’t see their conversations.
Add the token route
/api/ticketping-token is the one piece of server code you write. It checks who’s signed in, signs { sub, email, name, exp } with TICKETPING_IDENTITY_SECRET, and returns the token as text. Copy it for your backend:
Get the secret from Settings → API → Identity secret and set it as an environment variable on your server:
TICKETPING_IDENTITY_SECRET=tpis_...The identity secret signs tokens for any user. Keep it on your server, out of your HTML and out of version control.
Check that it works
- Sign in to your site and open the browser console.
- Run
await (await fetch('/api/ticketping-token', { method: 'POST' })).text()and copy the token. - Paste it into the token validator under Settings → API → Identity secret. It shows the claims, or says exactly what to fix.
- Reload the page and send a message. In the dashboard, the conversation shows the user’s name with a Verified badge.
The validator never marks a token as used, so checking a token there doesn’t break the widget.
Options
Pass options with an explicit init instead of data-key when you need them. Code settings override the dashboard:
<script>
window.Ticketping ||= (...args) => (Ticketping.q ||= []).push(args)
Ticketping('init', {
publishableKey: 'pk_...',
appearance: { accentColor: '#0F766E', position: 'bottom-left' },
texts: { greetingTitle: 'Questions? Ask us.' }
})
</script>
<script src="https://widget.ticketping.com/v2/loader.js" async></script>See Configuration for every setting and the JavaScript API for methods like open, showNewMessage and events.
Copy prompt for your AI coding agent
Add the Ticketping chat widget (v2) to this site.
Docs index: https://ticketping.com/llms.txt
This page as Markdown: https://ticketping.com/docs/vanilla-js.md
1. Add this to the shared layout, before </body>, so it's on every page:
<script src="https://widget.ticketping.com/v2/loader.js" data-key="pk_..." async></script>
Ask me for the publishable key (starts with pk_). It's public and the same in every environment.
2. If the site has signed-in users:
a. Add a POST /api/ticketping-token route on the server, using the code for this backend from
https://ticketping.com/docs/authentication.md. It must return 401 when nobody is signed in, and
otherwise return, as plain text, an HS256 JWT signed with the TICKETPING_IDENTITY_SECRET env var:
{ sub: String(user id), email, name, exp: now + 300 seconds }. Leave out email or name if empty.
b. Add TICKETPING_IDENTITY_SECRET=tpis_... to the server's env file (not committed) and to .env.example without a value.
c. In the layout, for signed-in users only, add:
window.Ticketping ||= (...args) => (Ticketping.q ||= []).push(args)
Ticketping('identify', { userId, email, name, getToken }) where getToken POSTs to /api/ticketping-token and returns the response text (throw if the response isn't ok).
d. Call Ticketping('logout') when the user signs out.
3. Never cache tokens and never expose the secret to the browser.
4. Tell me how to verify: sign in, run await (await fetch('/api/ticketping-token', { method: 'POST' })).text() in the console, and paste the token into the token validator at Settings → API → Identity secret.