Skip to content
Agent experiencescreenPop

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. Choose how it r…


type: screenPop status: stable sinceVersion: 0.1.0 seeAlso: [agentNotify] keywords: ["screenPop", "screen", "pop", "url", "html", "custom pop", "agent experience"]

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.

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 drawer 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 contactLookup so 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. Choose how it renders: embedded inline, side drawer, or a new browser tab. Only works inside an "On agent answered" chain.

FieldLabelTypeRequiredDefaultNotes
sourcePop typeselectOptionalurlOptions: url, html.
urlURLtextRequiredhttps://crm.acme.com/customers/{{contact.id}}Supports {{contact.}}, {{vars.}}, {{event.from}} templates. Must be HTTPS.
modeHow to displayselectOptionaldrawerOptions: drawer, iframe, newTab.
requireClickRequire agent click to openbooleanOptionalfalseForce a click-to-open notification instead of auto-opening.
htmlHTML bodyjsonRequired{}Full HTML document or fragment. Supports {{contact.}}, {{vars.}}, {{event.*}} templates expanded server-side before delivery.
htmlModeHow to displayselectOptionalembeddedOptions: embedded, drawer.
widthWidth (px)numberOptional0
heightHeight (px)numberOptional320

Outgoing events: __next

Examples

Drawer pop with a contact id

A standard pop that opens the matched contact's CRM page in the softphone's drawer 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" }
}

Iframe with a click-to-open guard

Use mode: iframe plus requireClick: true when the URL is heavy or shouldn't load until the agent is ready. The agent sees a click target on the softphone 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": "iframe",
    "requireClick": true,
    "width": 480,
    "height": 640
  },
  "on": { "__next": "end" }
}

Gotchas

  • Only fires inside an onAgentAnswered chain. The worker reads state.triggerAgent.userId to 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 softphone iframe modes also enforce mixed-content rules, so plain http:// would fail to render even if the worker passed it through.
  • iframe mode is sandboxed without same-origin. The softphone uses sandbox="allow-scripts allow-forms" — explicitly no allow-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, use mode: newTab instead.
  • Templates are resolved when the node fires, not when it loads. If vars.ticketId changes 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.