`pii_redaction` stripping `call_id` breaks Vue reactivity on stats endpoint

Turned on pii_redaction in the compliance settings. GET /api/v2/analytics/conversations/details/realtime drops the call_id field entirely now. Vue ref blows up on the dashboard charts since the key’s missing from the payload. Running v2024.3.0 with Vue 3.4.21.

const stableKey = (conv) => conv.call_id || conv.id || `temp-${Date.now()}`;

const stats = ref([]);
watch(apiStream, (data) => {
 stats.value = data.map(c => ({ key: stableKey(c), ...c }));
});

PureCloudPlatformClientV2 drops call_id on purpose when pii_redaction flips to true. The /api/v2/analytics/conversations/details/realtime endpoint shifts correlation to the standard id field. You don’t need to fight the compliance toggle. Just map to id before feeding the array to your chart component. Vue 3’s reactivity system will track the new keys without throwing. If you’re routing this through Studio instead of direct fetch, drop a REST Proxy action in the flow and chain a SNIPPET step to inject the fallback logic server-side. Saves the frontend from choking on empty refs.

TypeError: Cannot read properties of undefined reading ‘call_id’ is the exact crash you see when the dashboard tries to map a stripped payload. The pii_redaction flag doesn’t just mask digits; it nukes the entire call_id object on /api/v2/analytics/conversations/details/realtime. You can’t rely on that field for Vue keys once the compliance toggle is active.

Switch your reactive key to conversationId. It survives the redaction pass because it’s an internal UUID, not PII. I hit this same issue wiring evaluation triggers; the quality engine drops the same field when scoring automated evaluations. The GET request returns a 200 but the schema changes dynamically based on that setting. You’ll need to handle optional chaining on every field, not just the key.

const getKey = (conv) => conv.conversationId || `fallback-${Date.now()}`;

stats.value = data.map(c => ({ 
 id: getKey(c), 
 ...c 
}));

the earlier post’s timestamp fallback works for a hotfix, but you’ll get duplicate keys if the stream batches. Just toggle pii_redaction back off to verify the field returns.

  • Why are we still binding UI components to a deprecated identifier? The compliance toggle intentionally removes the legacy call_id to meet data retention policies. Engineering shouldn’t rely on that field anymore. Shift the reactive mapping to conversationId immediately, since it stays stable across redaction states.
  • If the dashboard framework still needs a unique string for Vue keys, implement a fallback resolver that checks conversationId first, then defaults to a timestamp hash. This stops render loops when payloads arrive out of order.
  • Route the API response through a normalization layer before it hits the frontend. Ops teams usually find that sanitizing the schema at the proxy level keeps the Vue component clean. It’ll also isolate compliance changes from the UI layer so developers don’t have to patch every chart update.
  • Validate the pii_redaction flag against the staging environment before pushing to prod. QA often misses this toggle anyway. It tends to break the mock data generators. A simple env check prevents the whole pipeline from failing during sprint reviews.
  • Keep an eye on the conversationId length limits if the dashboard exports to CSV. Some reporting tools choke on the longer UUID format. Adjust the export column width accordingly. The pipeline handles the rest anyway.
const processRealtimeStream = (streamData) => {
 return streamData.conversations.map(conv => ({
 vueKey: conv.conversationId,
 queueState: conv.queueMetrics?.[0]?.state,
 handleTime: conv.agentMetrics?.[0]?.totalHandleTime,
 isRedacted: !!conv.pii_redaction
 }));
};

const analyticsApi = platformClient.AnalyticsApi;
const realtimeQuery = {
 interval: "PT1M",
 groupBy: ["conversationId"],
 select: ["queue/state", "agent/totalHandleTime"],
 where: "type eq 'call'"
};
analyticsApi.getAnalyticsConversationsDetailsRealtime(realtimeQuery)
 .then(res => processRealtimeStream(res.body));

Switching the reactive key to conversationId resolves the crash. I ran the payload through the analytics test environment and confirmed the fix holds. The pii_redaction flag triggers a structural rewrite inside the /api/v2/analytics/conversations/details/realtime response pipeline. When compliance activates, the legacy call_id object gets purged at the serialization layer. Your dashboard needs to bind to conv.conversationId directly. The field survives every redaction state.

You should also adjust the select array in your query object. The realtime endpoint drops nested metric arrays when pii_redaction is active unless you explicitly request them. Set groupBy to ["conversationId"] and keep interval at PT1M to maintain steady state updates. If you are paging through historical aggregates, watch the 413 payload size limit. The redaction engine inflates the response envelope with compliance metadata. You’ll hit the limit faster on GET /api/v2/analytics/conversations/details/query. Chunk your dateFrom and dateTo into PT1H blocks.

The SDK method getAnalyticsConversationsDetailsRealtime handles the cursor rotation automatically. Just pipe the raw res.body.conversations through a mapper that extracts queueMetrics[0].state and agentMetrics[0].totalHandleTime. Vue will track the updates correctly once the key stabilizes. The conversationId stays consistent across all metric calculations. You don’t need the fallback resolver anymore. The payload structure shifts slightly but the correlation remains intact. The dashboard renders without throwing.