Client_app_sdk scriptData subscription dropping events during Architect flow handoff

what’s the standard way to keep the scriptData$ observable alive when the Architect flow triggers a transfer action? the iframe postMessage listener drops the payload at step 47, throwing a 400 Bad Request on GET /api/v2/analytics/conversations/details/query. RxJS completes the stream early because the onLeave lifecycle hook fires before the desktop container processes the custom attributes.

this.gcApi.service('scriptData').subscribe({
 next: (data) => console.log('payload', data),
 error: (err) => console.error('stream cut', err)
});

websocket disconnects right at the handoff, looks like SDK v2.8.1 expects a manual keep-alive ping but the docs don’t mention it.

i’ve run into this exact issue when pushing custom attributes through the web widget during a transfer. the problem isn’t usually the rxjs stream dying, it’s that the onLeave hook in the desktop client fires before the architect flow has finished persisting the script data to the interaction context. you’re seeing that 400 because the query runs against an interaction ID that hasn’t fully updated its metadata yet.

what i do is add a small debounce or retry mechanism on the client side, but more importantly, ensure the architect flow explicitly waits for the script data to be set before triggering the transfer. in architect, add a “Set Interaction Attributes” step right before the transfer. make sure you’re using the correct attribute path. for script data, it’s usually something like custom.scriptData.value.

on the sdk side, don’t rely solely on the scriptData$ observable for critical state. instead, poll the interaction details endpoint with a short interval until the custom attribute appears. here’s a quick snippet using the platformClient to check if the data is ready:

import { Interaction, PlatformClient } from '@genesyscloud/purecloud-platform-client-v2';

async function waitForScriptData(interactionId: string, maxRetries = 5) {
 let retries = 0;
 while (retries < maxRetries) {
 const interaction = await PlatformClient.Interactions.getInteractionDetails(interactionId);
 if (interaction.customAttributes?.scriptData) {
 return interaction.customAttributes.scriptData;
 }
 await new Promise(resolve => setTimeout(resolve, 1000)); // wait 1s
 retries++;
 }
 throw new Error('Script data not found within timeout');
}

this forces the client to wait until the backend actually has the data. also, check your oauth scopes. if you’re fetching interaction details, you need interaction:view and routing:interaction:view. missing these will cause silent failures or 403s that look like 400s depending on how the sdk handles the error. make sure your devops scripts also have these scopes attached to the service account.

The race condition described above is spot on. The desktop client tears down the WebSocket before the edge finishes syncing the interaction context. Since the transfer action triggers an immediate SIP re-INVITE or REFER depending on the trunk config, the local state gets wiped out.

Try intercepting the onLeave event and forcing a manual sync. You can’t rely on the automatic RxJS stream here because the underlying connection drops. A simple delay helps, but it’s not solid. Instead, push the script data to a temporary storage object or send a small HTTP POST to a custom webhook before the leave hook executes. This ensures the data lands in the interaction context before the query runs.

Also, check if your SBC is stripping custom headers. If you’re using BYOC trunks, some AudioCodes models drop SDP attributes that don’t match the standard RFC 3261 profile. Ensure your SIP traces show the full payload arriving at the edge. If the headers are missing there, the web SDK never sees them.