From 194e1044a0f737ee06e0515bc9b480b863c7d3b1 Mon Sep 17 00:00:00 2001 From: Roko AI Agent Date: Wed, 29 Jul 2026 13:01:09 +0000 Subject: [PATCH 01/12] docs: add Amazon Connect Customer Profiles push notifications (backend + client) --- src/directory/directory.mjs | 35 ++++ .../author-message-templates/index.mdx | 81 ++++++++ .../existing-resources/index.mdx | 58 ++++++ .../add-aws-services/notifications/index.mdx | 77 ++++++++ .../set-up-notifications/index.mdx | 184 ++++++++++++++++++ .../guest-and-authenticated-users/index.mdx | 98 ++++++++++ .../customer-profiles/identify-user/index.mdx | 108 ++++++++++ .../customer-profiles/index.mdx | 129 ++++++++++++ .../register-device/index.mdx | 134 +++++++++++++ .../customer-profiles/remove-device/index.mdx | 101 ++++++++++ 10 files changed, 1005 insertions(+) create mode 100644 src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx create mode 100644 src/pages/[platform]/build-a-backend/add-aws-services/notifications/existing-resources/index.mdx create mode 100644 src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx create mode 100644 src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx create mode 100644 src/pages/[platform]/frontend/push-notifications/customer-profiles/guest-and-authenticated-users/index.mdx create mode 100644 src/pages/[platform]/frontend/push-notifications/customer-profiles/identify-user/index.mdx create mode 100644 src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx create mode 100644 src/pages/[platform]/frontend/push-notifications/customer-profiles/register-device/index.mdx create mode 100644 src/pages/[platform]/frontend/push-notifications/customer-profiles/remove-device/index.mdx diff --git a/src/directory/directory.mjs b/src/directory/directory.mjs index 8661100b5bb..e19f4b6b94c 100644 --- a/src/directory/directory.mjs +++ b/src/directory/directory.mjs @@ -512,6 +512,24 @@ export const directory = { } ] }, + { + path: 'src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx', + section: 'backend', + children: [ + { + path: 'src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx', + section: 'backend' + }, + { + path: 'src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx', + section: 'backend' + }, + { + path: 'src/pages/[platform]/build-a-backend/add-aws-services/notifications/existing-resources/index.mdx', + section: 'backend' + } + ] + }, { path: 'src/pages/[platform]/build-a-backend/add-aws-services/geo/index.mdx', section: 'backend', @@ -869,6 +887,23 @@ export const directory = { } ] }, + { + path: 'src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx', + children: [ + { + path: 'src/pages/[platform]/frontend/push-notifications/customer-profiles/identify-user/index.mdx' + }, + { + path: 'src/pages/[platform]/frontend/push-notifications/customer-profiles/register-device/index.mdx' + }, + { + path: 'src/pages/[platform]/frontend/push-notifications/customer-profiles/remove-device/index.mdx' + }, + { + path: 'src/pages/[platform]/frontend/push-notifications/customer-profiles/guest-and-authenticated-users/index.mdx' + } + ] + }, { path: 'src/pages/[platform]/frontend/geo/index.mdx', children: [ diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx new file mode 100644 index 00000000000..5a10945f9d3 --- /dev/null +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx @@ -0,0 +1,81 @@ +import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; + +export const meta = { + title: 'Author message templates', + description: + 'Create a push message template in Amazon Q in Connect and connect it to an Amazon Connect journey custom action.', + platforms: ['javascript', 'react-native'] +}; + +export const getStaticPaths = async () => { + return getCustomStaticPath(meta.platforms); +}; + +export function getStaticProps(context) { + return { + props: { + platform: context.params.platform, + meta + } + }; +} + +Amplify provisions the delivery path for your notifications, but not the message content. The text your users receive comes from a **push message template** that you author in [Amazon Q in Connect](https://docs.aws.amazon.com/connect/latest/adminguide/amazon-q-connect.html). + + + +This is a required post-deployment step that you complete in the AWS Management Console. Amplify does not create message templates, and a journey that has no matching template falls back to default placeholder copy. + + + +## How the template is matched + +When an Amazon Connect journey reaches a custom action block that targets your push-delivery Lambda function, the function resolves the template for that journey run: + +1. It reads the campaign and action identifiers from the journey event. The action identifier is the **name of the custom action block** in your journey. +2. It discovers the Amazon Q in Connect knowledge base associated with the Amazon Connect instance that the campaign belongs to. +3. It lists the message templates in that knowledge base and selects the one whose channel is `PUSH` and whose **name exactly matches the custom action block name**. +4. It renders the active version of that template once per target profile and sends the result to each of the profile's registered devices. + +The match is on the exact template name, so the following two values must be identical: + +- The name of the message template in Amazon Q in Connect. +- The name of the custom action block in your Amazon Connect journey. + +If no template matches, delivery still proceeds using default copy, and the function records a `template.noMatch` entry in its Amazon CloudWatch log group. Check that log group first when your users receive placeholder text. + +## Create the message template + +1. Open the [Amazon Connect console](https://console.aws.amazon.com/connect/) and sign in to your Amazon Connect instance. +2. Confirm that Amazon Q in Connect is enabled on the instance. The push-delivery function reads templates from the knowledge base that Amazon Q in Connect associates with the instance, so an instance without it cannot resolve templates. +3. Navigate to **Amazon Q** > **Message templates**, then choose **Create template**. +4. For the channel, choose **Push**. +5. For **Name**, enter the name you will give the custom action block in your journey. Record this value. +6. Enter the title and body for each platform you support. A push template holds separate content for Apple Push Notification service (APNs) and Firebase Cloud Messaging (FCM), which lets you tailor the copy per platform. Content you leave empty for a platform falls back to default copy for that platform. +7. Save the template. The push-delivery function renders the template's active version, so publish or activate the version you want your users to receive. + +## Personalize the message + +Templates support Handlebars variables that are filled in per profile at delivery time. Reference a profile field with the `Attributes` namespace: + +```handlebars +Hello {{Attributes.firstName}}, your order is on the way. +``` + +The values available to a template come from the target Customer Profile: + +- Top-level profile fields, such as `firstName`. +- Every entry in the profile's custom attributes, which your application sets with [`identifyUser`](/[platform]/frontend/push-notifications/customer-profiles/identify-user/). + +Custom attribute entries take precedence over top-level fields when both use the same key. A variable that a profile has no value for is left in the message as literal text, so use variables only for fields you populate consistently, and prefer copy that reads correctly when a value is absent. + +## Add the custom action to your journey + +1. In the Amazon Connect console, navigate to **Journeys** and open or create a journey. +2. Add a **custom action** block and point it at the push-delivery Lambda function that Amplify deployed. +3. Set the block name to the template name from step 5 above. The names must match exactly, including capitalization. +4. Publish the journey. + +## Next steps + +- [Push notifications](/[platform]/frontend/push-notifications/customer-profiles/) — register devices and send profile information from your application. diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/existing-resources/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/existing-resources/index.mdx new file mode 100644 index 00000000000..150c231a243 --- /dev/null +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/existing-resources/index.mdx @@ -0,0 +1,58 @@ +import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; + +export const meta = { + title: 'Use existing AWS resources', + description: + 'Attach your Amplify notifications resource to an Amazon Connect Customer Profiles domain that already exists.', + platforms: ['javascript', 'react-native'] +}; + +export const getStaticPaths = async () => { + return getCustomStaticPath(meta.platforms); +}; + +export function getStaticProps(context) { + return { + props: { + platform: context.params.platform, + meta + } + }; +} + +Pass `domainName` to `defineNotifications` to attach to an Amazon Connect Customer Profiles domain that already exists: + +```ts title="amplify/backend.ts" +import { defineBackend } from '@aws-amplify/backend'; +import { defineNotifications } from '@aws-amplify/backend-notifications'; +import { auth } from './auth/resource'; + +defineBackend({ + auth, + notifications: defineNotifications({ + domainName: 'amazon-connect-my-instance' + }) +}); +``` + +In this mode Amplify **attaches** to the domain rather than creating one. It registers the `AmplifyProfile` object type into the domain additively and does not create an Amazon Connect instance or a Customer Profiles domain. Object types that already exist on the domain are left unchanged, so you can attach to a domain that other workloads are using. + +## Requirements for the existing domain + +The domain must meet the following requirements: + +- **Same AWS account and Region as your Amplify project.** The construct references the domain by name, which resolves only within the account and Region your backend deploys to. +- **The name must begin with `amazon-connect-`.** This is a functional requirement, not a naming preference. The AWS-managed `AmazonConnectServiceLinkedRolePolicy` grants your Amazon Connect instance access to Customer Profiles only on domains matching `arn:aws:profile:*:*:domains/amazon-connect-*`. A domain named otherwise is unreachable by the instance, and the Amazon Connect console reports that it does not have permission to access Customer Profiles. Because the service-linked role and its managed policy cannot be edited, the domain name is the only way to satisfy the policy. +- **Customer Profiles enabled on your Amazon Connect instance.** The most common domain to attach to is the one Amazon Connect creates for you when you enable Customer Profiles, which is named `amazon-connect-`. + + + +To find the domain name, open the [Amazon Connect console](https://console.aws.amazon.com/connect/), select your instance, and choose **Customer Profiles**. + + + +## Properties that do not apply + +`instanceAlias` and `expirationDays` configure a domain that Amplify creates, so they cannot be combined with `domainName`. Set the data retention period on the existing domain in the Amazon Connect console instead. + +To have Amplify create the Amazon Connect instance and the domain for you, see [Set up notifications](/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/). diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx new file mode 100644 index 00000000000..4ab54b68bcf --- /dev/null +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx @@ -0,0 +1,77 @@ +import { getChildPageNodes } from '@/utils/getChildPageNodes'; +import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; + +export const meta = { + title: 'Notifications', + description: + 'Send push notifications to your users with a backend powered by Amazon Connect Customer Profiles.', + route: '/[platform]/build-a-backend/add-aws-services/notifications', + platforms: ['javascript', 'react-native'] +}; + +export const getStaticPaths = async () => { + return getCustomStaticPath(meta.platforms); +}; + +export function getStaticProps(context) { + const childPageNodes = getChildPageNodes(meta.route); + return { + props: { + platform: context.params.platform, + meta, + childPageNodes + } + }; +} + +Amplify push notifications are backed by [Amazon Connect Customer Profiles](https://docs.aws.amazon.com/connect/latest/adminguide/customer-profiles.html). A Customer Profile holds the profile information for one person, and the push devices that belong to them. You send a notification by targeting profiles from an [Amazon Connect journey](https://docs.aws.amazon.com/connect/latest/adminguide/journeys.html), which calls into your Amplify backend to deliver the message. + +Add the resource to your backend with the `defineNotifications` construct: + +```ts title="amplify/backend.ts" +import { defineBackend } from '@aws-amplify/backend'; +import { defineNotifications } from '@aws-amplify/backend-notifications'; +import { auth } from './auth/resource'; + +defineBackend({ + auth, + notifications: defineNotifications() +}); +``` + +## What gets deployed + +Deploying `defineNotifications` provisions the following resources: + +- An **`AmplifyProfile` Customer Profiles object type**, registered on your Customer Profiles domain. It is keyed on `principalId`, a searchable and unique field that holds the Amazon Cognito identity pool `identityId` of the caller. Your backend derives `principalId` from the signed request, so a client never sends it and cannot write to another person's profile. +- A **DynamoDB device store** that holds the registered push devices. Device records live in this table rather than in Customer Profiles. +- Three **HTTP API routes** — `identify-user`, `register-device`, and `remove-device` — authorized with AWS Identity and Access Management (IAM) and called with [Signature Version 4](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv.html) signed requests. A single least-privilege Lambda function serves all three routes. +- A **push-delivery Lambda function**, invoked as a custom action from an Amazon Connect journey. It looks up the target profile's devices and sends the message to each one. +- An **AWS End User Messaging application**, with the APNs and FCM channels you configure. + +Depending on the mode you choose, an Amazon Connect instance and a Customer Profiles domain are created for you, or an existing domain is used. See [Set up notifications](/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/) for both modes. + +## Review the generated configuration + +After a successful deployment, the invoke endpoint and region are written to the `notifications` section of `amplify_outputs.json`: + +```json title="amplify_outputs.json" +{ + "notifications": { + "amazon_connect": { + "endpoint": "https://abcdefghij.execute-api.us-east-1.amazonaws.com", + "aws_region": "us-east-1" + } + } +} +``` + +Your frontend reads these values when you pass `amplify_outputs.json` to `Amplify.configure()`. To call the notification APIs from your application, see [Push notifications](/[platform]/frontend/push-notifications/customer-profiles/). + + + +Message content is not provisioned by Amplify. After you deploy, author a push message template in Amazon Q in Connect and connect it to a journey. See [Author message templates](/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/). + + + + diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx new file mode 100644 index 00000000000..e671af92b38 --- /dev/null +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx @@ -0,0 +1,184 @@ +import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; + +export const meta = { + title: 'Set up notifications', + description: + 'Add push notifications to your Amplify backend with the defineNotifications construct, either by creating a new Amazon Connect instance or by attaching to an existing Customer Profiles domain.', + platforms: ['javascript', 'react-native'] +}; + +export const getStaticPaths = async () => { + return getCustomStaticPath(meta.platforms); +}; + +export function getStaticProps(context) { + return { + props: { + platform: context.params.platform, + meta + } + }; +} + +The `defineNotifications` construct adds an Amazon Connect Customer Profiles-backed push notification resource to your Amplify backend. + +## Prerequisites + +Before you begin, complete the following steps: + +1. Add authentication to your backend. The notification APIs are called with [Signature Version 4](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv.html) signed requests using Amazon Cognito identity pool credentials, so an `auth` resource is required. Both signed-in and guest users can call the APIs — see [Guest access](/[platform]/build-a-backend/auth/concepts/guest-access/). +2. Install the notifications package: + +```bash title="Terminal" showLineNumbers={false} +npm add @aws-amplify/backend-notifications +``` + +3. Gather the credentials for each push channel you want to enable: + + - **Apple Push Notification service (APNs)** — a token-based signing key (`.p8`), its key ID, your Apple team ID, and your application's bundle ID. + - **Firebase Cloud Messaging (FCM)** — the service account JSON for your Firebase project. + +4. Store the sensitive credentials as secrets. The signing key and the service account JSON are referenced with `secret()` rather than written into your backend code: + +```bash title="Terminal" showLineNumbers={false} +npx ampx sandbox secret set APNS_SIGNING_KEY +npx ampx sandbox secret set FCM_SERVICE_ACCOUNT_JSON +``` + +To learn more about secrets, see [Environment variables and secrets](/[platform]/build-a-backend/functions/environment-variables-and-secrets/). + +## Choose how the Customer Profiles domain is provisioned + +`defineNotifications` supports two modes. The mode is determined by whether you pass `domainName`. + + + + +Omit `domainName` to create everything from scratch. Amplify provisions a new Amazon Connect instance and a new Customer Profiles domain, then registers the `AmplifyProfile` object type into that domain. No pre-existing Amazon Connect setup is required. + +```ts title="amplify/backend.ts" +import { defineBackend } from '@aws-amplify/backend'; +import { defineNotifications } from '@aws-amplify/backend-notifications'; +import { auth } from './auth/resource'; + +defineBackend({ + auth, + notifications: defineNotifications() +}); +``` + +Two optional properties are available in this mode: + +- `instanceAlias` — the alias for the new Amazon Connect instance. Aliases are globally unique within an AWS Region. When you omit this property, Amplify generates a stable name for your Amplify project. +- `expirationDays` — how long Customer Profiles retains profile data in the new domain. + +```ts title="amplify/backend.ts" +notifications: defineNotifications({ + instanceAlias: 'my-app-notifications', + expirationDays: 90 +}); +``` + + + +The first deployment in this mode takes longer than a typical Amplify deployment because it provisions an Amazon Connect instance and a Customer Profiles domain. + + + + + + +Pass `domainName` to attach to a Customer Profiles domain that already exists. Amplify registers the `AmplifyProfile` object type into that domain additively, and does not create an Amazon Connect instance or a domain. + +```ts title="amplify/backend.ts" +import { defineBackend } from '@aws-amplify/backend'; +import { defineNotifications } from '@aws-amplify/backend-notifications'; +import { auth } from './auth/resource'; + +defineBackend({ + auth, + notifications: defineNotifications({ + domainName: 'amazon-connect-my-instance' + }) +}); +``` + +`instanceAlias` and `expirationDays` apply only when Amplify creates the domain, so they cannot be combined with `domainName`. + +For the requirements your existing domain must meet, see [Use existing resources](/[platform]/build-a-backend/add-aws-services/notifications/existing-resources/). + + + + +## Configure push channels + +Add `apns`, `fcm`, or both to enable the corresponding channel on the AWS End User Messaging application that Amplify creates. Channels are optional and independent — omit one to leave it unconfigured. + +```ts title="amplify/backend.ts" +import { defineBackend, secret } from '@aws-amplify/backend'; +import { defineNotifications } from '@aws-amplify/backend-notifications'; +import { auth } from './auth/resource'; + +defineBackend({ + auth, + notifications: defineNotifications({ + apns: { + tokenKey: secret('APNS_SIGNING_KEY'), + tokenKeyId: 'ABC123DEFG', + teamId: 'DEF456GHIJ', + bundleId: 'com.example.myapp' + }, + fcm: { + serviceJson: secret('FCM_SERVICE_ACCOUNT_JSON') + } + }) +}); +``` + +The `apns` properties are: + +| Property | Required | Description | +| --- | --- | --- | +| `tokenKey` | Yes | The contents of your APNs token signing key (`.p8`), supplied with `secret()`. | +| `tokenKeyId` | Yes | The ID of the signing key. | +| `teamId` | Yes | Your Apple developer team ID. | +| `bundleId` | Yes | The bundle ID of your application. | +| `sandbox` | No | Set to `true` to send through the APNs sandbox environment, which is used for development builds. Defaults to `false`. | + +The `fcm` property is: + +| Property | Required | Description | +| --- | --- | --- | +| `serviceJson` | Yes | The contents of your Firebase service account JSON, supplied with `secret()`. | + + + +Pass `tokenKey` and `serviceJson` with `secret()`. Do not paste the key material into `amplify/backend.ts` — it would be committed to your repository. + + + +## Deploy and review the outputs + +Deploy the resource to your personal cloud sandbox: + +```bash title="Terminal" showLineNumbers={false} +npx ampx sandbox +``` + +When the deployment finishes, the invoke endpoint and region are written to `amplify_outputs.json`: + +```json title="amplify_outputs.json" +{ + "notifications": { + "amazon_connect": { + "endpoint": "https://abcdefghij.execute-api.us-east-1.amazonaws.com", + "aws_region": "us-east-1" + } + } +} +``` + +## Next steps + +- [Author message templates](/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/) — create the push message content in Amazon Q in Connect. +- [Push notifications](/[platform]/frontend/push-notifications/customer-profiles/) — call the notification APIs from your application. diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/guest-and-authenticated-users/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/guest-and-authenticated-users/index.mdx new file mode 100644 index 00000000000..73efbe14143 --- /dev/null +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/guest-and-authenticated-users/index.mdx @@ -0,0 +1,98 @@ +import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; + +export const meta = { + title: 'Guest and authenticated users', + description: + 'How Amazon Connect Customer Profiles notifications work for guest and signed-in users, and how a device moves to the authenticated identity on sign-in.', + platforms: ['javascript', 'react-native'] +}; + +export const getStaticPaths = async () => { + return getCustomStaticPath(meta.platforms); +}; + +export function getStaticProps(context) { + return { + props: { + platform: context.params.platform, + meta + } + }; +} + +The Customer Profiles notification APIs work for guest users and signed-in users. Both are supported through the same mechanism, so your application does not need a separate code path for each. + +## How both identities are supported + +Every request to your notifications backend is signed with [Signature Version 4](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv.html) using credentials from your Amazon Cognito identity pool: + +- A **guest** user receives credentials from the identity pool's unauthenticated role. +- A **signed-in** user receives credentials from the identity pool's authenticated role. + +Both are signed identically, and your backend derives the profile identity, `principalId`, from the signer identity of the request. Because that identifier comes from the credentials rather than from your application, no identity field is sent by the client and no code change is needed to support guests. + +Guest access must be enabled on your `auth` resource for unauthenticated callers to receive credentials. See [Guest access](/[platform]/build-a-backend/auth/concepts/guest-access/). + + + +A guest identity is scoped to the installation, not to a person. Treat a guest profile as belonging to the device until a user signs in. + + + + + +## A device moves to the authenticated identity on sign-in + +A guest user's push token and a signed-in user's push token are the same value, because the native platform issues the token to the installation rather than to a user. Without any handling, a device registered as a guest would stay attached to the guest identity after the user signed in, and journeys targeting the authenticated profile would not reach it. + +The library handles this for you. After `initializePushNotifications` has been called, it listens for the sign-in event and re-registers the device, which moves the existing registration from the guest identity to the authenticated one. Because registration is an idempotent operation keyed on a device identifier that is stable for the installation, this updates the existing record rather than creating a second one. + +No application code is required for this to happen: + +```ts title="index.js" +import { Amplify } from 'aws-amplify'; +import { initializePushNotifications } from 'aws-amplify/push-notifications/customer-profiles'; +import outputs from './amplify_outputs.json'; + +Amplify.configure(outputs); +initializePushNotifications(); +``` + +Re-registration on sign-in is a best-effort operation. A failure is logged and does not interrupt sign-in, so a device may briefly remain on the guest identity if the request fails. The device is re-registered on the next sign-in. + +If no push token has been issued yet when a user signs in, there is nothing to move. The first registration then happens against the authenticated identity once the native platform issues the token. + + + +## Sign a user out + +Signing a user out does not de-register their device. Call `removeDevice` while the user is still signed in, because de-registration is signed with their credentials: + +```ts +import { signOut } from 'aws-amplify/auth'; +import { removeDevice } from 'aws-amplify/push-notifications/customer-profiles'; + +await removeDevice(); +await signOut(); +``` + +After `signOut` completes, subsequent calls are signed as a new guest identity. See [Remove a device](/[platform]/frontend/push-notifications/customer-profiles/remove-device/). + +## Profile information for guests + +`identifyUser` works for guest users, so you can store profile details before a user creates an account. Those details are written to the guest profile. + +A guest profile and an authenticated profile are separate profiles, because they have different `principalId` values. Profile information is not copied between them when a user signs in, so call `identifyUser` after sign-in to populate the authenticated profile with the details you hold: + +```ts +import { identifyUser } from 'aws-amplify/push-notifications/customer-profiles'; + +await identifyUser({ + userProfile: { + email: 'jane@example.com', + name: 'Jane Doe' + } +}); +``` + +See [Identify a user](/[platform]/frontend/push-notifications/customer-profiles/identify-user/). diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/identify-user/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/identify-user/index.mdx new file mode 100644 index 00000000000..d57b5469603 --- /dev/null +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/identify-user/index.mdx @@ -0,0 +1,108 @@ +import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; + +export const meta = { + title: 'Identify a user', + description: + 'Send profile information for the current user to Amazon Connect Customer Profiles with the identifyUser API.', + platforms: ['javascript', 'react-native'] +}; + +export const getStaticPaths = async () => { + return getCustomStaticPath(meta.platforms); +}; + +export function getStaticProps(context) { + return { + props: { + platform: context.params.platform, + meta + } + }; +} + +Use `identifyUser` to send profile information for the current user to Amazon Connect Customer Profiles. The values you send populate the Customer Profile that your Amazon Connect journeys target and personalize messages with. + +```ts +import { identifyUser } from 'aws-amplify/push-notifications/customer-profiles'; + +await identifyUser({ + userProfile: { + email: 'jane@example.com', + name: 'Jane Doe', + phone: '+15551234567', + location: { + city: 'Seattle', + country: 'US', + postalCode: '98101', + region: 'WA' + }, + customAttributes: { + plan: 'premium', + favoriteCategory: 'outdoors' + } + } +}); +``` + +Every field is optional, so send only the values your application has. Each call replaces the fields you provide on the profile. + +## User profile fields + +| Field | Type | Description | +| --- | --- | --- | +| `email` | `string` | The user's email address. | +| `name` | `string` | The user's name. | +| `phone` | `string` | The user's phone number. | +| `location` | `object` | The user's location. Accepts `city`, `country`, `postalCode`, and `region`, each a `string`. | +| `customAttributes` | `Record` | Additional key-value pairs to store on the profile. | + +Values are validated before the request is sent. Every string, along with each `customAttributes` key and value, must be 255 characters or fewer, and `customAttributes` values must be strings. A profile that violates these bounds throws a validation error. + + + +`principalId` is a reserved `customAttributes` key and is rejected. Your backend uses it to store the profile identity. + + + +## How the profile identity is resolved + +Your application does not send a user identifier. Requests are signed with Signature Version 4 using Amazon Cognito identity pool credentials, and your backend derives the `principalId` for the profile from the signer identity of the request. A caller therefore cannot write to another user's profile, and there is no identifier for your application to manage. + +Because the identity comes from the credentials, `identifyUser` works for both signed-in and guest users. See [Guest and authenticated users](/[platform]/frontend/push-notifications/customer-profiles/guest-and-authenticated-users/). + +## When to call identifyUser + +Call `identifyUser` when the profile information you hold changes, for example: + +- After a user signs in, to associate their profile details with their authenticated identity. +- After a user updates their contact details or preferences. + +`identifyUser` sends profile information only and performs no device work. To manage push devices, use [`registerDevice`](/[platform]/frontend/push-notifications/customer-profiles/register-device/) and [`removeDevice`](/[platform]/frontend/push-notifications/customer-profiles/remove-device/). + + + + + +`identifyUser` does not require `initializePushNotifications`. Its only prerequisites are a configured endpoint and identity pool credentials, so you can call it before push notifications are initialized. + + + + + +## Personalize messages with profile values + +Message templates reference profile values with the `Attributes` namespace, so a `customAttributes` entry named `favoriteCategory` is available to a template as `{{Attributes.favoriteCategory}}`. See [Author message templates](/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/). + +## Handle errors + +`identifyUser` returns a promise that rejects when validation fails or the endpoint returns an error, so handle failures where a rejected promise would otherwise go unobserved: + +```ts +import { identifyUser } from 'aws-amplify/push-notifications/customer-profiles'; + +try { + await identifyUser({ userProfile: { email: 'jane@example.com' } }); +} catch (error) { + console.error('Failed to identify user', error); +} +``` diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx new file mode 100644 index 00000000000..199953b509a --- /dev/null +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx @@ -0,0 +1,129 @@ +import { getChildPageNodes } from '@/utils/getChildPageNodes'; +import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; + +export const meta = { + title: 'Push notifications', + description: + 'Send profile information and register push devices with Amazon Connect Customer Profiles from your application.', + route: '/[platform]/frontend/push-notifications/customer-profiles', + platforms: ['javascript', 'react-native'] +}; + +export const getStaticPaths = async () => { + return getCustomStaticPath(meta.platforms); +}; + +export function getStaticProps(context) { + const childPageNodes = getChildPageNodes(meta.route); + return { + props: { + platform: context.params.platform, + meta, + childPageNodes + } + }; +} + +The Amazon Connect Customer Profiles APIs let your application send profile information for the current user and manage the push devices that belong to them. Requests are signed with [Signature Version 4](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv.html) using Amazon Cognito identity pool credentials, and your backend derives the profile identity from the signed request. + +These APIs are exported from the `aws-amplify/push-notifications/customer-profiles` sub-path. + + + +This page assumes you have already deployed a notifications resource. See [Set up notifications](/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/). + + + +## Platform support + +The device APIs interact with the native push notification system, so support varies by platform: + +| API | Web | React Native | +| --- | --- | --- | +| `identifyUser` | Supported | Supported | +| `initializePushNotifications` | Not supported | Supported | +| `registerDevice` | Not supported | Supported | +| `removeDevice` | Not supported | Supported | + + + + + +On web, `initializePushNotifications`, `registerDevice`, and `removeDevice` throw a `PlatformNotSupportedError`. Use [`identifyUser`](/[platform]/frontend/push-notifications/customer-profiles/identify-user/) to send profile information from a web application, and register devices from your React Native application. + + + + + +## Install the library + + + +```bash title="Terminal" showLineNumbers={false} +npm add aws-amplify +``` + + + + + +Push notifications require the native module in addition to `aws-amplify`: + +```bash title="Terminal" showLineNumbers={false} +npm add aws-amplify @aws-amplify/react-native @aws-amplify/rtn-push-notification @react-native-async-storage/async-storage react-native-get-random-values +``` + +Because push notifications interact with the native platform, you also need to link the native module and grant your application the permission to receive remote notifications: + +- On iOS, run `npx pod-install`, add the push notification capability to your target in Xcode, and forward the remote notification callbacks from your `AppDelegate` to `AmplifyPushNotification`. +- On Android, no additional integration steps are required beyond installing the packages above. + + + +## Configure Amplify + +Pass `amplify_outputs.json` to `Amplify.configure()`. The endpoint and Region that your backend deployed are read from the `notifications` section of that file. + + + +```ts title="src/main.ts" +import { Amplify } from 'aws-amplify'; +import outputs from '../amplify_outputs.json'; + +Amplify.configure(outputs); +``` + + + + + +Configure Amplify and initialize push notifications at your application's root entry point. Initializing early allows your application to process notifications that arrive while it is in a terminated state. + +```ts title="index.js" +import { AppRegistry } from 'react-native'; +import { Amplify } from 'aws-amplify'; +import { initializePushNotifications } from 'aws-amplify/push-notifications/customer-profiles'; +import outputs from './amplify_outputs.json'; + +import App from './App'; +import { name as appName } from './app.json'; + +Amplify.configure(outputs); +initializePushNotifications(); + +AppRegistry.registerComponent(appName, () => App); +``` + +`initializePushNotifications` sets up the native listeners the category depends on. Calling it more than once has no effect. Until it has been called, `registerDevice` and `removeDevice` throw a validation error. + +Once initialized, the library registers the device automatically the first time the native platform issues a push token, so most applications do not call `registerDevice` themselves. See [Register a device](/[platform]/frontend/push-notifications/customer-profiles/register-device/). + + + + + +Call `removeDevice` before signing a user out. De-registration is signed with the current user's credentials, so it cannot succeed after `signOut` has completed. See [Remove a device](/[platform]/frontend/push-notifications/customer-profiles/remove-device/). + + + + diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/register-device/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/register-device/index.mdx new file mode 100644 index 00000000000..742fe776154 --- /dev/null +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/register-device/index.mdx @@ -0,0 +1,134 @@ +import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; + +export const meta = { + title: 'Register a device', + description: + 'Register a push device with Amazon Connect Customer Profiles so that Amazon Connect journeys can deliver notifications to it.', + platforms: ['javascript', 'react-native'] +}; + +export const getStaticPaths = async () => { + return getCustomStaticPath(meta.platforms); +}; + +export function getStaticProps(context) { + return { + props: { + platform: context.params.platform, + meta + } + }; +} + +A device must be registered before an Amazon Connect journey can deliver a notification to it. Registering stores the device's push token against the current user's profile identity, so your backend knows where to send messages. + + + + + +`registerDevice` is supported on React Native only. On web it throws a `PlatformNotSupportedError`, because registration depends on a push token issued by the native platform. + + + + + + + +## Registration happens automatically + +In most applications you do not call `registerDevice` yourself. After you call `initializePushNotifications`, the library listens for the push token that the native platform issues and registers the device the first time a token arrives. + +```ts title="index.js" +import { Amplify } from 'aws-amplify'; +import { initializePushNotifications } from 'aws-amplify/push-notifications/customer-profiles'; +import outputs from './amplify_outputs.json'; + +Amplify.configure(outputs); +initializePushNotifications(); +``` + +The library also re-registers the device when a user signs in, which moves the existing registration from the guest identity to the authenticated one. See [Guest and authenticated users](/[platform]/frontend/push-notifications/customer-profiles/guest-and-authenticated-users/). + +A token is issued only after the user grants notification permission, so request permission during your onboarding flow: + +```ts +import { + getPermissionStatus, + requestPermissions +} from 'aws-amplify/push-notifications/customer-profiles'; + +const status = await getPermissionStatus(); + +if (status === 'shouldRequest') { + await requestPermissions(); +} else if (status === 'shouldExplainThenRequest') { + // Explain why your application sends notifications, then request permission. + await requestPermissions(); +} +``` + +`getPermissionStatus` resolves to `'granted'`, `'denied'`, `'shouldRequest'`, or `'shouldExplainThenRequest'`. `requestPermissions` resolves to a boolean indicating whether permission was granted. + +## Register a device manually + +Call `registerDevice` with a push token when you need to control registration yourself, for example to register only after a user opts in to notifications in your own settings screen. Obtain the token with `onTokenReceived`: + +```ts +import { + onTokenReceived, + registerDevice +} from 'aws-amplify/push-notifications/customer-profiles'; + +const listener = onTokenReceived(async (token) => { + await registerDevice({ token }); +}); +``` + +The `token` is the only value you provide. The library resolves the remaining device fields for you: + +| Field | Source | +| --- | --- | +| `deviceId` | A stable identifier the library generates and persists per installation. | +| `platform` | Derived from the operating system. | +| `channelType` | Derived from the operating system, which selects the APNs or FCM channel. | + +Registration is an idempotent operation keyed on `deviceId`, so calling `registerDevice` again with a new token updates the existing record rather than creating a second one. + +## The device belongs to the current identity + +The registered device is stored against the `principalId` that your backend derives from the signed request, so a device always belongs to the identity that registered it. Your application never sends a user identifier, and one user cannot register a device against another user's profile. + +Because the identity comes from Amazon Cognito identity pool credentials, registration works for guest users as well as signed-in users. + +## When to call registerDevice + +Call `registerDevice` in these situations: + +- After a user opts in to notifications, when you are managing registration manually rather than relying on automatic registration. +- After receiving a replacement token from `onTokenReceived`, if you are not relying on the automatic listener. + +You do not need to call `registerDevice` on every application start, or after a user signs in. The registration persists, and sign-in re-registration is handled for you. + +## Handle errors + +`registerDevice` rejects in the following cases: + +- **Push notifications are not initialized.** Call `initializePushNotifications` before registering a device. +- **No token is available.** Pass a token, or wait until `onTokenReceived` has fired. +- **The request failed.** The endpoint returned a non-success status, or the request could not complete. + +```ts +import { registerDevice } from 'aws-amplify/push-notifications/customer-profiles'; + +try { + await registerDevice({ token }); +} catch (error) { + console.error('Failed to register device', error); +} +``` + +## Next steps + +- [Remove a device](/[platform]/frontend/push-notifications/customer-profiles/remove-device/) — de-register a device before signing a user out. + + diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/remove-device/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/remove-device/index.mdx new file mode 100644 index 00000000000..a8f8031f35b --- /dev/null +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/remove-device/index.mdx @@ -0,0 +1,101 @@ +import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; + +export const meta = { + title: 'Remove a device', + description: + 'De-register a push device from Amazon Connect Customer Profiles, and why removal must happen before signing a user out.', + platforms: ['javascript', 'react-native'] +}; + +export const getStaticPaths = async () => { + return getCustomStaticPath(meta.platforms); +}; + +export function getStaticProps(context) { + return { + props: { + platform: context.params.platform, + meta + } + }; +} + +Use `removeDevice` to de-register the current device so that Amazon Connect journeys stop delivering notifications to it. + +```ts +import { removeDevice } from 'aws-amplify/push-notifications/customer-profiles'; + +await removeDevice(); +``` + +`removeDevice` takes no arguments. The library resolves the device identifier for you, and your backend permits removal only of a device that the calling identity owns. + + + +**Call `removeDevice` before `signOut`.** De-registration is signed with the current user's credentials, and your backend removes a device only when the calling identity owns it. After `signOut` completes those credentials are gone and the caller signs as a new guest identity, so a removal attempted at that point cannot de-register the signed-in user's device. Always await `removeDevice` first: + +```ts +import { signOut } from 'aws-amplify/auth'; +import { removeDevice } from 'aws-amplify/push-notifications/customer-profiles'; + +await removeDevice(); +await signOut(); +``` + +Reversing the order leaves the device registered against the signed-out user's profile, and a later journey can deliver their notifications to a device they no longer use. + + + + + + + +`removeDevice` is supported on React Native only. On web it throws a `PlatformNotSupportedError`. A web application that also ships a React Native application should perform device removal there. + + + + + +## Sign a user out safely + +Handle a failed removal deliberately rather than letting it block sign-out. The following pattern signs the user out even when de-registration fails, which avoids trapping a user in a signed-in state because of a network error: + +```ts +import { signOut } from 'aws-amplify/auth'; +import { removeDevice } from 'aws-amplify/push-notifications/customer-profiles'; + +const handleSignOut = async () => { + try { + await removeDevice(); + } catch (error) { + console.error('Failed to remove device before sign out', error); + } + + await signOut(); +}; +``` + +## When to call removeDevice + +Call `removeDevice` in these situations: + +- Before signing a user out, as described above. +- When a user turns off notifications in your application's settings. +- Before deleting a user's account. + + + +You do not need to call `removeDevice` when the push token is replaced. Registration is keyed on a device identifier that is stable for the installation, so registering with a new token updates the existing record. See [Register a device](/[platform]/frontend/push-notifications/customer-profiles/register-device/). + +## Register the device again + +The device identifier persists after removal, so a user who opts back in can be registered again with `registerDevice`. Removing a device does not reset the identifier or require your application to store one. + + + +## Handle errors + +`removeDevice` rejects in the following cases: + +- **Push notifications are not initialized.** Call `initializePushNotifications` before removing a device. +- **The request failed.** The endpoint returned a non-success status, or the request could not complete. From 84e555a2d08615a8b3d8a88e1ca21f4ffcfbb983 Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Wed, 29 Jul 2026 13:15:02 +0000 Subject: [PATCH 02/12] docs: correct device-storage model, expand framework visibility, and fix push template authoring for Connect Customer Profiles push --- .../author-message-templates/index.mdx | 75 ++++++++++++------- .../existing-resources/index.mdx | 2 +- .../add-aws-services/notifications/index.mdx | 4 +- .../set-up-notifications/index.mdx | 2 +- .../guest-and-authenticated-users/index.mdx | 2 +- .../customer-profiles/identify-user/index.mdx | 2 +- .../customer-profiles/index.mdx | 10 +-- .../register-device/index.mdx | 4 +- .../customer-profiles/remove-device/index.mdx | 4 +- 9 files changed, 65 insertions(+), 40 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx index 5a10945f9d3..5593c5edf09 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx @@ -3,8 +3,8 @@ import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; export const meta = { title: 'Author message templates', description: - 'Create a push message template in Amazon Q in Connect and connect it to an Amazon Connect journey custom action.', - platforms: ['javascript', 'react-native'] + 'Create a push message template with the Amazon Q in Connect API and connect it to an Amazon Connect journey custom action.', + platforms: ['javascript', 'angular', 'nextjs', 'react', 'vue', 'react-native'] }; export const getStaticPaths = async () => { @@ -20,11 +20,11 @@ export function getStaticProps(context) { }; } -Amplify provisions the delivery path for your notifications, but not the message content. The text your users receive comes from a **push message template** that you author in [Amazon Q in Connect](https://docs.aws.amazon.com/connect/latest/adminguide/amazon-q-connect.html). +Amplify provisions the delivery path for your notifications, but not the message content. The text your users receive comes from a **push message template** stored in an Amazon Q in Connect knowledge base. -This is a required post-deployment step that you complete in the AWS Management Console. Amplify does not create message templates, and a journey that has no matching template falls back to default placeholder copy. +**The Amazon Q in Connect console does not support authoring PUSH-channel message templates.** You create and publish push templates with the `qconnect` AWS CLI (or the underlying Amazon Q in Connect API), against the knowledge base that `defineNotifications` provisions. Amplify does not create the templates themselves, and a journey that has no matching template falls back to default placeholder copy. @@ -32,48 +32,73 @@ This is a required post-deployment step that you complete in the AWS Management When an Amazon Connect journey reaches a custom action block that targets your push-delivery Lambda function, the function resolves the template for that journey run: -1. It reads the campaign and action identifiers from the journey event. The action identifier is the **name of the custom action block** in your journey. -2. It discovers the Amazon Q in Connect knowledge base associated with the Amazon Connect instance that the campaign belongs to. -3. It lists the message templates in that knowledge base and selects the one whose channel is `PUSH` and whose **name exactly matches the custom action block name**. -4. It renders the active version of that template once per target profile and sends the result to each of the profile's registered devices. +1. It calls `connectcampaignsv2:DescribeCampaign` on the campaign ID from the event to get the Connect instance ID. +2. It calls `connect:ListIntegrationAssociations`, filtered to the `Q_MESSAGE_TEMPLATES` integration type, to get the knowledge base ID. +3. It calls `wisdom:ListMessageTemplates` on that knowledge base and selects the template whose `channelSubtype` is `PUSH` and whose **name equals the journey custom action block name** (the event's `ActionId`). +4. It calls `wisdom:RenderMessageTemplate` for `:$ACTIVE_VERSION` once per target profile, so only a published version is ever delivered, and sends the result to each of the profile's registered devices. -The match is on the exact template name, so the following two values must be identical: +The template name is the wiring, so these two values must be identical: -- The name of the message template in Amazon Q in Connect. +- The `--name` you give the message template. - The name of the custom action block in your Amazon Connect journey. -If no template matches, delivery still proceeds using default copy, and the function records a `template.noMatch` entry in its Amazon CloudWatch log group. Check that log group first when your users receive placeholder text. +If no template matches, delivery still proceeds using default copy, and the same default-copy path applies when the campaign metadata, the knowledge base association, or a matching template cannot be found. + +## Find your knowledge base ID + +In create mode, `defineNotifications` provisions an empty `MESSAGE_TEMPLATES` knowledge base and associates it with your Amazon Connect instance through the `Q_MESSAGE_TEMPLATES` integration. In attach mode, associate a `MESSAGE_TEMPLATES` knowledge base with your existing Connect instance yourself so this lookup resolves. + +Either way, look up the knowledge base ID with the AWS CLI: + +```bash title="Terminal" showLineNumbers={false} +aws connect list-integration-associations \ + --instance-id \ + --integration-type Q_MESSAGE_TEMPLATES +``` + +The knowledge base ID is the last segment of the returned `IntegrationArn`, which ends in `knowledge-base/`. ## Create the message template -1. Open the [Amazon Connect console](https://console.aws.amazon.com/connect/) and sign in to your Amazon Connect instance. -2. Confirm that Amazon Q in Connect is enabled on the instance. The push-delivery function reads templates from the knowledge base that Amazon Q in Connect associates with the instance, so an instance without it cannot resolve templates. -3. Navigate to **Amazon Q** > **Message templates**, then choose **Create template**. -4. For the channel, choose **Push**. -5. For **Name**, enter the name you will give the custom action block in your journey. Record this value. -6. Enter the title and body for each platform you support. A push template holds separate content for Apple Push Notification service (APNs) and Firebase Cloud Messaging (FCM), which lets you tailor the copy per platform. Content you leave empty for a platform falls back to default copy for that platform. -7. Save the template. The push-delivery function renders the template's active version, so publish or activate the version you want your users to receive. +Create the template with `qconnect create-message-template`, using the same name you will give the journey's custom action block: + +```bash title="Terminal" showLineNumbers={false} +aws qconnect create-message-template \ + --knowledge-base-id \ + --name 'Push Notification' \ + --channel-subtype PUSH \ + --content '{"push":{"apns":{"title":"Hello {{Attributes.firstName}}","body":{"content":"Your order shipped."}},"fcm":{"title":"Hello {{Attributes.firstName}}","body":{"content":"Your order shipped."}}}}' +``` + +Per-platform content maps to channels as `push.apns` (Apple Push Notification service, including the sandbox channel) and `push.fcm` (Firebase Cloud Messaging). A platform entry needs both a title and a body to be used; a platform you leave out falls back to default copy for that platform. + +Publishing a version is required — rendering always targets `$ACTIVE_VERSION`, so a saved template with no published version is not delivered. Publish a version after every copy change: + +```bash title="Terminal" showLineNumbers={false} +aws qconnect create-message-template-version \ + --knowledge-base-id \ + --message-template-id +``` ## Personalize the message -Templates support Handlebars variables that are filled in per profile at delivery time. Reference a profile field with the `Attributes` namespace: +Templates support `{{Attributes.}}` variables, resolved per profile at delivery time: ```handlebars Hello {{Attributes.firstName}}, your order is on the way. ``` -The values available to a template come from the target Customer Profile: - -- Top-level profile fields, such as `firstName`. -- Every entry in the profile's custom attributes, which your application sets with [`identifyUser`](/[platform]/frontend/push-notifications/customer-profiles/identify-user/). +The values available to a template come from the target Customer Profile: its top-level fields (such as `firstName`) and every entry of its custom attributes — which your application sets with [`identifyUser`](/[platform]/frontend/push-notifications/customer-profiles/identify-user/) — are passed to the template as flat attributes. A variable with no matching profile value stays literal in the rendered copy, so use variables only for fields you populate consistently, and prefer copy that reads correctly when a value is absent. -Custom attribute entries take precedence over top-level fields when both use the same key. A variable that a profile has no value for is left in the message as literal text, so use variables only for fields you populate consistently, and prefer copy that reads correctly when a value is absent. +See the [Amazon Q in Connect message template API reference](https://docs.aws.amazon.com/amazon-q-connect/latest/APIReference/API_CreateMessageTemplate.html) for the full content schema. ## Add the custom action to your journey +Building the journey itself is done in the Amazon Connect console — only template authoring is CLI-only: + 1. In the Amazon Connect console, navigate to **Journeys** and open or create a journey. 2. Add a **custom action** block and point it at the push-delivery Lambda function that Amplify deployed. -3. Set the block name to the template name from step 5 above. The names must match exactly, including capitalization. +3. Set the block name to the exact `--name` value you gave the template above, including capitalization. 4. Publish the journey. ## Next steps diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/existing-resources/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/existing-resources/index.mdx index 150c231a243..853f5c00ff1 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/existing-resources/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/existing-resources/index.mdx @@ -4,7 +4,7 @@ export const meta = { title: 'Use existing AWS resources', description: 'Attach your Amplify notifications resource to an Amazon Connect Customer Profiles domain that already exists.', - platforms: ['javascript', 'react-native'] + platforms: ['javascript', 'angular', 'nextjs', 'react', 'vue', 'react-native'] }; export const getStaticPaths = async () => { diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx index 4ab54b68bcf..d073b2b50f5 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx @@ -6,7 +6,7 @@ export const meta = { description: 'Send push notifications to your users with a backend powered by Amazon Connect Customer Profiles.', route: '/[platform]/build-a-backend/add-aws-services/notifications', - platforms: ['javascript', 'react-native'] + platforms: ['javascript', 'angular', 'nextjs', 'react', 'vue', 'react-native'] }; export const getStaticPaths = async () => { @@ -24,7 +24,7 @@ export function getStaticProps(context) { }; } -Amplify push notifications are backed by [Amazon Connect Customer Profiles](https://docs.aws.amazon.com/connect/latest/adminguide/customer-profiles.html). A Customer Profile holds the profile information for one person, and the push devices that belong to them. You send a notification by targeting profiles from an [Amazon Connect journey](https://docs.aws.amazon.com/connect/latest/adminguide/journeys.html), which calls into your Amplify backend to deliver the message. +Amplify push notifications are backed by [Amazon Connect Customer Profiles](https://docs.aws.amazon.com/connect/latest/adminguide/customer-profiles.html). A Customer Profile holds the profile information for one person, keyed on a server-derived `principalId`. That person's registered push devices are stored separately, in a DynamoDB device store, associated to the same `principalId`—they are not embedded in the Customer Profile object. You send a notification by targeting profiles from an [Amazon Connect journey](https://docs.aws.amazon.com/connect/latest/adminguide/journeys.html), which calls into your Amplify backend to deliver the message to that person's devices. Add the resource to your backend with the `defineNotifications` construct: diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx index e671af92b38..9cbcdda44f7 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx @@ -4,7 +4,7 @@ export const meta = { title: 'Set up notifications', description: 'Add push notifications to your Amplify backend with the defineNotifications construct, either by creating a new Amazon Connect instance or by attaching to an existing Customer Profiles domain.', - platforms: ['javascript', 'react-native'] + platforms: ['javascript', 'angular', 'nextjs', 'react', 'vue', 'react-native'] }; export const getStaticPaths = async () => { diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/guest-and-authenticated-users/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/guest-and-authenticated-users/index.mdx index 73efbe14143..f8c0214b7bd 100644 --- a/src/pages/[platform]/frontend/push-notifications/customer-profiles/guest-and-authenticated-users/index.mdx +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/guest-and-authenticated-users/index.mdx @@ -4,7 +4,7 @@ export const meta = { title: 'Guest and authenticated users', description: 'How Amazon Connect Customer Profiles notifications work for guest and signed-in users, and how a device moves to the authenticated identity on sign-in.', - platforms: ['javascript', 'react-native'] + platforms: ['javascript', 'angular', 'nextjs', 'react', 'vue', 'react-native'] }; export const getStaticPaths = async () => { diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/identify-user/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/identify-user/index.mdx index d57b5469603..4f43e7c01eb 100644 --- a/src/pages/[platform]/frontend/push-notifications/customer-profiles/identify-user/index.mdx +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/identify-user/index.mdx @@ -4,7 +4,7 @@ export const meta = { title: 'Identify a user', description: 'Send profile information for the current user to Amazon Connect Customer Profiles with the identifyUser API.', - platforms: ['javascript', 'react-native'] + platforms: ['javascript', 'angular', 'nextjs', 'react', 'vue', 'react-native'] }; export const getStaticPaths = async () => { diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx index 199953b509a..b1142759430 100644 --- a/src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx @@ -6,7 +6,7 @@ export const meta = { description: 'Send profile information and register push devices with Amazon Connect Customer Profiles from your application.', route: '/[platform]/frontend/push-notifications/customer-profiles', - platforms: ['javascript', 'react-native'] + platforms: ['javascript', 'angular', 'nextjs', 'react', 'vue', 'react-native'] }; export const getStaticPaths = async () => { @@ -24,7 +24,7 @@ export function getStaticProps(context) { }; } -The Amazon Connect Customer Profiles APIs let your application send profile information for the current user and manage the push devices that belong to them. Requests are signed with [Signature Version 4](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv.html) using Amazon Cognito identity pool credentials, and your backend derives the profile identity from the signed request. +The Amazon Connect Customer Profiles APIs let your application send profile information for the current user and manage that person's registered push devices. Devices are stored separately from the Customer Profile—in a DynamoDB device store, associated by `principalId`—rather than embedded inside the profile. Requests are signed with [Signature Version 4](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv.html) using Amazon Cognito identity pool credentials, and your backend derives the profile identity from the signed request. These APIs are exported from the `aws-amplify/push-notifications/customer-profiles` sub-path. @@ -45,7 +45,7 @@ The device APIs interact with the native push notification system, so support va | `registerDevice` | Not supported | Supported | | `removeDevice` | Not supported | Supported | - + @@ -57,7 +57,7 @@ On web, `initializePushNotifications`, `registerDevice`, and `removeDevice` thro ## Install the library - + ```bash title="Terminal" showLineNumbers={false} npm add aws-amplify @@ -84,7 +84,7 @@ Because push notifications interact with the native platform, you also need to l Pass `amplify_outputs.json` to `Amplify.configure()`. The endpoint and Region that your backend deployed are read from the `notifications` section of that file. - + ```ts title="src/main.ts" import { Amplify } from 'aws-amplify'; diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/register-device/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/register-device/index.mdx index 742fe776154..050cf872043 100644 --- a/src/pages/[platform]/frontend/push-notifications/customer-profiles/register-device/index.mdx +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/register-device/index.mdx @@ -4,7 +4,7 @@ export const meta = { title: 'Register a device', description: 'Register a push device with Amazon Connect Customer Profiles so that Amazon Connect journeys can deliver notifications to it.', - platforms: ['javascript', 'react-native'] + platforms: ['javascript', 'angular', 'nextjs', 'react', 'vue', 'react-native'] }; export const getStaticPaths = async () => { @@ -22,7 +22,7 @@ export function getStaticProps(context) { A device must be registered before an Amazon Connect journey can deliver a notification to it. Registering stores the device's push token against the current user's profile identity, so your backend knows where to send messages. - + diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/remove-device/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/remove-device/index.mdx index a8f8031f35b..1d03c3ba1d7 100644 --- a/src/pages/[platform]/frontend/push-notifications/customer-profiles/remove-device/index.mdx +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/remove-device/index.mdx @@ -4,7 +4,7 @@ export const meta = { title: 'Remove a device', description: 'De-register a push device from Amazon Connect Customer Profiles, and why removal must happen before signing a user out.', - platforms: ['javascript', 'react-native'] + platforms: ['javascript', 'angular', 'nextjs', 'react', 'vue', 'react-native'] }; export const getStaticPaths = async () => { @@ -46,7 +46,7 @@ Reversing the order leaves the device registered against the signed-out user's p - + From d34af22311d836de4c879ffbe719a8c3a4142c8b Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Wed, 29 Jul 2026 13:18:21 +0000 Subject: [PATCH 03/12] docs: fix spellcheck and lint issues for Connect Customer Profiles push notifications --- cspell.json | 3 +++ .../notifications/set-up-notifications/index.mdx | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cspell.json b/cspell.json index 74ecac7788d..7dadf0f37a7 100644 --- a/cspell.json +++ b/cspell.json @@ -463,6 +463,7 @@ "confirmSignUp", "ConfirmSignUp", "confirmSignUpConfig", + "connectcampaignsv", "connectedform", "connectionWithKeyExamples.md", "constraintlayout", @@ -1091,6 +1092,7 @@ "putVocabularies", "pythonapi", "qafh", + "qconnect", "QLAPINONEDS", "QLAPI", "QLID", @@ -1353,6 +1355,7 @@ "Unauth", "uncategorized", "uncommenting", + "unconfigured", "unencrypted", "unioned", "unmarshall", diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx index 9cbcdda44f7..3305344e253 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx @@ -124,8 +124,8 @@ defineBackend({ notifications: defineNotifications({ apns: { tokenKey: secret('APNS_SIGNING_KEY'), - tokenKeyId: 'ABC123DEFG', - teamId: 'DEF456GHIJ', + tokenKeyId: 'A1B2C3D4E5', + teamId: 'T9S8R7Q6P5', bundleId: 'com.example.myapp' }, fcm: { From a7967a48279a628f86fde46c4a1a2ff50a53ae1a Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Wed, 29 Jul 2026 13:33:28 +0000 Subject: [PATCH 04/12] docs: rename push notifications nav items and hide Pinpoint EOL banner on Customer Profiles pages --- src/components/Layout/Layout.tsx | 5 ++- .../Layout/__tests__/Layout.test.tsx | 36 +++++++++++++++++-- .../add-aws-services/notifications/index.mdx | 2 +- .../customer-profiles/index.mdx | 2 +- 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/components/Layout/Layout.tsx b/src/components/Layout/Layout.tsx index aa3db961b70..9db7bc436c2 100644 --- a/src/components/Layout/Layout.tsx +++ b/src/components/Layout/Layout.tsx @@ -396,7 +396,10 @@ export const Layout = ({ /> )} - {(asPathWithNoHash.includes('/push-notifications/') || + {((asPathWithNoHash.includes('/push-notifications/') && + !asPathWithNoHash.includes( + '/push-notifications/customer-profiles' + )) || asPathWithNoHash.includes('/analytics/') || asPathWithNoHash.includes('/in-app-messaging/')) && !asPathWithNoHash.includes('/kinesis') && diff --git a/src/components/Layout/__tests__/Layout.test.tsx b/src/components/Layout/__tests__/Layout.test.tsx index ac116f9725a..4c0efbdf674 100644 --- a/src/components/Layout/__tests__/Layout.test.tsx +++ b/src/components/Layout/__tests__/Layout.test.tsx @@ -3,13 +3,18 @@ import { render, screen } from '@testing-library/react'; import { Layout } from '../index'; import userEvent from '@testing-library/user-event'; +const routerState: { asPath: string; pathname: string } = { + asPath: '/[platform]/start/getting-started/introduction/', + pathname: '/[platform]/start/getting-started/introduction/' +}; + const routerMock = { __esModule: true, useRouter: () => { return { query: { platform: 'react' }, - pathname: '/[platform]/start/getting-started/introduction/', - asPath: '/[platform]/start/getting-started/introduction/' + pathname: routerState.pathname, + asPath: routerState.asPath }; } }; @@ -32,6 +37,11 @@ describe('Layout', () => { ); + beforeEach(() => { + routerState.asPath = '/[platform]/start/getting-started/introduction/'; + routerState.pathname = '/[platform]/start/getting-started/introduction/'; + }); + it('should render the Layout component', async () => { render(layoutComponent); const layout = await screen.getByRole('main', { name: 'Main content' }); @@ -108,4 +118,26 @@ describe('Layout', () => { 'layout-sidebar__mobile-toggle--open' ); }); + + describe('PinpointEOLBanner', () => { + it('is not rendered for the Customer Profiles push-notifications client pages', async () => { + routerState.asPath = + '/react/frontend/push-notifications/customer-profiles/'; + render(layoutComponent); + expect(document.body.textContent).not.toContain('Amazon Pinpoint'); + }); + + it('is rendered for the legacy (gen1) push-notifications pages', async () => { + routerState.asPath = + '/gen1/react/build-a-backend/push-notifications/set-up-push-notifications/'; + render(layoutComponent); + expect(document.body.textContent).toContain('Amazon Pinpoint'); + }); + + it('is rendered for analytics pages', async () => { + routerState.asPath = '/react/build-a-backend/add-aws-services/analytics/'; + render(layoutComponent); + expect(document.body.textContent).toContain('Amazon Pinpoint'); + }); + }); }); diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx index d073b2b50f5..95ea981fe75 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx @@ -2,7 +2,7 @@ import { getChildPageNodes } from '@/utils/getChildPageNodes'; import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; export const meta = { - title: 'Notifications', + title: 'Push Notifications', description: 'Send push notifications to your users with a backend powered by Amazon Connect Customer Profiles.', route: '/[platform]/build-a-backend/add-aws-services/notifications', diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx index b1142759430..5bf1e76b911 100644 --- a/src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx @@ -2,7 +2,7 @@ import { getChildPageNodes } from '@/utils/getChildPageNodes'; import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; export const meta = { - title: 'Push notifications', + title: 'Push Notifications', description: 'Send profile information and register push devices with Amazon Connect Customer Profiles from your application.', route: '/[platform]/frontend/push-notifications/customer-profiles', From c15f032ddd8a8f8adb9a010647042358f643d0a8 Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Wed, 29 Jul 2026 13:38:50 +0000 Subject: [PATCH 05/12] docs: tidy prose in Customer Profiles push notifications pages --- .../author-message-templates/index.mdx | 8 ++++---- .../add-aws-services/notifications/index.mdx | 4 ++-- .../set-up-notifications/index.mdx | 18 +++++++++--------- .../customer-profiles/index.mdx | 2 +- .../register-device/index.mdx | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx index 5593c5edf09..6ca44eebe6a 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx @@ -72,7 +72,7 @@ aws qconnect create-message-template \ Per-platform content maps to channels as `push.apns` (Apple Push Notification service, including the sandbox channel) and `push.fcm` (Firebase Cloud Messaging). A platform entry needs both a title and a body to be used; a platform you leave out falls back to default copy for that platform. -Publishing a version is required — rendering always targets `$ACTIVE_VERSION`, so a saved template with no published version is not delivered. Publish a version after every copy change: +Publishing a version is required: rendering always targets `$ACTIVE_VERSION`, so a saved template with no published version is not delivered. Publish a version after every copy change: ```bash title="Terminal" showLineNumbers={false} aws qconnect create-message-template-version \ @@ -88,13 +88,13 @@ Templates support `{{Attributes.}}` variables, resolved per profile at deli Hello {{Attributes.firstName}}, your order is on the way. ``` -The values available to a template come from the target Customer Profile: its top-level fields (such as `firstName`) and every entry of its custom attributes — which your application sets with [`identifyUser`](/[platform]/frontend/push-notifications/customer-profiles/identify-user/) — are passed to the template as flat attributes. A variable with no matching profile value stays literal in the rendered copy, so use variables only for fields you populate consistently, and prefer copy that reads correctly when a value is absent. +The values available to a template come from the target Customer Profile: its top-level fields (such as `firstName`) and every entry of its custom attributes, which your application sets with [`identifyUser`](/[platform]/frontend/push-notifications/customer-profiles/identify-user/), are passed to the template as flat attributes. A variable with no matching profile value stays literal in the rendered copy, so use variables only for fields you populate consistently, and prefer copy that reads correctly when a value is absent. See the [Amazon Q in Connect message template API reference](https://docs.aws.amazon.com/amazon-q-connect/latest/APIReference/API_CreateMessageTemplate.html) for the full content schema. ## Add the custom action to your journey -Building the journey itself is done in the Amazon Connect console — only template authoring is CLI-only: +Building the journey itself is done in the Amazon Connect console; only template authoring is CLI-only: 1. In the Amazon Connect console, navigate to **Journeys** and open or create a journey. 2. Add a **custom action** block and point it at the push-delivery Lambda function that Amplify deployed. @@ -103,4 +103,4 @@ Building the journey itself is done in the Amazon Connect console — only templ ## Next steps -- [Push notifications](/[platform]/frontend/push-notifications/customer-profiles/) — register devices and send profile information from your application. +- [Push notifications](/[platform]/frontend/push-notifications/customer-profiles/): register devices and send profile information from your application. diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx index 95ea981fe75..7e592d42106 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx @@ -24,7 +24,7 @@ export function getStaticProps(context) { }; } -Amplify push notifications are backed by [Amazon Connect Customer Profiles](https://docs.aws.amazon.com/connect/latest/adminguide/customer-profiles.html). A Customer Profile holds the profile information for one person, keyed on a server-derived `principalId`. That person's registered push devices are stored separately, in a DynamoDB device store, associated to the same `principalId`—they are not embedded in the Customer Profile object. You send a notification by targeting profiles from an [Amazon Connect journey](https://docs.aws.amazon.com/connect/latest/adminguide/journeys.html), which calls into your Amplify backend to deliver the message to that person's devices. +Amplify push notifications are backed by [Amazon Connect Customer Profiles](https://docs.aws.amazon.com/connect/latest/adminguide/customer-profiles.html). A Customer Profile holds the profile information for one person, keyed on a server-derived `principalId`. That person's registered push devices are stored separately, in a DynamoDB device store, associated to the same `principalId`; they are not embedded in the Customer Profile object. You send a notification by targeting profiles from an [Amazon Connect journey](https://docs.aws.amazon.com/connect/latest/adminguide/journeys.html), which calls into your Amplify backend to deliver the message to that person's devices. Add the resource to your backend with the `defineNotifications` construct: @@ -45,7 +45,7 @@ Deploying `defineNotifications` provisions the following resources: - An **`AmplifyProfile` Customer Profiles object type**, registered on your Customer Profiles domain. It is keyed on `principalId`, a searchable and unique field that holds the Amazon Cognito identity pool `identityId` of the caller. Your backend derives `principalId` from the signed request, so a client never sends it and cannot write to another person's profile. - A **DynamoDB device store** that holds the registered push devices. Device records live in this table rather than in Customer Profiles. -- Three **HTTP API routes** — `identify-user`, `register-device`, and `remove-device` — authorized with AWS Identity and Access Management (IAM) and called with [Signature Version 4](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv.html) signed requests. A single least-privilege Lambda function serves all three routes. +- Three **HTTP API routes** (`identify-user`, `register-device`, and `remove-device`), authorized with AWS Identity and Access Management (IAM) and called with [Signature Version 4](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv.html) signed requests. A single least-privilege Lambda function serves all three routes. - A **push-delivery Lambda function**, invoked as a custom action from an Amazon Connect journey. It looks up the target profile's devices and sends the message to each one. - An **AWS End User Messaging application**, with the APNs and FCM channels you configure. diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx index 3305344e253..281f293aa87 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx @@ -26,7 +26,7 @@ The `defineNotifications` construct adds an Amazon Connect Customer Profiles-bac Before you begin, complete the following steps: -1. Add authentication to your backend. The notification APIs are called with [Signature Version 4](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv.html) signed requests using Amazon Cognito identity pool credentials, so an `auth` resource is required. Both signed-in and guest users can call the APIs — see [Guest access](/[platform]/build-a-backend/auth/concepts/guest-access/). +1. Add authentication to your backend. The notification APIs are called with [Signature Version 4](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv.html) signed requests using Amazon Cognito identity pool credentials, so an `auth` resource is required. Both signed-in and guest users can call the APIs; see [Guest access](/[platform]/build-a-backend/auth/concepts/guest-access/). 2. Install the notifications package: ```bash title="Terminal" showLineNumbers={false} @@ -35,8 +35,8 @@ npm add @aws-amplify/backend-notifications 3. Gather the credentials for each push channel you want to enable: - - **Apple Push Notification service (APNs)** — a token-based signing key (`.p8`), its key ID, your Apple team ID, and your application's bundle ID. - - **Firebase Cloud Messaging (FCM)** — the service account JSON for your Firebase project. + - **Apple Push Notification service (APNs)**: a token-based signing key (`.p8`), its key ID, your Apple team ID, and your application's bundle ID. + - **Firebase Cloud Messaging (FCM)**: the service account JSON for your Firebase project. 4. Store the sensitive credentials as secrets. The signing key and the service account JSON are referenced with `secret()` rather than written into your backend code: @@ -69,8 +69,8 @@ defineBackend({ Two optional properties are available in this mode: -- `instanceAlias` — the alias for the new Amazon Connect instance. Aliases are globally unique within an AWS Region. When you omit this property, Amplify generates a stable name for your Amplify project. -- `expirationDays` — how long Customer Profiles retains profile data in the new domain. +- `instanceAlias`: the alias for the new Amazon Connect instance. Aliases are globally unique within an AWS Region. When you omit this property, Amplify generates a stable name for your Amplify project. +- `expirationDays`: how long Customer Profiles retains profile data in the new domain. ```ts title="amplify/backend.ts" notifications: defineNotifications({ @@ -112,7 +112,7 @@ For the requirements your existing domain must meet, see [Use existing resources ## Configure push channels -Add `apns`, `fcm`, or both to enable the corresponding channel on the AWS End User Messaging application that Amplify creates. Channels are optional and independent — omit one to leave it unconfigured. +Add `apns`, `fcm`, or both to enable the corresponding channel on the AWS End User Messaging application that Amplify creates. Channels are optional and independent; omit one to leave it unconfigured. ```ts title="amplify/backend.ts" import { defineBackend, secret } from '@aws-amplify/backend'; @@ -153,7 +153,7 @@ The `fcm` property is: -Pass `tokenKey` and `serviceJson` with `secret()`. Do not paste the key material into `amplify/backend.ts` — it would be committed to your repository. +Pass `tokenKey` and `serviceJson` with `secret()`. Do not paste the key material into `amplify/backend.ts`; it would be committed to your repository. @@ -180,5 +180,5 @@ When the deployment finishes, the invoke endpoint and region are written to `amp ## Next steps -- [Author message templates](/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/) — create the push message content in Amazon Q in Connect. -- [Push notifications](/[platform]/frontend/push-notifications/customer-profiles/) — call the notification APIs from your application. +- [Author message templates](/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/): create the push message content in Amazon Q in Connect. +- [Push notifications](/[platform]/frontend/push-notifications/customer-profiles/): call the notification APIs from your application. diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx index 5bf1e76b911..1dc16ab9b86 100644 --- a/src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx @@ -24,7 +24,7 @@ export function getStaticProps(context) { }; } -The Amazon Connect Customer Profiles APIs let your application send profile information for the current user and manage that person's registered push devices. Devices are stored separately from the Customer Profile—in a DynamoDB device store, associated by `principalId`—rather than embedded inside the profile. Requests are signed with [Signature Version 4](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv.html) using Amazon Cognito identity pool credentials, and your backend derives the profile identity from the signed request. +The Amazon Connect Customer Profiles APIs let your application send profile information for the current user and manage that person's registered push devices. Devices are stored separately from the Customer Profile, in a DynamoDB device store, associated by `principalId`, rather than embedded inside the profile. Requests are signed with [Signature Version 4](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv.html) using Amazon Cognito identity pool credentials, and your backend derives the profile identity from the signed request. These APIs are exported from the `aws-amplify/push-notifications/customer-profiles` sub-path. diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/register-device/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/register-device/index.mdx index 050cf872043..3c14fef6b2a 100644 --- a/src/pages/[platform]/frontend/push-notifications/customer-profiles/register-device/index.mdx +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/register-device/index.mdx @@ -129,6 +129,6 @@ try { ## Next steps -- [Remove a device](/[platform]/frontend/push-notifications/customer-profiles/remove-device/) — de-register a device before signing a user out. +- [Remove a device](/[platform]/frontend/push-notifications/customer-profiles/remove-device/): de-register a device before signing a user out. From a7f817c32d81b9848494fd952cf5752ddbb19e01 Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Wed, 29 Jul 2026 13:40:56 +0000 Subject: [PATCH 06/12] docs: simplify push message template matching explanation --- .../author-message-templates/index.mdx | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx index 6ca44eebe6a..6100ae770b7 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx @@ -28,21 +28,9 @@ Amplify provisions the delivery path for your notifications, but not the message -## How the template is matched +## Name the template to match your journey -When an Amazon Connect journey reaches a custom action block that targets your push-delivery Lambda function, the function resolves the template for that journey run: - -1. It calls `connectcampaignsv2:DescribeCampaign` on the campaign ID from the event to get the Connect instance ID. -2. It calls `connect:ListIntegrationAssociations`, filtered to the `Q_MESSAGE_TEMPLATES` integration type, to get the knowledge base ID. -3. It calls `wisdom:ListMessageTemplates` on that knowledge base and selects the template whose `channelSubtype` is `PUSH` and whose **name equals the journey custom action block name** (the event's `ActionId`). -4. It calls `wisdom:RenderMessageTemplate` for `:$ACTIVE_VERSION` once per target profile, so only a published version is ever delivered, and sends the result to each of the profile's registered devices. - -The template name is the wiring, so these two values must be identical: - -- The `--name` you give the message template. -- The name of the custom action block in your Amazon Connect journey. - -If no template matches, delivery still proceeds using default copy, and the same default-copy path applies when the campaign metadata, the knowledge base association, or a matching template cannot be found. +A push template's name is the only way Amplify links it to a journey: give the template the exact same name as the custom action block in your Amazon Connect journey. ## Find your knowledge base ID @@ -72,7 +60,7 @@ aws qconnect create-message-template \ Per-platform content maps to channels as `push.apns` (Apple Push Notification service, including the sandbox channel) and `push.fcm` (Firebase Cloud Messaging). A platform entry needs both a title and a body to be used; a platform you leave out falls back to default copy for that platform. -Publishing a version is required: rendering always targets `$ACTIVE_VERSION`, so a saved template with no published version is not delivered. Publish a version after every copy change: +Publish a version after every copy change: ```bash title="Terminal" showLineNumbers={false} aws qconnect create-message-template-version \ @@ -82,13 +70,13 @@ aws qconnect create-message-template-version \ ## Personalize the message -Templates support `{{Attributes.}}` variables, resolved per profile at delivery time: +Templates support `{{Attributes.}}` variables, which resolve to the target Customer Profile's fields, including custom attributes you set with [`identifyUser`](/[platform]/frontend/push-notifications/customer-profiles/identify-user/): ```handlebars Hello {{Attributes.firstName}}, your order is on the way. ``` -The values available to a template come from the target Customer Profile: its top-level fields (such as `firstName`) and every entry of its custom attributes, which your application sets with [`identifyUser`](/[platform]/frontend/push-notifications/customer-profiles/identify-user/), are passed to the template as flat attributes. A variable with no matching profile value stays literal in the rendered copy, so use variables only for fields you populate consistently, and prefer copy that reads correctly when a value is absent. +A variable with no matching profile value stays literal in the rendered copy, so use variables only for fields you populate consistently, and prefer copy that reads correctly when a value is absent. See the [Amazon Q in Connect message template API reference](https://docs.aws.amazon.com/amazon-q-connect/latest/APIReference/API_CreateMessageTemplate.html) for the full content schema. From 5509bc00526cee2d1cc0f4ced829f9c1fe67a8ac Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Wed, 29 Jul 2026 13:46:06 +0000 Subject: [PATCH 07/12] docs: scope Customer Profiles push notifications to React Native only --- .../author-message-templates/index.mdx | 2 +- .../existing-resources/index.mdx | 2 +- .../add-aws-services/notifications/index.mdx | 2 +- .../set-up-notifications/index.mdx | 2 +- .../guest-and-authenticated-users/index.mdx | 6 +-- .../customer-profiles/identify-user/index.mdx | 6 +-- .../customer-profiles/index.mdx | 50 +------------------ .../register-device/index.mdx | 16 +----- .../customer-profiles/remove-device/index.mdx | 16 +----- 9 files changed, 9 insertions(+), 93 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx index 6100ae770b7..e54ff6a39d7 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx @@ -4,7 +4,7 @@ export const meta = { title: 'Author message templates', description: 'Create a push message template with the Amazon Q in Connect API and connect it to an Amazon Connect journey custom action.', - platforms: ['javascript', 'angular', 'nextjs', 'react', 'vue', 'react-native'] + platforms: ['react-native'] }; export const getStaticPaths = async () => { diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/existing-resources/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/existing-resources/index.mdx index 853f5c00ff1..5329d0d5835 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/existing-resources/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/existing-resources/index.mdx @@ -4,7 +4,7 @@ export const meta = { title: 'Use existing AWS resources', description: 'Attach your Amplify notifications resource to an Amazon Connect Customer Profiles domain that already exists.', - platforms: ['javascript', 'angular', 'nextjs', 'react', 'vue', 'react-native'] + platforms: ['react-native'] }; export const getStaticPaths = async () => { diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx index 7e592d42106..608a0f40a1a 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx @@ -6,7 +6,7 @@ export const meta = { description: 'Send push notifications to your users with a backend powered by Amazon Connect Customer Profiles.', route: '/[platform]/build-a-backend/add-aws-services/notifications', - platforms: ['javascript', 'angular', 'nextjs', 'react', 'vue', 'react-native'] + platforms: ['react-native'] }; export const getStaticPaths = async () => { diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx index 281f293aa87..58415d295ed 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx @@ -4,7 +4,7 @@ export const meta = { title: 'Set up notifications', description: 'Add push notifications to your Amplify backend with the defineNotifications construct, either by creating a new Amazon Connect instance or by attaching to an existing Customer Profiles domain.', - platforms: ['javascript', 'angular', 'nextjs', 'react', 'vue', 'react-native'] + platforms: ['react-native'] }; export const getStaticPaths = async () => { diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/guest-and-authenticated-users/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/guest-and-authenticated-users/index.mdx index f8c0214b7bd..804e682654b 100644 --- a/src/pages/[platform]/frontend/push-notifications/customer-profiles/guest-and-authenticated-users/index.mdx +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/guest-and-authenticated-users/index.mdx @@ -4,7 +4,7 @@ export const meta = { title: 'Guest and authenticated users', description: 'How Amazon Connect Customer Profiles notifications work for guest and signed-in users, and how a device moves to the authenticated identity on sign-in.', - platforms: ['javascript', 'angular', 'nextjs', 'react', 'vue', 'react-native'] + platforms: ['react-native'] }; export const getStaticPaths = async () => { @@ -39,8 +39,6 @@ A guest identity is scoped to the installation, not to a person. Treat a guest p - - ## A device moves to the authenticated identity on sign-in A guest user's push token and a signed-in user's push token are the same value, because the native platform issues the token to the installation rather than to a user. Without any handling, a device registered as a guest would stay attached to the guest identity after the user signed in, and journeys targeting the authenticated profile would not reach it. @@ -62,8 +60,6 @@ Re-registration on sign-in is a best-effort operation. A failure is logged and d If no push token has been issued yet when a user signs in, there is nothing to move. The first registration then happens against the authenticated identity once the native platform issues the token. - - ## Sign a user out Signing a user out does not de-register their device. Call `removeDevice` while the user is still signed in, because de-registration is signed with their credentials: diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/identify-user/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/identify-user/index.mdx index 4f43e7c01eb..b0398030c18 100644 --- a/src/pages/[platform]/frontend/push-notifications/customer-profiles/identify-user/index.mdx +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/identify-user/index.mdx @@ -4,7 +4,7 @@ export const meta = { title: 'Identify a user', description: 'Send profile information for the current user to Amazon Connect Customer Profiles with the identifyUser API.', - platforms: ['javascript', 'angular', 'nextjs', 'react', 'vue', 'react-native'] + platforms: ['react-native'] }; export const getStaticPaths = async () => { @@ -79,16 +79,12 @@ Call `identifyUser` when the profile information you hold changes, for example: `identifyUser` sends profile information only and performs no device work. To manage push devices, use [`registerDevice`](/[platform]/frontend/push-notifications/customer-profiles/register-device/) and [`removeDevice`](/[platform]/frontend/push-notifications/customer-profiles/remove-device/). - - `identifyUser` does not require `initializePushNotifications`. Its only prerequisites are a configured endpoint and identity pool credentials, so you can call it before push notifications are initialized. - - ## Personalize messages with profile values Message templates reference profile values with the `Attributes` namespace, so a `customAttributes` entry named `favoriteCategory` is available to a template as `{{Attributes.favoriteCategory}}`. See [Author message templates](/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/). diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx index 1dc16ab9b86..eb6eeca7eb9 100644 --- a/src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx @@ -6,7 +6,7 @@ export const meta = { description: 'Send profile information and register push devices with Amazon Connect Customer Profiles from your application.', route: '/[platform]/frontend/push-notifications/customer-profiles', - platforms: ['javascript', 'angular', 'nextjs', 'react', 'vue', 'react-native'] + platforms: ['react-native'] }; export const getStaticPaths = async () => { @@ -34,39 +34,8 @@ This page assumes you have already deployed a notifications resource. See [Set u -## Platform support - -The device APIs interact with the native push notification system, so support varies by platform: - -| API | Web | React Native | -| --- | --- | --- | -| `identifyUser` | Supported | Supported | -| `initializePushNotifications` | Not supported | Supported | -| `registerDevice` | Not supported | Supported | -| `removeDevice` | Not supported | Supported | - - - - - -On web, `initializePushNotifications`, `registerDevice`, and `removeDevice` throw a `PlatformNotSupportedError`. Use [`identifyUser`](/[platform]/frontend/push-notifications/customer-profiles/identify-user/) to send profile information from a web application, and register devices from your React Native application. - - - - - ## Install the library - - -```bash title="Terminal" showLineNumbers={false} -npm add aws-amplify -``` - - - - - Push notifications require the native module in addition to `aws-amplify`: ```bash title="Terminal" showLineNumbers={false} @@ -78,25 +47,10 @@ Because push notifications interact with the native platform, you also need to l - On iOS, run `npx pod-install`, add the push notification capability to your target in Xcode, and forward the remote notification callbacks from your `AppDelegate` to `AmplifyPushNotification`. - On Android, no additional integration steps are required beyond installing the packages above. - - ## Configure Amplify Pass `amplify_outputs.json` to `Amplify.configure()`. The endpoint and Region that your backend deployed are read from the `notifications` section of that file. - - -```ts title="src/main.ts" -import { Amplify } from 'aws-amplify'; -import outputs from '../amplify_outputs.json'; - -Amplify.configure(outputs); -``` - - - - - Configure Amplify and initialize push notifications at your application's root entry point. Initializing early allows your application to process notifications that arrive while it is in a terminated state. ```ts title="index.js" @@ -118,8 +72,6 @@ AppRegistry.registerComponent(appName, () => App); Once initialized, the library registers the device automatically the first time the native platform issues a push token, so most applications do not call `registerDevice` themselves. See [Register a device](/[platform]/frontend/push-notifications/customer-profiles/register-device/). - - Call `removeDevice` before signing a user out. De-registration is signed with the current user's credentials, so it cannot succeed after `signOut` has completed. See [Remove a device](/[platform]/frontend/push-notifications/customer-profiles/remove-device/). diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/register-device/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/register-device/index.mdx index 3c14fef6b2a..24a00328e23 100644 --- a/src/pages/[platform]/frontend/push-notifications/customer-profiles/register-device/index.mdx +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/register-device/index.mdx @@ -4,7 +4,7 @@ export const meta = { title: 'Register a device', description: 'Register a push device with Amazon Connect Customer Profiles so that Amazon Connect journeys can deliver notifications to it.', - platforms: ['javascript', 'angular', 'nextjs', 'react', 'vue', 'react-native'] + platforms: ['react-native'] }; export const getStaticPaths = async () => { @@ -22,18 +22,6 @@ export function getStaticProps(context) { A device must be registered before an Amazon Connect journey can deliver a notification to it. Registering stores the device's push token against the current user's profile identity, so your backend knows where to send messages. - - - - -`registerDevice` is supported on React Native only. On web it throws a `PlatformNotSupportedError`, because registration depends on a push token issued by the native platform. - - - - - - - ## Registration happens automatically In most applications you do not call `registerDevice` yourself. After you call `initializePushNotifications`, the library listens for the push token that the native platform issues and registers the device the first time a token arrives. @@ -130,5 +118,3 @@ try { ## Next steps - [Remove a device](/[platform]/frontend/push-notifications/customer-profiles/remove-device/): de-register a device before signing a user out. - - diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/remove-device/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/remove-device/index.mdx index 1d03c3ba1d7..e389dd7e2d9 100644 --- a/src/pages/[platform]/frontend/push-notifications/customer-profiles/remove-device/index.mdx +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/remove-device/index.mdx @@ -4,7 +4,7 @@ export const meta = { title: 'Remove a device', description: 'De-register a push device from Amazon Connect Customer Profiles, and why removal must happen before signing a user out.', - platforms: ['javascript', 'angular', 'nextjs', 'react', 'vue', 'react-native'] + platforms: ['react-native'] }; export const getStaticPaths = async () => { @@ -46,16 +46,6 @@ Reversing the order leaves the device registered against the signed-out user's p - - - - -`removeDevice` is supported on React Native only. On web it throws a `PlatformNotSupportedError`. A web application that also ships a React Native application should perform device removal there. - - - - - ## Sign a user out safely Handle a failed removal deliberately rather than letting it block sign-out. The following pattern signs the user out even when de-registration fails, which avoids trapping a user in a signed-in state because of a network error: @@ -83,16 +73,12 @@ Call `removeDevice` in these situations: - When a user turns off notifications in your application's settings. - Before deleting a user's account. - - You do not need to call `removeDevice` when the push token is replaced. Registration is keyed on a device identifier that is stable for the installation, so registering with a new token updates the existing record. See [Register a device](/[platform]/frontend/push-notifications/customer-profiles/register-device/). ## Register the device again The device identifier persists after removal, so a user who opts back in can be registered again with `registerDevice`. Removing a device does not reset the identifier or require your application to store one. - - ## Handle errors `removeDevice` rejects in the following cases: From afb848626e686de6e14476c388076b31495dab7a Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Wed, 29 Jul 2026 14:01:41 +0000 Subject: [PATCH 08/12] docs: add permissions, device token, notification interaction, and badge count pages for Customer Profiles push --- src/directory/directory.mjs | 12 ++ .../app-badge-count/index.mdx | 51 +++++++ .../interact-with-notifications/index.mdx | 125 ++++++++++++++++++ .../manage-device-token/index.mdx | 52 ++++++++ .../request-permissions/index.mdx | 88 ++++++++++++ 5 files changed, 328 insertions(+) create mode 100644 src/pages/[platform]/frontend/push-notifications/customer-profiles/app-badge-count/index.mdx create mode 100644 src/pages/[platform]/frontend/push-notifications/customer-profiles/interact-with-notifications/index.mdx create mode 100644 src/pages/[platform]/frontend/push-notifications/customer-profiles/manage-device-token/index.mdx create mode 100644 src/pages/[platform]/frontend/push-notifications/customer-profiles/request-permissions/index.mdx diff --git a/src/directory/directory.mjs b/src/directory/directory.mjs index e19f4b6b94c..072e330bec9 100644 --- a/src/directory/directory.mjs +++ b/src/directory/directory.mjs @@ -901,6 +901,18 @@ export const directory = { }, { path: 'src/pages/[platform]/frontend/push-notifications/customer-profiles/guest-and-authenticated-users/index.mdx' + }, + { + path: 'src/pages/[platform]/frontend/push-notifications/customer-profiles/request-permissions/index.mdx' + }, + { + path: 'src/pages/[platform]/frontend/push-notifications/customer-profiles/manage-device-token/index.mdx' + }, + { + path: 'src/pages/[platform]/frontend/push-notifications/customer-profiles/interact-with-notifications/index.mdx' + }, + { + path: 'src/pages/[platform]/frontend/push-notifications/customer-profiles/app-badge-count/index.mdx' } ] }, diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/app-badge-count/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/app-badge-count/index.mdx new file mode 100644 index 00000000000..193d975b337 --- /dev/null +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/app-badge-count/index.mdx @@ -0,0 +1,51 @@ +import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; + +export const meta = { + title: 'App badge count', + description: + 'Get and set the number displayed on your application icon.', + platforms: ['react-native'] +}; + +export const getStaticPaths = async () => { + return getCustomStaticPath(meta.platforms); +}; + +export function getStaticProps(context) { + return { + props: { + platform: context.params.platform, + meta + } + }; +} + +Use `getBadgeCount` and `setBadgeCount` to read and update the number displayed on your application's icon. Call `initializePushNotifications()` first; see [Push notifications](/[platform]/frontend/push-notifications/customer-profiles/). + +## Get the current badge count + +```ts +import { getBadgeCount } from 'aws-amplify/push-notifications/customer-profiles'; + +const badgeCount = await getBadgeCount(); +``` + +`getBadgeCount` resolves to the current count, or `null` on a platform that does not support badges. + +## Set the badge count + +```ts +import { setBadgeCount } from 'aws-amplify/push-notifications/customer-profiles'; + +setBadgeCount(3); +``` + +Set the count to `0` to clear the badge from your application's icon: + +```ts +import { setBadgeCount } from 'aws-amplify/push-notifications/customer-profiles'; + +setBadgeCount(0); +``` + +`setBadgeCount` is safe to call on a platform that does not support badges. The call is ignored rather than throwing an error. diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/interact-with-notifications/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/interact-with-notifications/index.mdx new file mode 100644 index 00000000000..b91904f7cdf --- /dev/null +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/interact-with-notifications/index.mdx @@ -0,0 +1,125 @@ +import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; + +export const meta = { + title: 'Interact with notifications', + description: + 'Respond to push notifications being received and opened across the states your application can be in.', + platforms: ['react-native'] +}; + +export const getStaticPaths = async () => { + return getCustomStaticPath(meta.platforms); +}; + +export function getStaticProps(context) { + return { + props: { + platform: context.params.platform, + meta + } + }; +} + +Your application can be in one of three states when a notification arrives or is opened, and you handle each differently. Call `initializePushNotifications()` first; see [Push notifications](/[platform]/frontend/push-notifications/customer-profiles/). + +- **Foreground**: your application is running, active, and visible. +- **Background**: your application is still running but is not active or visible. The user is typically on the home screen or in another application. +- **Terminated**: your application is not running at all, even in the background. + +## Respond to a notification being received + +| App state | Handle with | +| ---------------------------- | ------------------------------------- | +| Foreground | `onNotificationReceivedInForeground` | +| Background or terminated | `onNotificationReceivedInBackground` | + +### Received in the foreground + +Notifications received while your application is in the foreground are not displayed by the system. Use their content to update your application instead, for example to refresh a list. + +```ts +import { onNotificationReceivedInForeground } from 'aws-amplify/push-notifications/customer-profiles'; + +const listener = onNotificationReceivedInForeground((notification) => { + // Update your application with the notification's content. +}); +``` + +### Received in the background or while terminated + +```ts +import { onNotificationReceivedInBackground } from 'aws-amplify/push-notifications/customer-profiles'; + +const listener = onNotificationReceivedInBackground(async (notification) => { + // Process the notification, for example by fetching fresh data. +}); +``` + +To handle notifications received while your application is terminated, register this listener at your application's root entry point, before you register your application component. React Native runs it through [Headless JS](https://reactnative.dev/docs/headless-js-android), so your application does not mount when the listener runs: + +```ts title="index.js" +import { AppRegistry } from 'react-native'; +import { Amplify } from 'aws-amplify'; +import { + initializePushNotifications, + onNotificationReceivedInBackground +} from 'aws-amplify/push-notifications/customer-profiles'; +import outputs from './amplify_outputs.json'; + +import App from './App'; +import { name as appName } from './app.json'; + +Amplify.configure(outputs); +initializePushNotifications(); + +onNotificationReceivedInBackground(async (notification) => { + // Process the notification, for example by fetching fresh data. +}); + +AppRegistry.registerComponent(appName, () => App); +``` + +Registering the listener at this entry point means you do not need to remove it. + +Every listener returned by these APIs can be removed by calling `remove` on it: + +```ts +listener.remove(); +``` + +## Respond to a notification being opened + +| App state | Handle with | +| -------------------------- | -------------------------- | +| Foreground or background | `onNotificationOpened` | +| Terminated | `getLaunchNotification` | + +### Opened from the foreground or background + +Add an `onNotificationOpened` listener to respond when a user taps a notification while your application is running: + +```ts +import { onNotificationOpened } from 'aws-amplify/push-notifications/customer-profiles'; + +const listener = onNotificationOpened((notification) => { + // Take action based on the notification the user tapped, such as following a deep link. +}); +``` + +### Launched from a terminated state + +When a notification launches your application from a terminated state, call `getLaunchNotification` to retrieve it: + +```ts +import { getLaunchNotification } from 'aws-amplify/push-notifications/customer-profiles'; + +const launchNotification = await getLaunchNotification(); + +// Take action based on the notification, such as following a deep link. +``` + +`getLaunchNotification` consumes the launch notification. It resolves to `null` if: + +- You call it more than once, so only the first call after launch resolves to the notification. +- Another notification was opened while your application was already running. +- Your application was brought to the foreground by some other means, such as the user tapping the app icon. diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/manage-device-token/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/manage-device-token/index.mdx new file mode 100644 index 00000000000..4450e316c82 --- /dev/null +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/manage-device-token/index.mdx @@ -0,0 +1,52 @@ +import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; + +export const meta = { + title: 'Manage the device token', + description: + 'Listen for the push notification token the native platform issues to the device.', + platforms: ['react-native'] +}; + +export const getStaticPaths = async () => { + return getCustomStaticPath(meta.platforms); +}; + +export function getStaticProps(context) { + return { + props: { + platform: context.params.platform, + meta + } + }; +} + +The native platform issues a token that uniquely identifies the device for push delivery. Use `onTokenReceived` to listen for that token. Call `initializePushNotifications()` first; see [Push notifications](/[platform]/frontend/push-notifications/customer-profiles/). + +## Listen for the token + +Add an `onTokenReceived` listener to be notified when a token is issued: + +```ts +import { onTokenReceived } from 'aws-amplify/push-notifications/customer-profiles'; + +const listener = onTokenReceived((token) => { + // Use the token for your own purposes, such as logging or diagnostics. +}); +``` + +A token is delivered to your listener: + +- On every app launch, including the first install, once the user has granted notification permission. +- Whenever the token changes, which can happen if the native platform invalidates the previous token. + +Remove the listener when you no longer need it by calling `remove` on the value `onTokenReceived` returns: + +```ts +listener.remove(); +``` + +## Relationship to device registration + +You do not need to call `registerDevice` yourself in most applications. The library already listens for this token internally: once `initializePushNotifications` has been called, it registers the device automatically the first time a token arrives, and re-registers it when a user signs in, moving the registration from the guest identity to the authenticated one. See [Register a device](/[platform]/frontend/push-notifications/customer-profiles/register-device/) and [Guest and authenticated users](/[platform]/frontend/push-notifications/customer-profiles/guest-and-authenticated-users/). + +Add your own `onTokenReceived` listener only when you need the token value for something beyond registration, such as sending it to a system outside Amplify. diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/request-permissions/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/request-permissions/index.mdx new file mode 100644 index 00000000000..5ce3bc6ab72 --- /dev/null +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/request-permissions/index.mdx @@ -0,0 +1,88 @@ +import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; + +export const meta = { + title: 'Request permissions', + description: + 'Check and request permission to display push notifications on the device.', + platforms: ['react-native'] +}; + +export const getStaticPaths = async () => { + return getCustomStaticPath(meta.platforms); +}; + +export function getStaticProps(context) { + return { + props: { + platform: context.params.platform, + meta + } + }; +} + +Before a device can receive push notifications, the user must grant permission. Use `getPermissionStatus` and `requestPermissions` to check and request that permission. Call `initializePushNotifications()` first; see [Push notifications](/[platform]/frontend/push-notifications/customer-profiles/). + +## Check the current permission status + +Use `getPermissionStatus` to determine whether you need to request permission, and how: + +```ts +import { getPermissionStatus } from 'aws-amplify/push-notifications/customer-profiles'; + +const status = await getPermissionStatus(); +``` + +`getPermissionStatus` resolves to one of the following values: + +| Status | Meaning | +| --- | --- | +| `granted` | Permission has already been granted. No further action is needed. | +| `denied` | The user has denied permission. Requesting again will not show a system prompt; direct the user to their device settings instead. | +| `shouldRequest` | Permission has not been requested yet, so you can request it directly. | +| `shouldExplainThenRequest` | Explain why your application sends notifications before requesting permission. | + +## Request permission + +Use `requestPermissions` to show the system permission prompt: + +```ts +import { requestPermissions } from 'aws-amplify/push-notifications/customer-profiles'; + +const granted = await requestPermissions(); +``` + +`requestPermissions` resolves to a boolean indicating whether permission was granted. By default, it requests all supported permissions. Pass an object to request a subset: + +```ts +import { requestPermissions } from 'aws-amplify/push-notifications/customer-profiles'; + +await requestPermissions({ + alert: true, + badge: true, + sound: false +}); +``` + +`alert`, `badge`, and `sound` are each optional booleans. Android ignores these individual flags and requests a single combined permission. + +## Combine both APIs into a request flow + +Check the status before requesting, and use it to decide whether to show your own explanation first: + +```ts +import { + getPermissionStatus, + requestPermissions +} from 'aws-amplify/push-notifications/customer-profiles'; + +const status = await getPermissionStatus(); + +if (status === 'shouldRequest') { + await requestPermissions(); +} else if (status === 'shouldExplainThenRequest') { + // Explain why your application sends notifications, then request permission. + await requestPermissions(); +} +``` + +A token is issued to the device only after the user grants permission, so a device is not registered for push notifications until this flow completes. See [Manage the device token](/[platform]/frontend/push-notifications/customer-profiles/manage-device-token/). From 030a42dbc6df45b8f020d541322fee22d321f298 Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Wed, 29 Jul 2026 19:34:24 +0000 Subject: [PATCH 09/12] docs: address review feedback on Customer Profiles push notifications Addresses inline review feedback from @thisisabhash on #8613: - Remove the unused `connectcampaignsv` cspell entry. It was the only occurrence of the string in the repo (the definition itself), so it added a dictionary word no page uses. Spellcheck still passes. - Add a Layout test case for a Customer Profiles push-notifications child route (.../customer-profiles/register-device/). The existing guard matches without a trailing slash so child routes are already handled correctly; this locks in that behaviour so a future refactor to an exact-path check cannot silently reintroduce the Pinpoint EOL banner on these pages. - Link the push notifications backend overview to the new Pinpoint migration guide, since many readers arrive from Pinpoint push. Also merges origin/main to bring in the pinpoint-migration page (#8612) so the new link resolves, keeping both nav entries in directory.mjs. The platform-scoping feedback on the build-a-backend/notifications pages is left unchanged pending a product decision; the Customer Profiles push client provider requires @aws-amplify/react-native, so expanding these pages to Swift/Android would advertise a client path that does not exist. --- cspell.json | 1 - src/components/Layout/__tests__/Layout.test.tsx | 7 +++++++ .../add-aws-services/notifications/index.mdx | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/cspell.json b/cspell.json index 7dadf0f37a7..2e814113f0a 100644 --- a/cspell.json +++ b/cspell.json @@ -463,7 +463,6 @@ "confirmSignUp", "ConfirmSignUp", "confirmSignUpConfig", - "connectcampaignsv", "connectedform", "connectionWithKeyExamples.md", "constraintlayout", diff --git a/src/components/Layout/__tests__/Layout.test.tsx b/src/components/Layout/__tests__/Layout.test.tsx index 4c0efbdf674..cfa1e5c664c 100644 --- a/src/components/Layout/__tests__/Layout.test.tsx +++ b/src/components/Layout/__tests__/Layout.test.tsx @@ -127,6 +127,13 @@ describe('Layout', () => { expect(document.body.textContent).not.toContain('Amazon Pinpoint'); }); + it('is not rendered for the Customer Profiles push-notifications child pages', async () => { + routerState.asPath = + '/react/frontend/push-notifications/customer-profiles/register-device/'; + render(layoutComponent); + expect(document.body.textContent).not.toContain('Amazon Pinpoint'); + }); + it('is rendered for the legacy (gen1) push-notifications pages', async () => { routerState.asPath = '/gen1/react/build-a-backend/push-notifications/set-up-push-notifications/'; diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx index 608a0f40a1a..713994ff893 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx @@ -26,6 +26,8 @@ export function getStaticProps(context) { Amplify push notifications are backed by [Amazon Connect Customer Profiles](https://docs.aws.amazon.com/connect/latest/adminguide/customer-profiles.html). A Customer Profile holds the profile information for one person, keyed on a server-derived `principalId`. That person's registered push devices are stored separately, in a DynamoDB device store, associated to the same `principalId`; they are not embedded in the Customer Profile object. You send a notification by targeting profiles from an [Amazon Connect journey](https://docs.aws.amazon.com/connect/latest/adminguide/journeys.html), which calls into your Amplify backend to deliver the message to that person's devices. +If you are moving an existing application off the Pinpoint-backed push notifications feature, start with [Migrate from Pinpoint-backed features](/[platform]/build-a-backend/add-aws-services/pinpoint-migration/). + Add the resource to your backend with the `defineNotifications` construct: ```ts title="amplify/backend.ts" From 18c7ccb71e06e6bf7527cd6c436cf865f205e79d Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Wed, 29 Jul 2026 19:53:17 +0000 Subject: [PATCH 10/12] docs: expand notification backend pages to all platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses review feedback from @thisisabhash on #8613: the four build-a-backend/add-aws-services/notifications/ pages were scoped to platforms: ['react-native'], so a Swift, Android, Flutter, or web developer landing on them got a 404 with no other page describing how to provision the resource. Nothing on these pages is React Native specific — defineNotifications, the apns/fcm channel config, the qconnect CLI template authoring, and the domainName attach mode are backend-only and identical for every client. Expand all four to the canonical nine-platform set used by the other build-a-backend pages (109 pages use this exact set). Verified with a full production build: all 36 routes (9 platforms x 4 pages) prerender, and every link on these pages resolves on all nine platforms except the client-library links, which remain React Native only and are reported separately. --- .../notifications/author-message-templates/index.mdx | 12 +++++++++++- .../notifications/existing-resources/index.mdx | 12 +++++++++++- .../add-aws-services/notifications/index.mdx | 12 +++++++++++- .../notifications/set-up-notifications/index.mdx | 12 +++++++++++- 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx index e54ff6a39d7..eac5c911b3a 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx @@ -4,7 +4,17 @@ export const meta = { title: 'Author message templates', description: 'Create a push message template with the Amazon Q in Connect API and connect it to an Amazon Connect journey custom action.', - platforms: ['react-native'] + platforms: [ + 'javascript', + 'react-native', + 'swift', + 'android', + 'flutter', + 'angular', + 'nextjs', + 'react', + 'vue' + ] }; export const getStaticPaths = async () => { diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/existing-resources/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/existing-resources/index.mdx index 5329d0d5835..23be263ae17 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/existing-resources/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/existing-resources/index.mdx @@ -4,7 +4,17 @@ export const meta = { title: 'Use existing AWS resources', description: 'Attach your Amplify notifications resource to an Amazon Connect Customer Profiles domain that already exists.', - platforms: ['react-native'] + platforms: [ + 'javascript', + 'react-native', + 'swift', + 'android', + 'flutter', + 'angular', + 'nextjs', + 'react', + 'vue' + ] }; export const getStaticPaths = async () => { diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx index 713994ff893..edabc73ebb0 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx @@ -6,7 +6,17 @@ export const meta = { description: 'Send push notifications to your users with a backend powered by Amazon Connect Customer Profiles.', route: '/[platform]/build-a-backend/add-aws-services/notifications', - platforms: ['react-native'] + platforms: [ + 'javascript', + 'react-native', + 'swift', + 'android', + 'flutter', + 'angular', + 'nextjs', + 'react', + 'vue' + ] }; export const getStaticPaths = async () => { diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx index 58415d295ed..8974f2bd614 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx @@ -4,7 +4,17 @@ export const meta = { title: 'Set up notifications', description: 'Add push notifications to your Amplify backend with the defineNotifications construct, either by creating a new Amazon Connect instance or by attaching to an existing Customer Profiles domain.', - platforms: ['react-native'] + platforms: [ + 'javascript', + 'react-native', + 'swift', + 'android', + 'flutter', + 'angular', + 'nextjs', + 'react', + 'vue' + ] }; export const getStaticPaths = async () => { From 8ee56e3e18a5cfc12fce11bfb78466e6aef08842 Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Wed, 29 Jul 2026 20:15:24 +0000 Subject: [PATCH 11/12] docs: remove React Native only client links from notification backend pages The four build-a-backend/add-aws-services/notifications/ pages now build for all nine platforms, but they still linked to the push notifications client pages, which remain platforms: ['react-native']. Those links resolved only under /react-native/ and 404'd on the other eight platforms. - index.mdx: drop the trailing "To call the notification APIs from your application, see Push notifications" sentence. The preceding clause about amplify_outputs.json and Amplify.configure() is backend content and is kept. - set-up-notifications: drop the Push notifications bullet from "Next steps". The Author message templates bullet remains, so the section is still populated. - author-message-templates: reword the Attributes sentence to "including custom attributes set on the profile", removing the identifyUser link while keeping the sentence and the handlebars example it introduces. - author-message-templates: drop the "Next steps" section, whose only entry was the client link. The client pages stay registered in directory.mjs and still link back to these backend pages, so React Native readers keep both paths. Verified with a full production build: all 36 routes (9 platforms x 4 pages) prerender and zero references to /frontend/push-notifications/customer-profiles/ remain in any of them. --- .../notifications/author-message-templates/index.mdx | 6 +----- .../add-aws-services/notifications/index.mdx | 2 +- .../notifications/set-up-notifications/index.mdx | 1 - 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx index eac5c911b3a..e950ef967be 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx @@ -80,7 +80,7 @@ aws qconnect create-message-template-version \ ## Personalize the message -Templates support `{{Attributes.}}` variables, which resolve to the target Customer Profile's fields, including custom attributes you set with [`identifyUser`](/[platform]/frontend/push-notifications/customer-profiles/identify-user/): +Templates support `{{Attributes.}}` variables, which resolve to the target Customer Profile's fields, including custom attributes set on the profile: ```handlebars Hello {{Attributes.firstName}}, your order is on the way. @@ -98,7 +98,3 @@ Building the journey itself is done in the Amazon Connect console; only template 2. Add a **custom action** block and point it at the push-delivery Lambda function that Amplify deployed. 3. Set the block name to the exact `--name` value you gave the template above, including capitalization. 4. Publish the journey. - -## Next steps - -- [Push notifications](/[platform]/frontend/push-notifications/customer-profiles/): register devices and send profile information from your application. diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx index edabc73ebb0..8f3249e29d6 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx @@ -78,7 +78,7 @@ After a successful deployment, the invoke endpoint and region are written to the } ``` -Your frontend reads these values when you pass `amplify_outputs.json` to `Amplify.configure()`. To call the notification APIs from your application, see [Push notifications](/[platform]/frontend/push-notifications/customer-profiles/). +Your frontend reads these values when you pass `amplify_outputs.json` to `Amplify.configure()`. diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx index 8974f2bd614..b07fdfcc6ed 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx @@ -191,4 +191,3 @@ When the deployment finishes, the invoke endpoint and region are written to `amp ## Next steps - [Author message templates](/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/): create the push message content in Amazon Q in Connect. -- [Push notifications](/[platform]/frontend/push-notifications/customer-profiles/): call the notification APIs from your application. From 59dc886b119c093f9014faa1fcc2d35d3edf2161 Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Thu, 30 Jul 2026 09:38:59 +0000 Subject: [PATCH 12/12] docs: bound the Pinpoint banner carve-out and align markdown tables Addresses review feedback from @osama-rizk on #8613. Layout.tsx: the Customer Profiles carve-out matched the unbounded substring '/push-notifications/customer-profiles', so a future sibling route such as '/push-notifications/customer-profiles-legacy/' would also have had the Pinpoint EOL banner silently suppressed. Anchor the match with a trailing slash. next.config sets trailingSlash: true, so both the overview route and its child routes still match. Layout.test.tsx: add a positive case asserting the banner still renders for a Gen 2 push-notifications route that is not Customer Profiles. This pins the over-matching boundary that the previous positive tests (gen1 and analytics) did not cover. Verified the test is meaningful: it fails against the old unbounded match and passes with the anchored one. interact-with-notifications: align the two markdown tables. Cell text is unchanged, padding only. No content or platform changes in this commit. The platform scope of the client pages is left as is pending confirmation. --- src/components/Layout/Layout.tsx | 2 +- src/components/Layout/__tests__/Layout.test.tsx | 7 +++++++ .../interact-with-notifications/index.mdx | 16 ++++++++-------- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/components/Layout/Layout.tsx b/src/components/Layout/Layout.tsx index 9db7bc436c2..e40e0bc155c 100644 --- a/src/components/Layout/Layout.tsx +++ b/src/components/Layout/Layout.tsx @@ -398,7 +398,7 @@ export const Layout = ({ )} {((asPathWithNoHash.includes('/push-notifications/') && !asPathWithNoHash.includes( - '/push-notifications/customer-profiles' + '/push-notifications/customer-profiles/' )) || asPathWithNoHash.includes('/analytics/') || asPathWithNoHash.includes('/in-app-messaging/')) && diff --git a/src/components/Layout/__tests__/Layout.test.tsx b/src/components/Layout/__tests__/Layout.test.tsx index cfa1e5c664c..c4d6ce802c4 100644 --- a/src/components/Layout/__tests__/Layout.test.tsx +++ b/src/components/Layout/__tests__/Layout.test.tsx @@ -134,6 +134,13 @@ describe('Layout', () => { expect(document.body.textContent).not.toContain('Amazon Pinpoint'); }); + it('is rendered for a non-Customer-Profiles push-notifications sibling route', async () => { + routerState.asPath = + '/react/frontend/push-notifications/customer-profiles-legacy/'; + render(layoutComponent); + expect(document.body.textContent).toContain('Amazon Pinpoint'); + }); + it('is rendered for the legacy (gen1) push-notifications pages', async () => { routerState.asPath = '/gen1/react/build-a-backend/push-notifications/set-up-push-notifications/'; diff --git a/src/pages/[platform]/frontend/push-notifications/customer-profiles/interact-with-notifications/index.mdx b/src/pages/[platform]/frontend/push-notifications/customer-profiles/interact-with-notifications/index.mdx index b91904f7cdf..6275f013f07 100644 --- a/src/pages/[platform]/frontend/push-notifications/customer-profiles/interact-with-notifications/index.mdx +++ b/src/pages/[platform]/frontend/push-notifications/customer-profiles/interact-with-notifications/index.mdx @@ -28,10 +28,10 @@ Your application can be in one of three states when a notification arrives or is ## Respond to a notification being received -| App state | Handle with | -| ---------------------------- | ------------------------------------- | -| Foreground | `onNotificationReceivedInForeground` | -| Background or terminated | `onNotificationReceivedInBackground` | +| App state | Handle with | +| ------------------------ | ------------------------------------ | +| Foreground | `onNotificationReceivedInForeground` | +| Background or terminated | `onNotificationReceivedInBackground` | ### Received in the foreground @@ -89,10 +89,10 @@ listener.remove(); ## Respond to a notification being opened -| App state | Handle with | -| -------------------------- | -------------------------- | -| Foreground or background | `onNotificationOpened` | -| Terminated | `getLaunchNotification` | +| App state | Handle with | +| ------------------------ | ----------------------- | +| Foreground or background | `onNotificationOpened` | +| Terminated | `getLaunchNotification` | ### Opened from the foreground or background