Application scoping for Connect Customer applications
Every application built with the Connect Customer SDK runs with a contact scope. The contact scope determines whether the agent receives a separate instance of your application for each contact that they handle, or a single instance that serves all of them. You choose the scope when you design and register your application.
We recommend that you design your application to handle a single contact and register
it with the Per contact scope. AppManager creates a
separate instance of your application for each contact that the agent handles, provides
that contact's contactId to the instance at startup, and destroys the
instance when the contact ends. Your application does not track the agent's other
contacts, determine which contact the agent is working on, or change its content when
the agent moves between contacts. AppManager handles this behavior. When the agent switches contacts, AppManager displays the instance
for the newly selected contact and hides the others. A hidden instance retains its state
and is not reloaded or reinitialized.
Register the Cross contacts scope only when your application's content is session-level rather than contact-level, such as a notes application that an agent uses to record information across all of the contacts that they handle during a shift.
Important
If your application displays contact-specific information but is registered with the Cross contacts scope, a single instance is shared across all of the agent's concurrent contacts. That instance receives contact events for every one of those contacts, and your application must determine which contact the content on screen reflects. This can result in data for one contact being displayed while the agent is working on another.
Your application does not receive an event when the agent switches between contacts. If your application is contact-specific, register it with the Per contact scope rather than tracking the active contact in your application.
Contact scoping works the same way in the Connect Customer agent workspace and in a custom agent application that you build with Connect Customer Streams.
Choose a contact scope
Use the following table to decide which contact scope to register your application with.
| If your application | Register it with | What AppManager does |
|---|---|---|
Displays, collects, or modifies information that belongs to a
single contact, such as a customer record looked up from contact
attributes, a wrap-up form, or the order being discussed on the
call. Requires a contactId, or calls
ContactClient request operations. Displays different
content depending on which contact the agent is working on. |
Per contact
|
Creates a separate instance for each contact. Each instance is bound to one contact for its entire lifetime, can access data for that contact only, and is destroyed when that contact ends. |
| Presents the same session-level content regardless of which contact the agent is handling, and holds state that must outlive any individual contact, such as a notes application that spans a shift. |
Cross contacts
|
Creates a single instance that persists across contacts and is not destroyed when contacts end. The instance receives contact events for every contact that the agent is handling. |
Note
Registering your application with the Per
contact scope does not limit its availability to times when the
agent is handling a contact. Agents open applications when they choose,
including when they have no active contact, and a custom agent application can
also launch a per-contact application with the idle scope. In both
cases the instance runs without being bound to a contact. See Handle your scope at startup.
Register your application with a contact scope
You set the contact scope when your application is registered as an integration
in the Connect Customer console. It is the Contact scope field on the
Add integration page, and its value is a property of the
application, exposed to the Connect Customer SDK as contactHandling.scope. For
the procedure, see Integrate third-party applications
in the agent workspace in the Connect Customer Administrator
Guide.
You can change the contact scope of an existing integration at any time. The change takes effect the next time an agent signs in.
The contact scope does not grant your application access to contact data. If your
application subscribes to contact events or calls ContactClient
request operations, grant the corresponding permissions when you register the
integration. For more information, see Events and requests in Connect Customer agent workspace.
To register an application with a localhost access URL while you develop it, see Test your application for Connect Customer agent workspace locally.
Handle your scope at startup
The following example is for an application registered with the Per contact scope. A per-contact instance learns which
contact it belongs to from the scope on its create event, and that value does not
change for the life of the instance. Read the scope in onCreate rather
than assuming a contact is present, because an agent can open your application
while they are not handling a contact.
import { AmazonConnectApp, AppCreateEvent } from "@amazon-connect/app"; import { ContactClient } from "@amazon-connect/contact"; const { provider } = AmazonConnectApp.init({ onCreate: async (event: AppCreateEvent) => { const { scope } = event.context; // This application is registered with the Per contact scope, so the scope is // "contact" when the agent has an active contact and "idle" when they do not. if (scope?.type !== "contact") { renderEmptyState(); return; } // This instance handles this contact only, for its entire lifetime. const { contactId } = scope; const contactClient = new ContactClient({ provider }); const attributes = await contactClient.getAttributes(contactId, "*"); renderContactView(contactId, attributes); contactClient.onConnected(() => refreshContactView(contactId)); }, onDestroy: async () => { // The contact that this instance was created for has ended. }, });
An application registered with the Per contact scope starts in one of two states.
-
{ type: "contact", contactId }– The instance is bound to that contact, can access data for that contact only, and is destroyed when the contact ends. Read thecontactIdonce and use it for the lifetime of the instance. -
{ type: "idle" }– The agent opened your application while they were not handling a contact. The instance cannot access contact data while it holds this scope. Contact events are not delivered to it, andContactClientrequest operations fail authorization, including operations that do not identify a specific contact, such aslistContacts. Render an empty state. This is expected behavior. You do not need to register a second application to handle it.
Pass the contactId to the ContactClient request
operations that require it, such as getAttributes and
accept. For event subscriptions such as onConnected, the
contactId parameter is optional: if you omit it, the instance receives
events for the contact that it is scoped to. For more information, see Integrate application with Connect Customer agent workspace contact data.
Note
If your application shows contact-specific content but is registered with the
Cross contacts scope, none of the preceding
behavior applies. The instance receives no scope value, a single
instance is shared across all of the agent's contacts and receives contact
events for all of them, and your application must determine which contact its
content belongs to. See Choose a contact scope.
Design considerations for per-contact applications
A per-contact application can run more than once at the same time, and an instance can be destroyed at any time. Consider the following.
-
Several instances can run at once. Do not assume that only one instance of your application is running in the browser. Each instance runs in its own frame, with its own document and JavaScript state. If an agent opens the agent application in a second browser tab, a second instance of your application runs in that tab.
-
Key shared resources by contact. Instances share only what lies outside their frames, such as browser storage. Key any such resource by
contactIdso that one instance does not overwrite the state of another. -
An instance can start with no contact. Handle the
idlescope, for example by rendering an empty state, rather than assuming that a contact is present at creation. An instance that is not bound to a contact is not destroyed when contacts end: it persists for the lifetime of the page session rather than the agent's sign-in. -
Clean up promptly on destroy. When the contact ends, AppManager invokes your
onDestroycallback and waits five seconds for it to report completion. After that the instance is destroyed regardless, and incomplete work is lost. Your application is not displayed while the callback runs, so it cannot prompt the agent to confirm anything. Save data that must persist after the contact ends as it changes, rather than only in theonDestroycallback.
Launch an application with an explicit scope
The agent application that hosts your application launches it with an explicit scope. Your
application cannot set its own scope. The host passes a scope in
AppLaunchOptions.scope when it calls launchApp, and that
value takes precedence over the scope that you registered. For this reason, read the
scope at startup rather than assuming it. The following table describes the scope your application runs with
for each combination of registered scope and launch-time scope. An
active contact exists whenever the agent is handling one
or more contacts.
| Registration-time scope | Launch-time scope | Resulting behavior |
|---|---|---|
| Per contact |
contact
|
AppManager creates one instance per contact and destroys the instance when the contact ends. |
idle
|
The instance is available while the agent is idle and is not destroyed when contacts end. It cannot access contact data while it holds this scope. | |
| Not specified | Behaves the same as contact if an active
contact exists at launch, and the same as idle if
the agent is idle. The scope of the launching application does
not apply. |
|
| Cross contacts | Not specified, launched at the top level |
The instance persists across contacts and is destroyed
only when the page session ends or the agent application
calls This is the configuration that matches the publisher's intent for a cross-contact application. |
| Not specified, launched from within a scoped application | The instance inherits the scope of the nearest application above it in the launch chain. Launched from a contact-scoped application, it is bound to that contact and is destroyed when the contact ends. It runs without a scope only when no application in the chain has one. | |
idle
|
The instance persists across contacts and is destroyed only
when the page session ends or the agent application calls
destroy(), but it cannot access contact data while
it holds this scope. Omit the scope value instead
if your application needs contact data. |
|
contact
|
The instance can access data for the associated contact only, and AppManager destroys it when that contact ends. This prevents the application from persisting across contacts as the publisher intends. |
Note
From within an application that already has a scope, a launch that
requests a different scope fails with the invalidScopeProvided
error. A nested launch can request only the scope of the launching
application, or no scope value.
If you are building a custom agent application, or if your application launches other applications, see Launch-time scope for how to pass a scope, and Launch an application with an explicit scope for code examples.