Screen Pop: Architecture & Implementation
Overview
Screen pop is the automatic display of a customer record when they call. Agent's desktop automatically looks up the caller by phone number and displays their Salesforce record.
Benefits:
- No manual lookup needed (saves 30+ seconds per call)
- Agent sees customer context immediately
- Fewer wrong accounts selected
- Better first-call resolution
How It Works (The Flow)
Customer calls (ANI: +15551234567)
↓
Architect Flow receives call
↓
Data Action: Look up contact by phone
in Salesforce API
↓
Salesforce returns: Contact ID + Account info
↓
Flow sets Interaction Attributes:
- contact_id = "003xx000003SG"
- account_id = "001xx000002Edc"
↓
Flow transfers to Support Queue
↓
Agent receives call
↓
Agent's desktop extension
reads Interaction Attributes
↓
Desktop makes API call to Salesforce:
GET /sobjects/Contact/003xx000003SG
↓
Browser pops Salesforce record in new window
↓
Agent sees: Name, account, cases, history
↓
Agent handles call with context
Architecture Components
1. Call Entry Point (Architect Flow)
The flow that receives inbound calls:
START
↓
Play: "Thank you for calling..."
↓
Data Action: lookup-contact-by-phone
Input: ${interaction.caller.phoneNumber}
Output: ${contact.id}, ${account.id}
↓
Decision: Contact found?
YES → Set attributes → Transfer
NO → Collect account number → Transfer
↓
Transfer to Queue
(attributes go with call)
↓
END
2. Data Action (API Call)
{
"name": "lookup-contact-by-phone",
"method": "POST",
"url": "https://your-instance.salesforce.com/services/apexrest/contact-lookup",
"inputContract": {
"phoneNumber": {
"type": "string",
"required": true
}
},
"outputContract": {
"success": { "type": "boolean" },
"contactId": { "type": "string" },
"firstName": { "type": "string" },
"lastName": { "type": "string" },
"accountId": { "type": "string" },
"accountName": { "type": "string" },
"tier": { "type": "string" }
}
}
3. Interaction Attributes
Data attached to the call that agent's desktop can access:
{
"contact_id": "003xx000003SG",
"contact_name": "John Doe",
"account_id": "001xx000002Edc",
"account_name": "Acme Corp",
"customer_tier": "Premium",
"last_contact": "2026-03-10T14:30:00Z"
}
4. Agent Desktop Extension
JavaScript in the Genesys Workspace (desktop app or web):
// Listen for incoming interaction
genesysClient.on('interaction.incoming', async (interaction) => {
// Get attributes set by flow
const contactId = interaction.attributes?.contact_id;
if (contactId) {
// Pop Salesforce record
const recordUrl = `https://your-instance.salesforce.com/${contactId}`;
window.open(recordUrl, 'salesforce');
}
});
Step-by-Step Implementation
Step 1: Create Salesforce Apex Endpoint
// ContactLookupController.cls
@RestResource(urlMapping='/contact-lookup')
global class ContactLookupController {
@HttpPost
global static LookupResponse lookup(String phoneNumber) {
LookupResponse response = new LookupResponse();
try {
// Search for contact by phone
List<Contact> contacts = [
SELECT Id, FirstName, LastName, Email,
AccountId, Account.Name,
Custom_Tier__c
FROM Contact
WHERE Phone = :phoneNumber
OR MobilePhone = :phoneNumber
LIMIT 1
];
if (contacts.isEmpty()) {
response.success = false;
return response;
}
Contact contact = contacts[0];
response.success = true;
response.contactId = contact.Id;
response.firstName = contact.FirstName;
response.lastName = contact.LastName;
response.accountId = contact.AccountId;
response.accountName = contact.Account?.Name;
response.tier = contact.Custom_Tier__c;
} catch (Exception e) {
response.success = false;
response.error = e.getMessage();
}
return response;
}
global class LookupResponse {
public Boolean success;
public String contactId;
public String firstName;
public String lastName;
public String accountId;
public String accountName;
public String tier;
public String error;
}
}
Step 2: Create Architect Flow
In Genesys Architect → Create Inbound Call Flow:
Flow Steps:
1. START
↓
2. Play Audio: "Thank you for calling..."
↓
3. Data Action: lookup-contact-by-phone
Input: ${interaction.caller.phoneNumber}
↓
4. Decision: ${dataAction.result.success}?
IF YES:
└─ Set Agent Variables:
- contact_id = ${dataAction.result.contactId}
- contact_name = ${dataAction.result.firstName} ${dataAction.result.lastName}
- account_id = ${dataAction.result.accountId}
- account_name = ${dataAction.result.accountName}
- customer_tier = ${dataAction.result.tier}
IF NO:
└─ Play Audio: "Please hold while we locate your account..."
↓
5. Transfer to Queue: Support Queue
↓
6. DISCONNECT
Step 3: Create Desktop Extension
In Genesys Cloud → Integrations → Custom Apps → Desktop App Extensions:
// manifest.json
{
"version": "1.0",
"name": "Salesforce Screen Pop",
"description": "Pops Salesforce contact on inbound call"
}
// index.html
<!DOCTYPE html>
<html>
<head>
<script src="https://sdk.mypurecloud.com/v131/platform.min.js"></script>
</head>
<body>
<script>
const client = require('purecloud-platform-client-v2');
// Initialize
const platformClient = client.ApiClient.instance;
platformClient.setEnvironment('mypurecloud.com');
// Listen for incoming interaction
const notificationService = platformClient.createNotificationService();
notificationService.subscribe(
'v2.conversations.{id}',
async (event) => {
const interaction = event.eventBody;
// Check if attributes set by flow
if (interaction.attributes?.contact_id) {
const contactId = interaction.attributes.contact_id;
const accountId = interaction.attributes.account_id;
const contactName = interaction.attributes.contact_name;
// Build Salesforce URL
const baseUrl = 'https://your-instance.salesforce.com';
const recordUrl = `${baseUrl}/${contactId}`;
// Pop window
window.open(recordUrl, 'salesforce_record',
'width=1200,height=800,resizable=yes');
console.log(`Screen pop: ${contactName} (${accountId})`);
}
}
);
</script>
</body>
</html>
Handling Edge Cases
Multiple Matches
Problem: Phone number found 3 contacts (different names, same company)
Solution: Let agent pick
Flow: Decision - ${dataAction.result.matches.length} > 1?
IF YES:
└─ Play: "Multiple accounts found. Press..."
└─ Collect Input:
"Press 1 for John Doe"
"Press 2 for Jane Doe"
"Press 3 for John Smith"
└─ Set contact_id = ${dataAction.result.matches[input]}.id
IF NO:
└─ Continue normally
Contact Not Found
Problem: Phone number not in Salesforce
Solution: Offer fallback
Flow: Decision - ${dataAction.result.success}?
IF NO:
└─ Play: "Account not found. Please enter your account number..."
└─ Collect Input: Account Number
└─ Data Action: lookup-by-account-number
└─ Set attributes if found
└─ Transfer without pop if not found
Slow Lookup (Timeout)
Problem: Salesforce API slow, lookup takes 5+ seconds
Solution: Don't block the call
Flow: Data Action: lookup-contact-by-phone
Timeout: 3 seconds
Decision: Action succeeded?
IF YES (within 3 sec):
└─ Set attributes → Transfer
IF NO (timed out):
└─ Play: "Connecting you now..."
└─ Transfer WITHOUT attributes
└─ (Agent can manual search)
Salesforce Field Mapping
What agent sees after screen pop:
| Data Point | Source | Salesforce Record |
|---|---|---|
| Contact Name | Flow attribute | Contact.Name |
| API response | Contact.Email | |
| Phone | API response | Contact.Phone |
| Account | Flow attribute | Account.Name |
| Tier/Priority | Flow attribute | Contact.Custom_Tier__c |
| Recent Cases | (automatic in SF) | Related Cases |
| Contact History | (automatic in SF) | Activity Timeline |
Performance Optimization
Problem: Lookup taking 2+ seconds
Causes:
- Salesforce API slow
- Network latency
- SOQL query inefficient
Solutions:
-
Add Index in Salesforce
-- Make phone lookups fast CREATE INDEX idx_contact_phone ON Contact(Phone, MobilePhone); -
Cache recent lookups
class ScreenPopCache { constructor(ttlSeconds = 3600) { this.cache = new Map(); this.ttl = ttlSeconds; } async lookup(phone) { const cached = this.cache.get(phone); if (cached && Date.now() - cached.timestamp < this.ttl * 1000) { return cached.data; } const result = await callSalesforceAPI(phone); this.cache.set(phone, { data: result, timestamp: Date.now() }); return result; } } -
Use webhook instead of polling
- Salesforce creates contact → webhook updates Genesys
- (More advanced, requires webhook setup)
Testing Screen Pop
Manual Test
- Configure test flow in Architect
- Set up desktop extension locally
- Make test call to your Genesys DID
- Verify:
- ✓ Architect flow receives call
- ✓ Data Action executes (check execution history)
- ✓ Salesforce API returns contact
- ✓ Flow sets interaction attributes
- ✓ Desktop receives attributes
- ✓ Window pops Salesforce record
Automated Test
// test-screen-pop.js
async function testScreenPop() {
// 1. Test Salesforce lookup
const contact = await lookupContactByPhone('+15551234567');
console.assert(contact.id, 'Contact not found');
// 2. Test Genesys Data Action
const result = await callDataAction('lookup-contact-by-phone', {
phoneNumber: '+15551234567'
});
console.assert(result.success, 'Data Action failed');
// 3. Test flow
const call = await makeTestCall('+15551234567');
const attributes = call.attributes;
console.assert(attributes.contact_id, 'No contact_id in attributes');
console.log('✓ Screen pop test passed');
}
Troubleshooting
Problem: Desktop doesn't pop window
Check:
- Extension enabled in Genesys Workspace?
- Flow sets interaction attributes?
- Desktop JavaScript can access attributes?
- Browser allows popups?
- Salesforce URL correct?
Debug:
// Add logging to desktop extension
genesysClient.on('interaction.incoming', (interaction) => {
console.log('Attributes:', interaction.attributes);
console.log('Contact ID:', interaction.attributes?.contact_id);
});
Problem: Lookup returns "Contact not found" for valid phone
Check:
- Phone in Salesforce exactly matches flow phone?
- Phone format consistent (E.164, local, international)?
- Apex query correct?
Debug:
// Test in Salesforce Developer Console
List<Contact> contacts = [
SELECT Id FROM Contact
WHERE Phone = '+15551234567'
];
System.debug(contacts.size() + ' contacts found');
Problem: Performance is slow
Check:
- Data Action timeout too long?
- Salesforce API slow?
- Network latency high?
Optimize:
- Set timeout to 3 seconds (not 10)
- Add Salesforce index on Phone field
- Implement caching
- Use webhook instead of API call
Production Deployment Checklist
- Salesforce Apex endpoint created & tested
- Data Action configured in Genesys
- Architect flow configured & tested
- Desktop extension installed & enabled
- Error handling for timeouts
- Fallback for not-found contacts
- Field mapping verified
- Performance acceptable (<3 sec)
- Monitoring & alerting set up
- Staff trained on screen pop behavior
Related Topics
- Chapter 11: API Endpoints Reference (Salesforce API)
- Chapter 11: Error Handling & Retry Strategy
- Chapter 5: Data Actions (in Architect flows)
- Chapter 12: Contact Sync from Salesforce
No Comments