Screen Pop
Open the customer record in your app on the very first ring — before anyone says hello.
Two event surfaces can drive a Screen Pop; pick the one that matches your architecture.
Option 1: frontend via Server-Sent Events (simplest for embedded integrations)
If the customer record already lives in a browser tab, let the browser itself subscribe to DialStack events and react. No backend round-trip.
DialStack pushes real-time events to the browser over Server-Sent Events (SSE) — a long-lived HTTP connection that streams events one-way from server to client. It's simpler than WebSockets and reconnects automatically.
Use the SDK to open an SSE stream with a session token:
import { loadDialstackAndInitialize } from '@dialstack/sdk-js';
const dialstack = await loadDialstackAndInitialize({
publishableKey: 'pk_live_YOUR_KEY',
fetchClientSecret: async () => {
const res = await fetch('/api/dialstack/session');
const { client_secret, expires_at } = await res.json();
return { clientSecret: client_secret, expiresAt: expires_at };
},
});
dialstack.on('call.incoming', async (event) => {
const customer = await lookupByPhone(event.from_number);
if (customer) openCustomerRecord(customer.id);
});
Latency: sub-second from the first ring to the record opening. Connection stays alive as long as the browser tab is open. SSE reconnects automatically.
See Real-Time Events for the full SSE API, authentication, and reconnection behavior.
Option 2: backend webhook → your own realtime channel
If the customer lookup requires your backend (to cross a firewall, join a DB, call a CRM), handle the Screen Pop server-side and push to the frontend over your own channel:
import { DialStack } from '@dialstack/sdk-server';
// POST /webhooks/dialstack — registered as a webhook endpoint
app.post('/webhooks/dialstack', express.raw({ type: 'application/json' }), async (req, res) => {
const event = DialStack.webhooks.constructEvent(
req.body,
req.header('x-dialstack-signature'),
process.env.DIALSTACK_WEBHOOK_SECRET
); // throws on a bad signature; see receiving-webhooks.md
if (event.type === 'call.incoming') {
const customer = await db.customers.findOne({ phone: event.data.from_number });
if (customer) {
// push to the user's open session via YOUR realtime channel
pusher.trigger(`user-${event.data.user}`, 'screen-pop', {
customerId: customer.id,
callId: event.data.call_id,
});
}
}
res.status(200).end();
});
Webhooks are fire-and-forget — respond 200 quickly. Don't do the customer lookup on the webhook's critical path if it can be slow; queue it.
What makes a good Screen Pop
- Speed over completeness. Pop the record in < 500ms. Enrich later.
- Degrade gracefully. Unknown caller? Show the unknown-caller state, don't hide the Screen Pop entirely.
- Idempotent. A webhook can be delivered more than once: de-dupe by the envelope's
id. SSE events carry noid; key a pop oncall_idwhen you read the stream directly, or on the caller andtimestampwith the SDK, so a repeated event doesn't open the record twice. - No blocking UI. If lookup fails, log it and continue — never block the ring.
Where the data comes from
The call.incoming event carries different fields on each surface:
| Field | SDK (dialstack.on) | SSE stream | Webhook (event.data) | Use for |
|---|---|---|---|---|
from_number | yes | yes | yes | Match to a customer record (E.164) |
from_name | yes | yes | yes | Fall-back display name when you have no match (may be null) |
to_number | yes | yes | yes | Which of your numbers was dialed (useful for multi-location routing) |
user_id | yes | yes | as user | The user the call is routed to, when it targets a single user directly |
call_id | no | yes | yes | Stable call identifier: attach the opened record to your activity log, and later fetch call details, recording, or transcript |
timestamp | yes (a Date) | yes | started_at | When the call arrived |
See Real-Time Events for the SSE payload and Webhook Events for the webhook payload. Signature verification is covered in Receiving Webhooks.
See also
- Real-Time Events (SSE) — account-scoped event stream for frontends.
- Webhook Events — platform-scoped webhook firehose.
- Receiving Webhooks — endpoints, signatures, retries.
- Activity Logging — the other half of the event loop: write the call to your system of record.