Migrate from v1

Move a v1 widget install to v2. The snippet, identity tokens and npm API all change.

v2 is a new widget. It uses a different key, a different host, and a different identity token. Existing v1 conversations stay in your inbox as tickets; they do not appear in the v2 widget history.

SpendCrypto is the only production v1 install we know of. If that’s you, start with the Django identity route and the script tag or the npm API.

What changes

v1v2
appId + teamSlugOne publishable key (pk_...) per widget
unpkg.com/@ticketping/chat-widget plus a CSS filehttps://widget.ticketping.com/v2/loader.js (no CSS file)
window.TicketpingChat / TicketpingChat.initwindow.Ticketping / Ticketping('init', { publishableKey })
Host JWT with no expiry, looked up by emailShort-lived HS256 JWT (sub, exp at most 10 minutes; the examples use 5), signed with TICKETPING_IDENTITY_SECRET
authOnlyTickets team flagIdentified users only and Require verified identity on the widget’s Security tab
Cookies for the chat JWTlocalStorage keys namespaced by publishable key

Create a widget at Settings → Widgets and copy its publishable key. Create the identity secret at Settings → API → Identity secret. Both values are the same in every environment.

Identified users only shows anonymous visitors a “Log in to chat” button instead of the message box. Require verified identity refuses identify calls that have no token, so a typed-in email is not enough. Turn both on to match what authOnlyTickets did.

Replace the snippet

Remove the v1 script, its CSS, and any window.ticketpingConfig block.

html
<script src="https://widget.ticketping.com/v2/loader.js" data-key="pk_..." async></script>

Until 2.0.0 is released, /v2/loader.js is not published. Pin a beta with the SRI install, or install @ticketping/chat-widget@next.

Identify signed-in users

v1 sent a long-lived token from the browser. v2 asks your server for a fresh token whenever it needs one.

html
<script>
  window.Ticketping ||= (...args) => (Ticketping.q ||= []).push(args)

  Ticketping('identify', {
    userId: '{{ user.id }}',
    email: '{{ user.email }}',
    name: '{{ user.get_full_name }}',
    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>

The route signs { sub, email, name, exp: now + 300 } with HS256 using TICKETPING_IDENTITY_SECRET. Copy the one for your stack from Identity verification.

Turn on Require verified identity on the widget before you go live, so nobody can claim another user’s identity from the browser console.

npm

npm install @ticketping/chat-widget@next
ts
import { Ticketping } from '@ticketping/chat-widget'

Ticketping.init({ publishableKey: 'pk_...' })
Ticketping.identify({ userId, email, name, getToken })

Framework adapters live on subpaths: @ticketping/chat-widget/react, /vue, /svelte. See Next.js, Vue and SvelteKit.

The v1 default export, TicketpingChat, the React TicketpingChat component, and the Svelte 4 wrapper are gone.

What stays in the inbox

v1 chats already stored as tickets remain in the dashboard and in Slack. The v2 widget only lists conversations created through v2, so a returning user starts clean in the widget and your team still has the old tickets.

Before you cut over

  1. Install the v2 snippet on localhost and send a test message. It is tagged TEST and does not mix with live tickets.
  2. Identify a signed-in user and confirm the Verified badge in the inbox. Use the token validator if the token is rejected.
  3. Lock allowed domains, then switch production to the v2 snippet and remove the v1 one.