How to Stop Routing Chats to Agents Who Are Already on a Phone Call in UIKit
A blended CSR handles both voice and messaging from the same desktop. The two channels are routed by two different mechanisms, and neither one knows what the other is doing. The result is familiar to anyone who has run a blended contact center on Pega Customer Service: an agent answers an inbound phone call, and thirty seconds later a new chat lands in their queue.
The agent now has two bad options. Ignore the chat and let it age until it reassigns, or split attention across a live call and a live conversation. Most sites solve this with a manual toggle and a training slide telling agents to remember to flip it. That works until it is busy, which is exactly when it matters.
This article covers the supported extension pattern that automates it. When the CSR answers a call, Pega sets their messaging presence to Temporarily Unavailable so no new chats are routed to them. When the call ends, presence returns to Available. Any chat already in progress is left completely alone.
Applies to: Pega Customer Service 24.1.x and later | UIKit Interaction Portal | Pega Call + Pega Chat / Digital Messaging on the same desktop
This is a small, low-risk build, but it is still a build. You are overriding two out-of-the-box rules, and the step numbers are version-specific. Read section 2 before you decide how far to take it.
1. How it works
Every presence transition needs two actions, not one:
- Set the presence state. Flip the agent’s messaging presence (available / temporarily unavailable) on the agent presence record.
- Update the chat status on the UI. Publish a notification so the chat icon in the agent desktop actually reflects the new state.
Skipping the second action is the single most common mistake here. Routing behaves correctly, the agent stops receiving chats, and the icon in their desktop keeps saying Available — so the agent files a bug against something that is working.
The reference implementation already ships
You do not have to invent this. Pega already does exactly this for Click-to-call: when a CSR initiates an outbound call, messaging is set to Temporarily Unavailable, and when the call ends it is set back to Available.
The activity is czUpdateCallEventsWrapper. Open it before you start. Everything below is the same presence-setting and publish sequence, relocated to the inbound call answered and call ended extension points.
Copy the parameter expressions out of that activity rather than retyping them from a screenshot. Two of them are long data page references and a typo in either one fails quietly.
2. One design decision, made up front: keep it one-way
Phone state drives chat availability. Chat state does not drive phone availability.
That asymmetry is deliberate. Calls and chats are routed by separate mechanisms, and making the control bidirectional introduces deadlock conditions that are genuinely hard to detect — an agent who is unavailable for calls because of a chat, and unavailable for chats because of a call, with nothing to break the tie. Diagnosing that in production is not a good afternoon.
If you truly need a symmetric blended experience, treat it as a separate design effort with its own capacity model. Do not bolt it onto this pattern.
3. Prerequisites
- Pega Customer Service UIKit portal. (This pattern targets the UIKit Interaction Portal. If you are on the Constellation Interaction Portal, the extension points differ.)
- Pega Call and Pega Chat / Digital Messaging configured for the same CSR desktop.
- The ability to override the
SetPartyNamesdata transform and theDisconnectedactivity in your own application ruleset. - Familiarity with the agent presence data page
D_AgentPresenceInfoState.
There are two extension points to configure. Configure both — one on its own leaves agents stuck in whichever state they last entered.
4. Part A — Call answered: set the CSR to Temporarily Unavailable
Rule to extend: the SetPartyNames data transform.
4.1 Step 4 — Set the presence parameters
Add a Property-Set step described as “Property set for the mid chat call start event”, with these parameters:
| Property | Value |
|---|---|
Param.ChatStatus |
"TempUnavailable" |
Param.Availability |
false |
Param.ActionType |
"MMTU" |
Param.TemporaryUnavailableReason |
"Outbound Call Initiated" |
Param.Message |
@Utilities.getLocalizedText("MidChatCallStartNtfn",".pyCaption",tools) |
Param.OperatorID |
pxRequestor.pxUserIdentifier |
Param.MidChatCallIds |
@pxReplaceAllViaRegex(D_AgentPresenceInfoState[OperatorID:Param.OperatorID,QueueID:""].Cus… |
Param.SkipNotification |
@equalsIgnoreCase(D_AgentPresenceInfoState[OperatorID:Param.OperatorID,QueueID:""].Custom… |
The last two values are truncated above and in the screenshot. Copy them from czUpdateCallEventsWrapper rather than reconstructing them.
One cosmetic note: "Outbound Call Initiated" is inherited straight from the Click-to-call implementation and is inaccurate on an inbound call. It is a reason string, so nothing breaks, but it will show up in reporting and confuse whoever reads it in six months. Rename it to something honest like "Inbound Call Answered" if your reporting surfaces it.
4.2 Steps 5–7 — Apply the chat status and presence data transforms
| Step | Method | Page | Data transform | PassParameterPage |
|---|---|---|---|---|
| 5 | Apply-DataTransform | CPMPortal |
UpdateTemporaryUnavailableChatStatus |
unchecked |
| 6 | Apply-DataTransform | CPMPortal |
SetAvailability |
checked |
| 7 | Apply-DataTransform | — | czUpdateAgentPresence |
checked |
Then set the jump on step 7. Enable Conditions after this action, and configure a single condition:
- When =
Always - if true =
Jump to Later Step - true param =
Publish
That jump is the whole mechanism for getting the change onto the agent’s screen. Without it, you have completed action one and skipped action two.
Figure 1.
SetPartyNames, steps 4–7 setting Temporarily Unavailable presence, with the step 7 jump condition targeting Publish.
4.3 Step 14 — Publish the change to the UI
The jump lands on the Publish step, which calls PublishCSRNotificationDetails against the CSRNotificationPage to push the status change to the CSR desktop.
Confirm Pass current parameter page is checked. The values that matter are:
| Name | Value |
|---|---|
Message |
Param.Message |
OperatorID |
Param.OperatorID |
Figure 2. Step 14. PublishCSRNotificationDetails updates the chat icon on the agent desktop.
5. Part B — Call ended: set the CSR back to Available
Rule to extend: the Disconnected activity.
5.1 Step 8 — Set the presence parameters
Add a Property-Set step described as “Property set for the mid chat call end event”:
| Property | Value |
|---|---|
Param.Availability |
true |
Param.ActionType |
"MMA" |
Param.TemporaryUnavailableReason |
"Outbound Call Ended" |
Param.Message |
@Utilities.getLocalizedText("MidChatCallEndNtfn",".pyCaption",tools) |
Param.OperatorID |
pxRequestor.pxUserIdentifier |
Param.MidChatCallIds |
D_AgentPresenceInfoState[OperatorID:Param.OperatorID,QueueID:""].CustomAttributes.czMidCha… |
Param.SkipNotification |
@equalsIgnoreCase(D_AgentPresenceInfoState[OperatorID:Param.OperatorID,QueueID:""].Custom… |
Note there is no Param.ChatStatus on this side. The UpdateAvailableChatStatus transform in step 11 handles it.
5.2 Steps 9–13 — Rebuild the chat list, then apply the transforms
| Step | Method | Page | Detail |
|---|---|---|---|
| 9 | Property-Set | — | Build the CurrentChatIDs page from the agent presence record |
| 10 | (loop) | CurrentChatIDs.pxResults |
Loop over the results |
| 11 | Apply-DataTransform | CPMPortal |
UpdateAvailableChatStatus, PassParameterPage unchecked |
| 12 | Apply-DataTransform | CPMPortal |
SetAvailability, PassParameterPage checked |
| 13 | Apply-DataTransform | — | czUpdateAgentPresence, PassParameterPage checked |
Set the jump on step 13 exactly as you did on step 7: When = Always, if true = Jump to Later Step, true param = Publish.
Figure 3. Disconnected, steps 8–13 restoring Available presence, with the step 13 jump condition targeting Publish.
5.3 Step 14 — Publish
Same destination as Part A: the Publish step calling PublishCSRNotificationDetails against CSRNotificationPage, with Pass current parameter page checked. See Figure 2 — the configuration is identical.
6. Quick reference
| Event | Rule | Presence steps | Then |
|---|---|---|---|
| Call answered | SetPartyNames data transform |
4–7 | Jump to Publish (step 14) |
| Call ended | Disconnected activity |
8–13 | Jump to Publish (step 14) |
Reference implementation to copy from: czUpdateCallEventsWrapper (Click-to-call).
7. Validate the configuration
Work through this in order. Each step isolates one thing.
- Log a CSR into both Pega Call and Pega Chat on the same desktop.
- Answer an inbound phone call. Confirm the chat icon flips to Temporarily Unavailable, and that no new chats are routed to the CSR.
- Confirm a chat that was already in progress is unaffected and continues normally. This is the one people forget to test, and it is the one that matters most to agents.
- End the call. Confirm the chat icon returns to Available and new chats are offered again.
- Repeat with a call that is transferred rather than ended cleanly, and with a dropped call. Confirm the agent does not get stranded in Temporarily Unavailable.
If routing behaves but the icon does not move, your jump to Publish is not firing. If the icon moves but chats keep arriving, check PassParameterPage on steps 6, 7, 12, and 13.
8. Notes and caveats
- One-way by design. This controls chat from phone state only. It does not block incoming calls based on chat state. See section 2 for why.
- Active chats are preserved. The CSR is removed from eligibility for new chats. Existing conversations are never ended.
- Extension points are version-specific. These overrides target
SetPartyNamesandDisconnectedas they exist in CS 24.1.x. Step numbers shift between releases. Re-verify the step structure after every platform upgrade, and keep the “jump to Publish” intent in your ruleset notes so the next person understands what the jump was for. - UIKit specific. If your agents are on the Constellation Interaction Portal, the presence extension points are different. Do not assume this transfers.
- Watch the reason strings.
"Outbound Call Initiated"and"Outbound Call Ended"are inherited from Click-to-call. Rename them if they reach a report.
If you have implemented two-way blended presence control successfully, or found a cleaner extension point on Constellation, I would like to hear about it — reply below.


