Screen pop
Pushes content to the answering agent's softphone — either a URL (CRM page, ticket, knowledge base) or inline custom HTML you author here. Every pop opens…
What it does
Pushes content to the answering agent's softphone — pick a pop type: a
URL (CRM customer page, open ticket, knowledge-base article) or Custom
HTML (an inline card you author right here). This single node covers both
modes; the former standalone "Custom pop" node has been folded in. Templates
resolve server-side against vars, contact, and event, so what you ship
can be specific to this caller (https://crm.acme.com/customers/{{contact.id}},
or <h3>{{contact.displayName}}</h3>) without any client-side glue.
Every pop renders as a tab in the agent's side panel — one panel per call,
next to the softphone, with the caller card first and flow pops after it. A
URL pop can instead open in a new browser tab (mode: newTab); on the
mobile app a new-tab pop never opens on its own, it shows as a side-panel tab
with an Open button. HTML pops always use the side panel. There is no
"embedded in the phone" pop any more: flows saved with mode: iframe,
mode: embedded or htmlMode: embedded render in the side panel.
The pop is published over the per-user realtime channel that the softphone
subscribes to, so it only reaches the specific agent who answered the
bridge — not every agent in the org. That's why this node only works inside
an onAgentAnswered chain: outside that scope the worker has no agent
identity to address. Pops are buffered per-call on the softphone and GC'd
about thirty seconds after the call ends, so a pop that fires near
hangup still gets a chance to display before its owning call closes.
When to use it
- Open a CRM customer record the moment an agent answers a known caller
- Drop a ticket or work-order URL into the agent's side panel for inbound service calls
- Surface a knowledge-base article when the caller landed in a specialty queue (warranty, billing, technical)
- Open a payment or e-sign page in a new tab when the flow has gathered enough context to start a transaction
- Pair with
contactLookupso the URL deep-links by contact id only when the caller is recognized
Configuration
Pushes content to the answering agent's softphone — either a URL (CRM page, ticket, knowledge base) or inline custom HTML you author here. Every pop opens as a tab in the agent side panel; a URL pop can open in a new browser tab instead. Only works inside an "On agent answered" chain.
| Field | Label | Type | Required | Default | Notes |
|---|---|---|---|---|---|
| source | Pop type | select | Optional | url | Options: url, html. |
| url | URL | text | Required | https://crm.acme.com/customers/{{contact.id}} | Supports {{contact.}}, {{vars.}}, {{event.from}} templates. Must be HTTPS. |
| mode | How to display | select | Optional | drawer | Options: drawer, newTab. The side panel shows the page as a tab next to the softphone. A new tab is never opened on the mobile app — there the pop is a side-panel tab with an Open button. Flows saved with the old "Embedded iframe" option show in the side panel. |
| requireClick | Require agent click to open | boolean | Optional | false | Force a click-to-open notification instead of auto-opening. |
| html | HTML body | json | Required | {} | Full HTML document or fragment, shown as a tab in the agent side panel. Supports {{contact.}}, {{vars.}}, {{event.*}} templates expanded server-side before delivery. |
| width | Width (px) | number | Optional | 0 | |
| height | Height (px) | number | Optional | 320 |
Outgoing events: __next
Examples
Side-panel pop with a contact id
A standard pop that opens the matched contact's CRM page in the agent's side panel the instant the agent picks up.
{
"id": "pop-crm",
"type": "screenPop",
"config": {
"url": "https://crm.acme.com/customers/{{contact.id}}",
"mode": "drawer",
"requireClick": false
},
"on": { "__next": "agent-whisper" }
}
Side panel with a click-to-open guard
Use requireClick: true when the URL is heavy or shouldn't load until the
agent is ready. The agent sees a click target in the side panel and the
page only fetches when they ask for it.
{
"id": "pop-ticket",
"type": "screenPop",
"config": {
"url": "https://help.acme.com/tickets/{{vars.ticketId}}",
"mode": "drawer",
"requireClick": true,
"width": 480,
"height": 640
},
"on": { "__next": "end" }
}
Gotchas
- Only fires inside an
onAgentAnsweredchain. The worker readsstate.triggerAgent.userIdto route the pop to a specific user channel. If you drop this node before any bridge picks up — or anywhere outside an agent-answered chain — the worker logs a warning and skips it. The flow still advances down the next edge. - HTTPS only. URLs that aren't
https://...are dropped at the worker with a warning. The side panel also enforces mixed-content rules, so plainhttp://would fail to render even if the worker passed it through. - The side panel is sandboxed without same-origin. The softphone uses
sandbox="allow-scripts allow-forms"— explicitly noallow-same-origin. Any in-page script that reads cookies, talks to its own backend on its own session, or assumes window.parent access will break. For full-fidelity pages, usemode: newTabinstead (on the mobile app that is an Open button, not an automatic tab). - Templates are resolved when the node fires, not when it loads. If
vars.ticketIdchanges after the pop is sent (because a later script rewrites it) the URL the agent sees is the old one. The pop is a one-shot event, not a live binding. - One pop per call view, mostly. The softphone dedups identical pops
inside a ~2 second window per
callId. Firing the same node twice in quick succession (e.g. inside a tight loop) yields a single visible pop. - The agent must be online. The pop is published to Redis and forwarded via the user channel — if the agent's softphone has lost its websocket the event will not be replayed when they reconnect.
