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:


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 CloudIntegrationsCustom AppsDesktop 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
Email 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:

Solutions:

  1. Add Index in Salesforce

    -- Make phone lookups fast
    CREATE INDEX idx_contact_phone 
    ON Contact(Phone, MobilePhone);
    
  2. 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;
      }
    }
    
  3. Use webhook instead of polling

    • Salesforce creates contact → webhook updates Genesys
    • (More advanced, requires webhook setup)

Testing Screen Pop

Manual Test

  1. Configure test flow in Architect
  2. Set up desktop extension locally
  3. Make test call to your Genesys DID
  4. 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:

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:

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:

Optimize:


Production Deployment Checklist



Revision #1
Created 15 March 2026 00:44:40 by Cesar Gzz
Updated 15 March 2026 00:44:52 by Cesar Gzz