Help
Developers

Page SDK

The widget's window.showpilot: hear milestones on the page, tell the agent who the visitor is, hand it context, open a tour.

The embed script installs window.showpilot the moment it runs. It is small, additive, and does nothing until you call it, so an existing embed is unchanged.

<script>
  // Optional: queue calls before the script loads.
  window.showpilotq = window.showpilotq || [];
  window.showpilotq.push(['on', 'meeting.booked', (e) => console.log('booked', e)]);
</script>

Hear milestones

showpilot.on('tour.completed', ({ publicId }) => { /* … */ });
const off = showpilot.on('*', (e) => analytics.track(e.event, e)); // every milestone
off();

Events use the same names as the webhook catalog: conversation.started, lead.identified, meeting.booked, tour.played, tour.step_viewed, tour.cta_clicked, tour.completed, content.viewed, content.completed, voice.started, visitor.identified. Payloads never carry personal data; the same milestones also land on window.dataLayer as showpilot_<name>.

Tell the agent who the visitor is

showpilot.identify({
  userId: 'u_42',                 // or email
  email: 'sam@acme.example',
  name: 'Sam Rivera',
  traits: { plan: 'team', seats: '40' },
  signature: '<from your server>',
  timestamp: 1758800000,
});

Unsigned calls are accepted and the visitor is marked claimed. To make it verified, your server signs the subject (the userId, else the email) with the identity secret from Settings → API keys:

// Node, on your server, per page load
const ts = Math.floor(Date.now() / 1000);
const signature = 'sha256=' + crypto.createHmac('sha256', IDENTITY_SECRET).update(`${userId}.${ts}`).digest('hex');

Signatures are good for ten minutes. A bad or stale signature is refused with 400, never silently downgraded. The call resolves { ok, visitorId, identity: 'verified' | 'claimed' } and fires visitor.identified on the page.

Hand it context

showpilot.context({ plan: 'enterprise', stage: 'renewal', account: 'Acme' });

Up to twenty string values, kept for the page. They ride every chat turn and the session's launch context, so the agent answers as if it already knew.

Open something

showpilot.open();                              // the panel
showpilot.open({ tour: '<tour public id>' });  // a tour, in the agent's stage
showpilot.open({ tour: '<id>', step: 3 });
showpilot.ready(() => { /* the widget has mounted */ });

Calls made before the widget mounts wait for it.

On this page