diff --git a/cspell.json b/cspell.json
index c43dce26b34..33d2df8ef0c 100644
--- a/cspell.json
+++ b/cspell.json
@@ -2,20 +2,6 @@
"version": "0.1",
"language": "en",
"words": [
- "_",
- "_blank",
- "_Granting",
- "_Identity",
- "_new",
- "_or_",
- "_userauth.auth_fail",
- "_userauth.sign_in",
- "_userauth.sign_up",
- "agentic",
- "awslabs",
- "@aws-amplify/auth",
- "@aws-amplify/core",
- "@aws-amplify/storage",
"*.js",
"0.75rem",
"0.81rem",
@@ -36,16 +22,28 @@
"7da1ff",
"8.11.x",
"8.x",
+ "@aws-amplify/auth",
+ "@aws-amplify/core",
+ "@aws-amplify/storage",
+ "_",
+ "_blank",
+ "_Granting",
+ "_Identity",
+ "_new",
+ "_or_",
+ "_userauth.auth_fail",
+ "_userauth.sign_in",
+ "_userauth.sign_up",
"a_b",
"aar",
- "ABCDEXXXXX",
"abcdefghi",
+ "ABCDEXXXXX",
"abort",
"AbortIncompleteMultipartUpload",
"accesskey",
"accessKey",
- "ACCESSKEYID",
"ACCESSKEY",
+ "ACCESSKEYID",
"AccessToken",
"AccountRepresentative",
"ACLs",
@@ -55,15 +53,18 @@
"addfunction",
"addgraphqldatasource",
"addingfunction",
+ "addingfunction",
"adhere",
+ "adminui",
+ "agentic",
+ "AIRPLANETABLE",
"albumVisit",
- "ampx",
"Alexa",
"Algolia",
"AllowedOrigin",
"allowfullscreen",
- "AllPosts.jsx",
"allPosts",
+ "AllPosts.jsx",
"allprojects",
"ALPN",
"AMAZON_COGNITO_USER_POOLS",
@@ -74,40 +75,48 @@
"AmazonPersonalizeProvider",
"AmazonS3Client",
"Amplif",
- "ampx",
"amplifiedtodo",
- "AMPLIFYCLI",
+ "Amplify",
+ "Amplify's",
"amplify-CLI",
- "amplifymapview",
"amplify-provider-awscloudformation",
"amplify-s3-album",
"amplify-totp-setup",
"amplify-vue",
- "Amplify",
- "Amplify's",
- "amplify’s",
"AmplifyAngularModule",
- "amplifyapp.com",
"amplifyapp",
+ "amplifyapp.com",
"amplifybackend",
- "amplifyhosting",
- "amplifyconfiguration.json",
+ "AMPLIFYCLI",
+ "amplifyconfig",
"amplifyconfiguration",
+ "amplifyconfiguration.json",
"AmplifyEventBus",
"amplifyframework",
+ "amplifyhosting",
"amplifyjsapp",
+ "amplifyjsapp",
+ "AMPLIFYLAYERGUIDE",
+ "amplifymapview",
"amplifyMeta.json",
"AmplifyModules",
"amplifyoutputs",
"AmplifyPlugin",
"amplifyPush",
"amplifyrc",
+ "AMPLIFYRULES",
"amplifyService",
"AmplifyService",
"AmplifyTheme.js",
"amplifytools",
- "amplifyxc.config",
"amplifyxc",
+ "amplifyxc.config",
+ "amplify\u2019s",
+ "Ampligram",
+ "ampligram",
+ "ampx",
+ "ampx",
+ "ampx",
"AMQJS",
"analytics",
"android.app.Activity",
@@ -118,11 +127,12 @@
"angular-cli",
"anonymized",
"AnyPublisher",
- "API_KEY",
- "API.swift",
- "API's",
"api",
+ "API's",
+ "API.swift",
+ "API_KEY",
"apigateway",
+ "apigatewayv",
"apiId",
"apiKey",
"APIKeyExpirationEpoch",
@@ -132,40 +142,45 @@
"apiwithkey",
"APNs",
"apolloapi",
+ "apolloapi",
"apollographql",
"apolloserver",
- "app_id",
+ "apolloserver",
"app.component.html",
"app.component.ts",
"app.js",
"app.module.ts",
"App.vue",
+ "app_id",
"AppClientId",
"AppClientIDWeb",
"AppClientSecret",
"appcompat",
"APPDATA",
+ "AppDelegate",
"AppDelegate.m",
"AppDelegate.swift",
- "AppDelegate",
"appid",
- "apigatewayv",
"appleid",
"appName.app",
"AppStore",
"Appsync",
"AppSync",
"AppSyncApiName",
+ "architected",
"architecting",
"Arial",
"Arial",
"arm64-v8a",
- "armeabi-v7a",
"armeabi",
+ "armeabi-v7a",
"arn",
"ARNs",
"arraybuffer",
"artifactID",
+ "ASIAVJKIAM",
+ "assetlinks",
+ "astro",
"async",
"asyncawait",
"AsyncStorage",
@@ -174,18 +189,16 @@
"Auth.currentAuthenticatedUser",
"Auth.federatedSignIn",
"Auth0",
+ "Authadmin",
"Authauthenticated",
- "Authunauthenticate",
+ "AUTHCONFIG",
"authcurrentsession",
- "authverifycurrentuserattribute",
- "authverifycurrentuserattributesubmit",
"authcurrentusercredentials",
- "authgetpreferredmfa",
- "authuserattributes",
"authData",
- "Authenticator's",
"Authenticator",
+ "Authenticator's",
"AuthenticatorActivity",
+ "authgetpreferredmfa",
"AuthGuardService",
"authMode",
"authmycognitoresource",
@@ -193,24 +206,33 @@
"authorizer",
"Authorizer",
"authorizers",
+ "authreadonly",
"authState",
"authtype",
+ "Authunauthenticate",
+ "authuserattributes",
+ "authverifycurrentuserattribute",
+ "authverifycurrentuserattributesubmit",
"AuthZ",
+ "autobranch",
+ "autoclosure",
+ "autodetection",
"autogenerated",
+ "autoKsuid",
"autolinking",
+ "autologin",
"Automerge",
"autoplay",
"autopopulate",
"autopopulated",
"autoscaling",
"autotrack",
- "aws_bots_config.name",
- "AWS_IAM",
+ "aws",
+ "aws-amplify",
"aws-amplify-angular",
- "aws-amplify-react-native",
"aws-amplify-react",
+ "aws-amplify-react-native",
"aws-amplify-vue",
- "aws-amplify",
"aws-android-sdk-apigateway-core",
"aws-android-sdk-auth-core",
"aws-android-sdk-auth-facebook",
@@ -222,9 +244,9 @@
"aws-android-sdk-cognitoauth",
"aws-android-sdk-cognitoidentityprovider",
"aws-android-sdk-core",
+ "aws-android-sdk-ddb",
"aws-android-sdk-ddb-document",
"aws-android-sdk-ddb-mapper",
- "aws-android-sdk-ddb",
"aws-android-sdk-ec2",
"aws-android-sdk-elb",
"aws-android-sdk-iot",
@@ -249,8 +271,8 @@
"aws-mobile-appsync-sdk-ios",
"aws-sdk-ios",
"aws.cognito.signin.user.admin",
- "aws",
- "Authadmin",
+ "aws_bots_config.name",
+ "AWS_IAM",
"AWSAPI",
"AWSAPIGateway",
"AWSAPIPlugin",
@@ -260,6 +282,7 @@
"AWSAuthCore",
"AWSAuthUI",
"AWSAutoScaling",
+ "awscliv",
"awscloudformation",
"AWSCLOUDFORMATIONCONFIG",
"AWSCLOUDFORMATIONCONFIG",
@@ -271,8 +294,8 @@
"AWSComprehend",
"awsconfig",
"awsconfig",
- "awsconfiguration.json",
"AWSConfiguration",
+ "awsconfiguration.json",
"AWSConnect",
"AWSCore",
"AWSDD",
@@ -296,15 +319,16 @@
"AWSKinesisVideo",
"AWSKinesisVideoArchivedMedia",
"AWSKMS",
+ "awslabs",
"AWSLambda",
"AWSLex",
"AWSLogs",
"AWSMachineLearning",
"awsmobile",
+ "AWSMobileClient",
"AWSMobileClient.default",
"AWSMobileClient.getInstance",
"AWSMobileClient.sharedInstance",
- "AWSMobileClient",
"AWSOIDC",
"AWSPinpoint",
"AWSPinpointAnalyticsPlugin",
@@ -312,15 +336,17 @@
"AWSRekognition",
"AWSS",
"AWSS3ServerSideEncryption",
- "AWSS3TransferUtility.s3TransferUtility",
"AWSS3TransferUtility",
+ "AWSS3TransferUtility.s3TransferUtility",
"AWSSageMakerRuntime",
+ "AWSSDK",
+ "AWSSDKHTTP",
"AWSSES",
"AWSSimpleDB",
"AWSSNS",
"AWSSQS",
- "AWSSTS",
"AWSStaticCredentialsProvider",
+ "AWSSTS",
"AWSTask",
"AWSTextract",
"AWSTranscribe",
@@ -329,10 +355,10 @@
"AWSURL",
"AWSUserPoolsSignIn",
"Axios",
- "backend-configs",
- "backendstack",
"backend",
+ "backend-configs",
"backends",
+ "backendstack",
"backgroundColor",
"backgrounding",
"backoff",
@@ -354,8 +380,11 @@
"bestpractices",
"betatest",
"bidirectionality",
+ "bindui",
+ "birthdate",
"birthdate",
"Bitbucket",
+ "bitnami",
"bizcorprole",
"BizDev",
"blacklist",
@@ -363,14 +392,16 @@
"boilerplates",
"boolean",
"boto",
+ "boto",
"botTitle",
"BRANCHNAME",
- "BROWSABLE",
"Brandel",
+ "BROWSABLE",
"bucketName",
"build.gradle",
"buildscript",
"buildSync",
+ "buildui",
"Bundler",
"byCustomerByStatusByDate",
"byname",
@@ -381,15 +412,16 @@
"c4c4c4",
"cacheable",
"Cactuss",
- "callout--info",
"callout",
"callout",
+ "callout--info",
+ "callouts",
"camelCase",
"canCancel",
"cancelAllWithType",
"cancelHandler",
- "CannedAccessControlList.PublicRead",
"CannedAccessControlList",
+ "CannedAccessControlList.PublicRead",
"cantguessthis",
"capacityInBytes",
"Capitan",
@@ -398,6 +430,7 @@
"CAPTCHAs",
"Cartfile",
"cfdoc",
+ "CHALLENGEANSWER",
"ChallengeName",
"chatbot",
"Chatbot",
@@ -409,43 +442,47 @@
"CHLG",
"cicd",
"CircleCI",
+ "classname",
"classpath",
"clearComplete",
"cleartext",
- "CLI's",
"cli",
+ "CLI's",
"Client.swift",
"ClientId",
"clientMetadata",
"ClientMetadata",
+ "clijson",
"cloudform",
- "cloudformation-template",
"CloudFormation",
+ "cloudformation-template",
"Cloudfront",
"CloudFront",
"CloudWatch",
+ "cloudwatchlogs",
+ "CNAME",
"CocoaLumberjack",
"Cocoapods",
"CocoaPods",
"CodeCommit",
"codegen",
"CODEGENJOB",
- "COGNITO_USERPOOL_ID",
- "Cognito's",
"cognito",
"Cognito",
"Cognito",
+ "Cognito's",
+ "COGNITO_USERPOOL_ID",
"cognitoabcd",
"cognitoauth",
"cognitoauth",
"CognitoIdentity",
"cognitoidentityprovider",
"CognitoUserPool",
+ "com.amazonaws",
"com.amazonaws.mobile.auth.ui.SignInUI",
"com.amazonaws.mobile.client.AWSMobileClient",
"com.amazonaws.mobile.client.AWSStartupHandler",
"com.amazonaws.mobile.client.AWSStartupResult",
- "com.amazonaws",
"com.myProjectName",
"Comment.todo",
"Compat",
@@ -457,18 +494,21 @@
"configLevel",
"configs",
"configureaccess",
+ "confirmingsignincustomflow",
"confirmSignIn",
"ConfirmSignIn",
"confirmSignInConfig",
"confirmSignUp",
"ConfirmSignUp",
"confirmSignUpConfig",
+ "confirmsignupcustomflow",
"connectedform",
"connectionWithKeyExamples.md",
"constraintlayout",
"contactapi",
"containertag",
"continueWith",
+ "conver",
"cordova",
"CoreML",
"Corp's",
@@ -484,22 +524,27 @@
"CRUD",
"CRUDL",
"Cryptocurrency",
+ "Cryptocurrency",
+ "cryptofunction",
"cryptofunction",
"CSRF",
"css",
"Ctrl-c",
- "customauth",
"CUSTOM_AUTH",
+ "customauth",
+ "customcf",
"customerEmail",
+ "customerprofiles",
"customizable",
"customtabs",
"customui",
- "conver",
"dabit",
"dataaccess",
"dataacess",
+ "databind",
"databinding",
"datalogconfig",
+ "datamodel",
"dataset",
"datasource",
"DataSource",
@@ -508,6 +553,8 @@
"DataStore",
"dd3f5b",
"deddd",
+ "dedup",
+ "Dedup",
"deduped",
"deeplink",
"Deeplink",
@@ -536,11 +583,15 @@
"developerpreviewjs",
"devguide",
"devpreview",
+ "Dexie",
+ "dexie",
"dflt",
"Didfinishlaunchingwithoptions",
+ "disambiguator",
"displayMode",
"displayOrder",
"dists",
+ "Dockerizing",
"DocSet",
"DocSets",
"Donef",
@@ -548,6 +599,8 @@
"dotenvx",
"downcasting",
"dropdown",
+ "duckdb",
+ "dynamicquery",
"dynamoDB",
"DynamoDB",
"DynamoDBBillingMode",
@@ -558,39 +611,51 @@
"e88b01",
"echofunction",
"ecommerce",
+ "editorgroupaccess",
"Elasticsearch",
"ElasticSearch",
"ElasticsearchEBSVolumeGB",
"ElasticsearchInstanceCount",
"ElasticsearchInstanceType",
"ElasticsearchStreamingFunctionName",
- "electron.js",
"electron",
+ "electron.js",
"email_verified",
"emailpassword",
+ "enabledMfas",
"endraw",
+ "endregion",
"enqueued",
+ "Entra",
"entryComponent",
"entryComponents",
+ "entrypoint",
+ "Entrypoint",
"Entypo",
"enum",
+ "enumlabel",
+ "enumtypid",
"env",
"ENVNAME",
+ "envs",
+ "ERESOLVE",
+ "Ersi",
+ "esac",
"esarn",
"escapehatch",
"espaguetis",
"event.prev.result",
- "EventBus",
"eventbridge",
+ "EventBus",
+ "eventhandling",
"eventType",
"eventValue",
"execa",
- "eventhandling",
"execute",
"expectedVersion",
- "Entra",
- "IDSAML",
"FACEBOOK_TOKEN_HERE",
+ "Fargate",
+ "favoritefood",
"fb1231231231232123123",
"fbapi",
"fbauth",
@@ -600,38 +665,25 @@
"ff9900",
"ffac31",
"ffffff",
- "Figma",
- "Figma's",
- "figma",
- "fileuploader",
- "architected",
- "newsfeeds",
- "textareas",
- "figmatocode",
- "databind",
- "buildui",
- "dynamicquery",
- "uibuilder",
- "staticbind",
- "getcomponent",
- "sqft",
- "Ampligram",
- "ampligram",
- "classname",
- "favoritefood",
"fieldName",
+ "Fieldsdk",
"Fieldzoh",
"Fieldzwu",
- "Fieldsdk",
+ "Figma",
+ "figma",
+ "Figma's",
+ "figmatocode",
+ "fileb",
"filename",
"Filepath",
"Filepath",
+ "fileuploader",
"findViewById",
"firebaseconsole",
"Firehose",
+ "Flexboxes",
"FLIGHTSTATS",
"flipside",
- "Flexboxes",
"forgotPassword",
"ForgotPassword",
"forgotPasswordConfig",
@@ -639,6 +691,7 @@
"formapi",
"formbuilder",
"formfunction",
+ "formfunction",
"formtable",
"FORMTABLE",
"frontend",
@@ -647,20 +700,27 @@
"fullname",
"Gapi",
"ge",
+ "generatemodelsforlazyloadandcustomselectionset",
"geo_point",
"Geocode",
+ "Geocodes",
"geofence",
"Geofence",
+ "geofence",
"Geofences",
+ "geofences",
"Geofencing",
"geolocation",
"GEOMFROMTEXT",
"geospatial",
+ "geospatial",
"getAllKeys",
"getApplicationContext",
"getCacheCurSize",
+ "getcomponent",
"getCredentials",
"GETCURRENTUSER",
+ "GETCURRENTUSER",
"getDeliveryMedium",
"getIdentityId",
"getIdToken",
@@ -668,37 +728,42 @@
"getItem",
"getitems",
"getJWTToken",
- "GetPost.jsx",
+ "getmytodofunction",
"getPost",
+ "GetPost.jsx",
"getTodo",
"getTokens",
"getUsername",
- "getmytodofunction",
+ "gitflow",
"github",
"gitignore",
"GitLab",
"global.scss",
- "gluegun's",
"gluegun",
+ "gluegun's",
"goapi",
+ "GOARCH",
"google.gms",
"googleusercontent",
"gqlcompile",
"gqlfunc",
"gqlimages",
+ "gqlimages",
+ "gqllambda",
"gqllambda",
"gqls",
+ "gqls",
+ "gqlv",
"gradle",
- "gradlew",
"Gradle",
+ "gradlew",
"GraphiQL",
"GRAPHQENDPOINT",
- "graphql_endpoint_iam_region",
"graphql",
"Graphql",
"GraphQL",
- "GRAPHQLTRANSFORMER",
"graphql#17-data-access-patterns",
+ "graphql_endpoint_iam_region",
"graphqlapi",
"GRAPHQLAPIENDPOINTOUTPUT",
"GRAPHQLAPIIDOUTPUT",
@@ -706,6 +771,8 @@
"graphqlconfig",
"GRAPHQLENDPOINT",
"GraphQLOperations",
+ "graphqls",
+ "GRAPHQLTRANSFORMER",
"greetingfunction",
"gridsome",
"Gridsome",
@@ -723,6 +790,7 @@
"HasMany",
"headlessaccesskeyid",
"headlesssecrectaccesskey",
+ "healthcheck",
"Helvetica",
"Helvetica",
"Hoc",
@@ -732,7 +800,9 @@
"home.page.ts",
"HostedUI",
"Hosting's",
+ "hotswap",
"html",
+ "HTTPAPI",
"https",
"HTTPURL",
"i.e.",
@@ -745,23 +815,33 @@
"IdentityManager",
"IDENTITYPOOL",
"IdentityProviders.FACEBOOK.toString",
+ "identitystore",
"IdP",
"idpresponse",
+ "IDSAML",
"IdToken",
"iframe",
+ "imagedefinitions",
"ImageView",
+ "immer",
+ "importauth",
"IN_TRANSIT",
"inappbrowser",
+ "inappbrowser",
"inappmessaging",
- "Iniciar",
"index.html",
"index.js",
+ "indexdef",
"IndexedDB",
+ "indexname",
"Info.plist",
+ "infowindow",
+ "Iniciar",
"initapi",
"inout",
"inputs.mdx",
"installable",
+ "instanceof",
"Intelli",
"interceptApplication",
"Inventorys",
@@ -776,6 +856,7 @@
"isSignedIn",
"item.class.ts",
"itemMaxSize",
+ "jamba",
"javascript",
"javax",
"jcenter",
@@ -797,13 +878,17 @@
"keystore",
"kibana",
"kill",
- "kinesisfirehose",
"Kinesis",
+ "kinesisfirehose",
"KinesisFirehoseRecorder",
"KinesisRecorder",
"kinesisvideo",
+ "Kiro",
+ "kiro",
"KMS-generated",
+ "knowledgebases",
"Kotlin",
+ "kotlinx",
"Kylo",
"Lambd",
"Lambda",
@@ -813,11 +898,14 @@
"lateinit",
"le",
"libglib",
+ "Libre's",
"libs",
"libsecret",
"lifecycle",
"lifecycles",
"lightgray",
+ "lightgray",
+ "linestring",
"Linkification",
"list.item.modal.html",
"list.item.modal.ts",
@@ -837,30 +925,39 @@
"Log.d",
"Log.i",
"Logcat",
+ "loggingconstraints",
"logic_protocol_scheme",
"LoginWithAmazon",
"logoImage",
+ "longblob",
+ "longtext",
"lt",
"machinelearning",
"macOS",
"main.js",
"main.ts",
- "MainActivity.java",
"MainActivity",
+ "MainActivity.java",
"makeToast",
"manageusers",
"mangiare",
+ "manylinux",
+ "manytomany",
"mapbox",
"mapboxsdk",
+ "maplibre",
"maplibregl",
"master",
"md",
"mdash",
"MediaAutoTrack",
+ "mediumblob",
+ "mediumint",
+ "mediumtext",
+ "menudetaileditors",
"metadata",
"mfaDescription",
"mfaTypes",
- "enabledMfas",
"MiB",
"middleware",
"Millis",
@@ -879,9 +976,6 @@
"mouseover",
"mqttv",
"msg",
- "mybookapi",
- "mysupersecurepassword",
- "myusername",
"Mult",
"multenvtest",
"multiauth",
@@ -890,6 +984,7 @@
"Multifactor",
"multipart",
"multiPartConcurrencyLimit",
+ "multirepo",
"multishells",
"Mutation.createTodo",
"mutationName",
@@ -899,55 +994,66 @@
"myAmplifyProject",
"myangularapp",
"myapi",
- "reactamplified",
- "region",
- "myapp.xcodeproj",
"myapp",
+ "myapp.xcodeproj",
"myapplication",
+ "myawesomekey",
+ "mybookapi",
"mybucket",
"mycognitoresource",
"mycoolpassword",
+ "mydb",
"mydev",
"myendpoint",
"myenvname",
+ "myfunction",
"myimage",
"mykey",
"mylambda",
- "mynextapp",
"mynewpassword",
+ "mynextapp",
+ "mynextapp",
"myoldpassword",
- "myPrivatePrefix,",
"myprivateprefix",
- "myPublicPrefix,",
+ "myPrivatePrefix,",
+ "myproject",
"mypublicprefix",
+ "myPublicPrefix,",
"MYRESOURCENAME",
"mysandbox",
"mysecretproject",
"mysecurerandompassword",
"MySQL",
"MYSTORAGE",
+ "MYSTORAGE",
"mystream",
+ "mysupersecurepassword",
"mytestproject",
"mytrigger",
- "netinfo",
+ "myusername",
+ "myvalue",
"NATIVECLIENT",
+ "netinfo",
"Neue",
"Neue",
"NEW_PASSWORD_REQUIRED",
"newHire",
"newimage",
- "NextActivity.class",
+ "newsfeeds",
"NextActivity",
+ "NextActivity.class",
"nextActivityClass",
+ "nextamplified",
+ "nextamplifygen",
"nextjs",
"Nextjs",
"nextsteps",
"ng-recaptcha",
"Nkjd",
- "node_modules",
- "Node.js.",
"node.js",
"Node.js",
+ "Node.js.",
+ "node_modules",
"nodeapi",
"NodeJS",
"nodownload",
@@ -955,6 +1061,7 @@
"noMfaDescription",
"non-SRP",
"Nonnull",
+ "norpc",
"NoSQL",
"NoteContent",
"NoteId",
@@ -962,9 +1069,10 @@
"notificationclick",
"npm",
"npx",
- "nsswamin",
"NSAllowsLocalNetworking",
"NSData",
+ "nspname",
+ "nsswamin",
"NSURL",
"NSURLSession",
"NSUUID",
@@ -972,8 +1080,8 @@
"Nuxt",
"oauth",
"OAuth",
- "OAuth2.0",
"oauth2",
+ "OAuth2.0",
"OBJC",
"OBJECT_KEY",
"observeQuery",
@@ -985,15 +1093,17 @@
"onCreate",
"onDelete",
"OneGraph",
+ "onetomany",
+ "Onetoone",
"onHubCapsule",
"OnInit",
"onPick",
"onResult",
"onUpdate",
"onvalidate",
- "OPENID_CONNECT",
"openid",
"OpenID",
+ "OPENID_CONNECT",
"OpenSearch",
"opensearchservice",
"openssl",
@@ -1003,22 +1113,27 @@
"Outputs.RootURL.Value",
"ownerField",
"ownerfields",
+ "ownersaccess",
"p12",
"paho",
"Pancho",
"parameter.json",
"parameterization",
"parameters.json",
+ "parametersjson",
"parcelable",
"passin",
"passwordless",
"pausable",
"PAY_PER_REQUEST",
"Permission.Read",
+ "Persistor",
+ "persistor",
"phone_number",
"phonenumber",
"PhotoPicker",
"piace",
+ "Pinia",
"PinpointAnalytics",
"pinpointappid",
"PinpointFunctionsOutputs",
@@ -1026,6 +1141,7 @@
"PinpointTargeting",
"pipenv",
"pipenv's",
+ "Pipfile",
"PITR",
"pkey",
"placeindex",
@@ -1046,15 +1162,18 @@
"postname",
"posts.graphql",
"PostsTable",
+ "posttags",
"posttitle",
"powertools",
+ "Powertools",
+ "Pre",
"pre-annotated",
"pre-built",
"pre-created",
"pre-defined",
"pre-populated",
"pre-signed",
- "Pre",
+ "preconfigured",
"prepend",
"prepended",
"prepper",
@@ -1062,8 +1181,10 @@
"presigned",
"Presigning",
"PreSignUp",
+ "Pressable",
"prev",
"printLn",
+ "privatesaccess",
"ProcessLifeCycle",
"programmatically",
"Project.team",
@@ -1072,12 +1193,13 @@
"Provisioining",
"proxied",
"pseudocode",
+ "psql",
"publicRead",
"pubspec",
+ "pubspec",
"pubsub",
"Pubsub",
"PubSub",
- "Powertools",
"PUSHINFOPROVIDER",
"PushListenerService",
"pushnotification",
@@ -1090,22 +1212,23 @@
"putVocabularies",
"pythonapi",
"qafh",
- "QLAPINONEDS",
"QLAPI",
+ "QLAPINONEDS",
"QLID",
"qrcode",
"Query.commentsForTodo",
"Query.echo.req.vtl",
"Query.echo.res.vtl",
"Query.getComment",
- "Query.getTodo.comments",
"Query.getTodo",
+ "Query.getTodo.comments",
"Query.listComments",
"Query.listTodos",
"Query.nearbyTodos",
"Query.searchTodos",
"queryField",
"QueryField",
+ "querytransfers",
"queueing",
"quickstart",
"Quokka",
@@ -1120,25 +1243,34 @@
"R.layout.activity_authenticator",
"react-google-recaptcha",
"react-native-fs",
+ "reactamplified",
"REACTCONFIG",
"reactnative",
"realtime",
+ "rebranded",
"reCaptcha",
"recordcache",
"RecyclerView",
- "retryable",
"redirect_to",
"referrerpolicy",
"refetches",
+ "refreshable",
+ "region",
"Registrarse",
- "Regístrate",
+ "Reg\u00edstrate",
"Rehydrated",
+ "rehype",
"Rekognition",
+ "remoteconfig",
+ "remotelogging",
+ "remoteloggingconstraints",
"removeItem",
"repo",
"reponame",
+ "reponame",
"requireNewPassword",
"resendSignUp",
+ "resettingpassword",
"resolver's",
"resourcename",
"Resources.S3Bucket.Properties.BucketName",
@@ -1146,26 +1278,28 @@
"RESTAPI",
"RESTENDPOINT",
"resubscription",
+ "retryable",
"retryLimit",
"returnValue",
"rgba",
"richard",
"rnamplify",
+ "roadmap",
"RoleName",
+ "ROOT_QUERY",
"ROOT_QUERY.getPost",
"ROOT_QUERY.listPosts",
- "ROOT_QUERY",
"rootstack",
"Route53",
"runOnUiThread",
- "runtime's",
"runtime",
+ "runtime's",
"runtimes",
"rxbindings",
"RxJava",
"S'inscrire",
- "s3.amazonaws.com",
"s3",
+ "s3.amazonaws.com",
"s3aeaffb53",
"S3Album",
"s3AlbumConfig",
@@ -1180,16 +1314,17 @@
"Salli",
"SAML",
"savedInstanceState",
+ "savegeofences",
"sceneapi",
+ "schema's",
"schema.graphql",
"schema.json",
- "schema's",
"schemas",
"screencap",
"screencast",
"scrollview",
- "SDK's",
"sdk",
+ "SDK's",
"SDKs",
"SDLC",
"searchable",
@@ -1197,9 +1332,10 @@
"searchQueryField",
"secretkey",
"secretKey",
+ "secretsmanager",
"serverless",
"ServiceWorker",
- "Sesión",
+ "Sesi\u00f3n",
"SessionStorage",
"setContentView",
"setItem",
@@ -1213,49 +1349,59 @@
"signin",
"signInChallengeResponse",
"signInConfig",
- "signInResult.getSignInState",
- "signInResult.GetSignInState",
+ "signingup",
"signInResult",
"SignInResult",
+ "signInResult.getSignInState",
+ "signInResult.GetSignInState",
"SignInUIConfiguration.builder",
"SignInUIOptions.builder",
"signout",
"signOutButton",
"signup",
- "signUpConfig.signUpFields",
"signUpConfig",
+ "signUpConfig.signUpFields",
"signUpFields",
- "signUpResult.getConfirmationState",
- "signUpResult.getUserCodeDeliveryDetails",
"signUpResult",
"SignUpResult",
+ "signUpResult.getConfirmationState",
+ "signUpResult.getUserCodeDeliveryDetails",
"signups",
"sitekey",
+ "SIWA",
"sjgub",
"sjqub",
"slave",
- "SMSMFA",
+ "smallint",
"SMS_MFA",
"smsDescription",
- "someuser",
+ "SMSMFA",
+ "snapcraft",
+ "snapshotted",
+ "snstopic",
+ "snstopicemailsub",
"softwareupdate",
+ "someuser",
"spinner.js",
+ "sqft",
"SQLite",
"src",
"SRID",
- "snstopic",
- "snstopicemailsub",
"SSECustomerAlgorithm",
"SSECustomerKey",
"SSECustomerKeyMD5",
"SSEKMS",
"ssn",
+ "startbuild",
+ "Stateful",
"Stateful",
+ "staticbind",
"status#createdAt",
"statusCreatedAt",
"Storage.get",
"Storage.put",
"storagebucketname",
+ "STORAGECONFIG",
"storagedemo",
"storageOptions",
"storagepath",
@@ -1280,6 +1426,7 @@
"super.onCreate",
"superset",
"suppressschemamigrationprompt",
+ "swiftpm",
"SwiftUI",
"syncable",
"syncConfiguration",
@@ -1293,25 +1440,30 @@
"tanstack",
"task.result",
"taskIdentifier",
- "template.json",
"TEAMID",
+ "template.json",
"testappa",
"testtable",
+ "testtable",
"testtrigger",
+ "textareas",
"textEnabled",
"Textract",
- "textView.setText",
"textView",
"TextView",
+ "textView.setText",
"theListFunction",
"theming",
"theming",
"timeoutIntervalForResource",
"TimeWatched",
+ "tinyblob",
+ "tinyint",
+ "tinytext",
"TMQTT",
"todelete",
- "Todo.comments",
"todo",
+ "Todo.comments",
"todoapp",
"todoitem",
"todoitems",
@@ -1321,9 +1473,9 @@
"Todotable",
"tokenInstructions",
"toolchain",
- "totp-setup",
"totp",
"TOTP",
+ "totp-setup",
"totpDescription",
"TransferNetworkConnectionType",
"TransferService",
@@ -1331,8 +1483,8 @@
"TransferThreadPoolSize",
"transferUtility",
"TransferUtility",
- "TRANSFORMERVERSION",
"transform.conf.json",
+ "TRANSFORMERVERSION",
"transpile",
"transpiled",
"transpiles",
@@ -1341,8 +1493,12 @@
"TTLs",
"typeName",
"typeof",
+ "typname",
+ "typnamespace",
"UDID",
"ui",
+ "UI's",
+ "uibuilder",
"UIColor",
"UINavigationController",
"Uint",
@@ -1351,6 +1507,7 @@
"unauth",
"Unauth",
"uncategorized",
+ "unclustered",
"uncommenting",
"unencrypted",
"unioned",
@@ -1364,6 +1521,7 @@
"unregisters",
"unsanitized",
"Unselect",
+ "unsynced",
"Untag",
"updateapi",
"updateauth",
@@ -1371,47 +1529,55 @@
"UpdateTable",
"updateTodo",
"uploadData",
+ "Uploader",
+ "uppercased",
"upvotes",
"URIs",
- "URL's",
"url",
+ "URL's",
"urls",
"use",
- "userguide",
"useamplify",
"useamplifyabcd",
"usecase",
"user_identity_id",
"userauth",
"UserCodeDeliveryDetails",
- "userfiles-mobilehub",
"userfiles",
+ "userfiles-mobilehub",
+ "userguide",
"userid",
+ "userids",
"usernameAttributes",
+ "usernamne",
"userpool",
"userpool",
"UserPool",
+ "USERPOOL",
"UserPoolId",
"userPools",
"UserPools",
"userState",
"UserState",
- "userStateDetails.getUserState",
"userStateDetails",
"UserStateDetails",
+ "userStateDetails.getUserState",
"usersub",
"USERTABLE",
- "USERPOOL",
"util",
"v2.0",
"v2.7",
"v25.0.0",
"validationData",
"vanillajs",
+ "vararg",
+ "varbinary",
"varchar",
"vendedlogs",
+ "vercel",
"verify.js",
"VerifyAuthChallengeResponse",
+ "verifyingattributes",
"VeriSign",
"versioned",
"versionField",
@@ -1419,23 +1585,27 @@
"versionInput",
"ViewController.swift",
"viewmodel",
+ "visionos",
"vite",
"voiceEnabled",
+ "voteField",
+ "Vue",
"vue-recaptcha",
"Vue.js",
- "Vue",
+ "wafv",
"walk",
"walkthrough",
"warningThreshold",
"webapp",
- "webconsole",
+ "webauthn",
"WEBCLIENT",
+ "webconsole",
"webhook",
+ "webp",
"webpack",
"websocket",
"WebSocket",
"webview",
- "webp",
"whitelist",
"widget",
"widget's",
@@ -1446,29 +1616,34 @@
"withAuthenticator",
"withFederated",
"withoauth",
+ "withoauth",
+ "WORKDIR",
"X-Amz-Date",
"X-Amz-Security-Token",
"X-Api-Key",
- "x86_64",
"x86",
+ "x86_64",
"Xabcdefghij",
"xcconfig",
- "Xcode's",
"Xcode",
+ "Xcode's",
"xcodeproj",
+ "xcshareddata",
"xcworkspace",
"xfbml",
"xib",
+ "xmark",
"xml",
- "XR.start",
"xr",
- "XX-XXXX-X_abcd1234",
+ "XR.start",
"XX-XXXX-X",
+ "XX-XXXX-X_abcd1234",
"XXXXXXXX-XXXX-1234-abcd-1234567890ab",
"xyz123useamplifyabcdClient.swift",
"Yeezy",
"yeezyboost",
"Yeezys",
+ "Yeezys",
"YOUR_API_RESOURCE_NAME",
"YOUR_APP_NAME",
"YOUR_PROJECT_FOLDER",
@@ -1481,188 +1656,24 @@
"yourserver",
"Zocial",
"zoneinfo",
- "bindui",
- "birthdate",
- "usernamne",
- "formfunction",
- "boto",
- "AIRPLANETABLE",
- "apolloapi",
- "apolloserver",
- "testtable",
- "gqlimages",
- "gqls",
- "gqllambda",
- "Cryptocurrency",
- "cryptofunction",
- "mynextapp",
- "Yeezys",
- "addingfunction",
- "reponame",
- "MYSTORAGE",
- "amplifyjsapp",
- "lightgray",
- "inappbrowser",
- "importauth",
- "withoauth",
- "myawesomekey",
- "myvalue",
- "есть",
- "нравится",
- "спагетти",
- "signingup",
- "confirmsignupcustomflow",
- "confirmingsignincustomflow",
- "verifyingattributes",
- "resettingpassword",
- "pubspec",
- "Stateful",
- "GETCURRENTUSER",
- "amplifyconfig",
- "nextamplified",
- "vercel",
- "Uploader",
- "AMPLIFYLAYERGUIDE",
- "instanceof",
- "CHALLENGEANSWER",
- "Fargate",
- "Dockerizing",
- "duckdb",
- "WORKDIR",
- "endregion",
- "entrypoint",
- "Entrypoint",
- "healthcheck",
- "CNAME",
- "imagedefinitions",
- "mydb",
- "bitnami",
- "adminui",
- "autologin",
- "UI's",
- "ownersaccess",
- "privatesaccess",
- "menudetaileditors",
- "editorgroupaccess",
- "authreadonly",
- "envs",
- "Onetoone",
- "onetomany",
- "manytomany",
- "datamodel",
- "AUTHCONFIG",
- "myproject",
- "STORAGECONFIG",
- "secretsmanager",
- "customcf",
- "Pipfile",
- "maplibre",
- "unclustered",
- "geospatial",
- "Ersi",
- "Geocodes",
- "gqlv",
- "ASIAVJKIAM",
- "Pressable",
- "geofence",
- "geofences",
- "savegeofences",
- "myfunction",
- "roadmap",
- "infowindow",
- "Libre's",
- "Pinia",
- "kotlinx",
- "snapcraft",
- "snapshotted",
- "visionos",
- "loggingconstraints",
- "remoteconfig",
- "remoteloggingconstraints",
- "remotelogging",
- "cloudwatchlogs",
- "userids",
- "xmark",
- "refreshable",
- "querytransfers",
- "generatemodelsforlazyloadandcustomselectionset",
- "wafv",
- "autoKsuid",
- "astro",
- "disambiguator",
- "tinyint",
- "tinytext",
- "mediumtext",
- "longtext",
- "linestring",
- "smallint",
- "mediumint",
- "varbinary",
- "tinyblob",
- "mediumblob",
- "longblob",
- "psql",
- "indexname",
- "indexdef",
- "typname",
- "enumlabel",
- "enumtypid",
- "typnamespace",
- "nspname",
- "autobranch",
- "gitflow",
- "SIWA",
- "hotswap",
- "clijson",
- "parametersjson",
- "nextamplifygen",
- "multirepo",
- "startbuild",
- "awscliv",
- "identitystore",
- "esac",
- "voteField",
- "ampx",
- "autodetection",
- "jamba",
- "webauthn",
- "knowledgebases",
- "rehype",
- "assetlinks",
- "AMPLIFYRULES",
- "preconfigured",
- "manylinux",
- "GOARCH",
- "norpc",
- "AWSSDKHTTP",
- "HTTPAPI",
- "AWSSDK",
- "uppercased",
- "autoclosure",
- "Kiro",
- "kiro",
- "Persistor",
- "persistor",
- "Dexie",
- "dexie",
- "dedup",
- "Dedup",
- "posttags",
- "callouts",
- "immer",
- "ERESOLVE",
- "graphqls",
- "swiftpm",
- "xcshareddata",
- "unsynced",
- "vararg"
+ "\u0435\u0441\u0442\u044c",
+ "\u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f",
+ "\u0441\u043f\u0430\u0433\u0435\u0442\u0442\u0438"
+ ],
+ "flagWords": [
+ "hte",
+ "full-stack",
+ "Full-stack",
+ "Full-Stack",
+ "sudo"
],
- "flagWords": ["hte", "full-stack", "Full-stack", "Full-Stack", "sudo"],
"patterns": [
{
"name": "youtube-embed-ids",
"pattern": "/embedId=\".*\" /"
}
],
- "ignoreRegExpList": ["youtube-embed-ids"]
+ "ignoreRegExpList": [
+ "youtube-embed-ids"
+ ]
}
diff --git a/src/directory/directory.mjs b/src/directory/directory.mjs
index fe42d05a123..129b1dd3c58 100644
--- a/src/directory/directory.mjs
+++ b/src/directory/directory.mjs
@@ -482,6 +482,10 @@ export const directory = {
{
path: 'src/pages/[platform]/build-a-backend/add-aws-services/analytics/existing-resources/index.mdx',
section: 'backend'
+ },
+ {
+ path: 'src/pages/[platform]/build-a-backend/add-aws-services/analytics/pinpoint-migration/index.mdx',
+ section: 'backend'
}
]
},
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/pinpoint-migration/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/pinpoint-migration/index.mdx
new file mode 100644
index 00000000000..b4781b7f2d2
--- /dev/null
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/pinpoint-migration/index.mdx
@@ -0,0 +1,516 @@
+import { getCustomStaticPath } from '@/utils/getCustomStaticPath';
+
+export const meta = {
+ title: 'Migrate from Pinpoint push campaigns to Amazon Connect',
+ description: 'Guide for migrating Pinpoint push notification campaigns to Amazon Connect Journeys with End User Messaging',
+ route: "/[platform]/build-a-backend/add-aws-services/analytics/pinpoint-migration",
+ platforms: [
+ 'flutter',
+ 'swift',
+ 'android'
+ ]
+};
+
+export const getStaticPaths = async () => {
+ return getCustomStaticPath(meta.platforms);
+};
+
+export function getStaticProps(context) {
+ return {
+ props: {
+ platform: context.params.platform,
+ meta
+ }
+ };
+}
+
+[AWS will end support for Amazon Pinpoint on October 30, 2026](https://docs.aws.amazon.com/pinpoint/latest/userguide/migrate.html). This guide covers migrating your Pinpoint push notification campaigns to Amazon Connect, using End User Messaging (the rebranded Pinpoint messaging API) for push delivery.
+
+## If you only use Amplify Analytics
+
+If you only use Amplify Analytics (`recordEvent`, session tracking) and don't use push notifications, your migration path is **Amazon Kinesis Data Streams** — not Connect. See [Set up Kinesis Data Streams](/[platform]/build-a-backend/add-aws-services/analytics/streaming-analytics/) for setup instructions. The Amplify Kinesis client is already available.
+
+The rest of this guide is for teams migrating **push notification campaigns**.
+
+## What doesn't change
+
+Firebase Cloud Messaging (FCM) and Apple Push Notification service (APNs) still deliver pushes to devices. Pinpoint was never sending pushes directly — it called FCM/APNs via End User Messaging. **That API is not deprecated.** Your on-device push handling code (notification display, tap handling, deep linking, permissions) does not need to change.
+
+What changes is how pushes are **triggered** (Connect Journeys instead of Pinpoint campaigns) and how device tokens are **registered** (Connect Customer Profiles instead of Pinpoint endpoints).
+
+## Choose your migration path
+
+### Option A: Direct send (no campaign UI needed)
+
+If you already manage your own device token lists and just need to send pushes, you can skip Connect entirely and call End User Messaging directly. This is the simplest migration.
+
+
+
+**End User Messaging App ID:** This is your existing Pinpoint Application ID. After the rebrand, the same ID is used by the End User Messaging APIs. Find it in the AWS console under **End User Messaging → Applications**, or via `aws pinpoint get-apps`.
+
+
+
+```typescript
+import { PinpointClient, SendMessagesCommand } from '@aws-sdk/client-pinpoint';
+
+const client = new PinpointClient({ region: 'us-east-1' });
+const APP_ID = 'your-end-user-messaging-app-id'; // Your existing Pinpoint Application ID
+
+const devices = [
+ { token: 'fcm-token-abc123', channel: 'GCM' as const },
+ { token: 'apns-token-xyz789', channel: 'APNS' as const },
+];
+
+for (const device of devices) {
+ await client.send(new SendMessagesCommand({
+ ApplicationId: APP_ID,
+ MessageRequest: {
+ Addresses: {
+ [device.token]: { ChannelType: device.channel }
+ },
+ MessageConfiguration: {
+ GCMMessage: {
+ Title: 'Your notification title',
+ Body: 'Your notification body',
+ Action: 'OPEN_APP',
+ },
+ APNSMessage: {
+ Title: 'Your notification title',
+ Body: 'Your notification body',
+ Action: 'OPEN_APP',
+ }
+ }
+ }
+ }));
+}
+```
+
+**Pros:** Minimal migration. No Connect setup. Keep your existing workflow.
+
+**Cons:** No segmentation UI, no campaign scheduling, no targeting by user attributes. You manage everything yourself.
+
+### Option B: Connect Journeys (for segmentation and campaign UI)
+
+If you want to target users by attributes and use a campaign management UI, migrate to Amazon Connect.
+
+## Prerequisites
+
+Before starting Option B, you need:
+
+- **An Amazon Connect instance** with outbound campaigns enabled. Find your instance ID via `aws connect list-instances` or from the Connect console URL (the UUID after `/instance/`).
+- **Customer Profiles enabled** and linked to your Connect instance. Enable it in the Connect console under **Customer Profiles**.
+- **An End User Messaging app** (your existing Pinpoint Application ID). Find it via `aws pinpoint get-apps` or in the console under **End User Messaging → Applications**.
+
+#### Step 1: Create a Connect Customer Profiles domain
+
+```bash
+aws customer-profiles create-domain \
+ --domain-name my-push-domain \
+ --default-expiration-days 365 \
+ --region us-east-1
+```
+
+#### Step 2: Create the device profile object type
+
+This tells Connect how to store device tokens on user profiles.
+
+
+
+```bash
+aws customer-profiles put-profile-object-type \
+ --domain-name my-push-domain \
+ --object-type-name AmplifyDevice \
+ --description "Mobile device for push notifications" \
+ --keys '{
+ "deviceIdKey": [{"StandardIdentifiers": ["UNIQUE"], "FieldNames": ["deviceId"]}],
+ "userIdKey": [{"StandardIdentifiers": ["PROFILE"], "FieldNames": ["userId"]}]
+ }' \
+ --fields '{
+ "deviceId": {"Source": "_source.deviceId", "Target": "_source.deviceId", "ContentType": "STRING"},
+ "deviceToken": {"Source": "_source.deviceToken", "Target": "_source.deviceToken", "ContentType": "STRING"},
+ "channelType": {"Source": "_source.channelType", "Target": "_source.channelType", "ContentType": "STRING"},
+ "platform": {"Source": "_source.platform", "Target": "_source.platform", "ContentType": "STRING"},
+ "userId": {"Source": "_source.userId", "Target": "_source.userId", "ContentType": "STRING"}
+ }' \
+ --allow-profile-creation \
+ --region us-east-1
+```
+
+
+
+This creates an `AmplifyDevice` object type with fields for `deviceId`, `deviceToken`, `channelType`, `platform`, and `userId`. The `UNIQUE` key on `deviceId` ensures one record per device; the `PROFILE` key on `userId` links devices to profiles.
+
+#### Step 3: Export and import your Pinpoint endpoints
+
+Follow the [official Pinpoint migration guide](https://docs.aws.amazon.com/pinpoint/latest/userguide/migrate.html#migration-steps) to export your endpoints, then import them as Customer Profiles. For push endpoints (GCM/APNS), also register them as device profile objects:
+
+```typescript
+import { CustomerProfilesClient, PutProfileObjectCommand } from '@aws-sdk/client-customer-profiles';
+
+const client = new CustomerProfilesClient({ region: 'us-east-1' });
+const DOMAIN = 'my-push-domain';
+
+// For each push device from your Pinpoint export:
+await client.send(new PutProfileObjectCommand({
+ DomainName: DOMAIN,
+ ObjectTypeName: 'AmplifyDevice',
+ Object: JSON.stringify({
+ userId: 'user-001',
+ deviceId: 'pinpoint-endpoint-id',
+ deviceToken: 'fcm-or-apns-token',
+ channelType: 'GCM',
+ platform: 'Android',
+ })
+}));
+```
+
+#### Step 4: Deploy the push delivery Lambda
+
+Amazon Connect Journeys support email, SMS, WhatsApp, and voice as native channels — but **not push notifications**. To send pushes from a Journey, you need a Lambda function that bridges the gap. The Journey invokes this Lambda via a "Custom Action" block, and the Lambda reads device tokens from the user's profile objects and calls End User Messaging to deliver the push via FCM/APNs.
+
+
+
+Create an execution role with these permissions:
+
+```json
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Action": "mobiletargeting:SendMessages",
+ "Resource": "arn:aws:mobiletargeting:us-east-1:ACCOUNT:apps/YOUR_EUM_APP_ID/*"
+ },
+ {
+ "Effect": "Allow",
+ "Action": "profile:ListProfileObjects",
+ "Resource": "arn:aws:profile:us-east-1:ACCOUNT:domains/my-push-domain"
+ },
+ {
+ "Effect": "Allow",
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents"
+ ],
+ "Resource": "arn:aws:logs:us-east-1:ACCOUNT:*"
+ }
+ ]
+}
+```
+
+Trust policy:
+
+```json
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Principal": {"Service": "lambda.amazonaws.com"},
+ "Action": "sts:AssumeRole"
+ }
+ ]
+}
+```
+
+
+
+
+
+The Lambda receives a batch of customer profiles from the Journey's Custom Action block. It reads each profile's device tokens and sends push notifications via End User Messaging. Notification content comes from environment variables so you can update it without redeploying code.
+
+```typescript
+// push-delivery/index.ts
+import { CustomerProfilesClient, ListProfileObjectsCommand } from '@aws-sdk/client-customer-profiles';
+import { PinpointClient, SendMessagesCommand } from '@aws-sdk/client-pinpoint';
+import type { MessageConfiguration } from '@aws-sdk/client-pinpoint';
+
+// Push delivery uses the mobiletargeting API (@aws-sdk/client-pinpoint),
+// which remains available after Pinpoint EOL.
+const cp = new CustomerProfilesClient({});
+const eum = new PinpointClient({});
+
+const DOMAIN = process.env.CUSTOMER_PROFILES_DOMAIN!;
+const EUM_APP_ID = process.env.EUM_APP_ID!;
+const NOTIFICATION_TITLE = process.env.NOTIFICATION_TITLE ?? 'Notification';
+const NOTIFICATION_BODY = process.env.NOTIFICATION_BODY ?? '';
+
+interface CampaignEvent {
+ Items: {
+ CustomerProfiles: Array<{
+ ProfileId: string;
+ CustomerData: string;
+ IdempotencyToken: string;
+ }>;
+ };
+}
+
+/**
+ * Invoked by a Connect Journey Custom Action block.
+ * Event format: https://docs.aws.amazon.com/connect/latest/adminguide/lambda-invoke-functions.html
+ */
+export const handler = async (event: CampaignEvent) => {
+ const profiles = event.Items.CustomerProfiles;
+ const responseItems = [];
+
+ for (const record of profiles) {
+ const { ProfileId } = record;
+
+ const devicesResponse = await cp.send(new ListProfileObjectsCommand({
+ DomainName: DOMAIN,
+ ObjectTypeName: 'AmplifyDevice',
+ ProfileId,
+ }));
+
+ const statuses: string[] = [];
+ for (const obj of devicesResponse.Items ?? []) {
+ const device = JSON.parse(obj.Object!);
+ const token: string | undefined = device.deviceToken;
+ const channel: string = device.channelType ?? 'GCM';
+
+ if (!token) continue;
+
+ const MessageConfiguration: MessageConfiguration = {};
+ if (channel === 'GCM') {
+ MessageConfiguration.GCMMessage = {
+ Title: NOTIFICATION_TITLE,
+ Body: NOTIFICATION_BODY,
+ Action: 'OPEN_APP',
+ };
+ } else if (channel === 'APNS' || channel === 'APNS_SANDBOX') {
+ MessageConfiguration.APNSMessage = {
+ Title: NOTIFICATION_TITLE,
+ Body: NOTIFICATION_BODY,
+ Action: 'OPEN_APP',
+ };
+ }
+
+ const resp = await eum.send(new SendMessagesCommand({
+ ApplicationId: EUM_APP_ID,
+ MessageRequest: {
+ Addresses: { [token]: { ChannelType: channel } },
+ MessageConfiguration,
+ },
+ }));
+
+ const status = resp.MessageResponse?.Result?.[token]?.DeliveryStatus ?? 'UNKNOWN';
+ statuses.push(status);
+ }
+
+ responseItems.push({ Id: ProfileId, ResultData: { deliveryStatuses: statuses } });
+ }
+
+ return { Items: { CustomerProfiles: responseItems } };
+};
+```
+
+
+
+##### Deploy the Lambda
+
+```bash
+# Bundle and deploy (using esbuild)
+npx esbuild push-delivery/index.ts --bundle --platform=node --outfile=dist/index.js
+
+cd dist && zip -r ../lambda.zip index.js && cd ..
+
+aws lambda create-function \
+ --function-name push-delivery \
+ --runtime nodejs20.x \
+ --handler index.handler \
+ --role arn:aws:iam::ACCOUNT:role/push-delivery-role \
+ --zip-file fileb://lambda.zip \
+ --environment 'Variables={CUSTOMER_PROFILES_DOMAIN=my-push-domain,EUM_APP_ID=your-end-user-messaging-app-id,NOTIFICATION_TITLE=Your Title,NOTIFICATION_BODY=Your message body}'
+
+aws lambda add-permission \
+ --function-name push-delivery \
+ --statement-id connect-invoke \
+ --action lambda:InvokeFunction \
+ --principal connect.amazonaws.com
+```
+
+##### Register the Lambda with Connect
+
+
+
+The `associate-lambda-function` CLI command is for **contact flows**, not outbound campaigns. For Journey Custom Actions, register your Lambda via the Connect console:
+
+1. Open the [Amazon Connect console](https://console.aws.amazon.com/connect/)
+2. Select your instance
+3. In the navigation pane, go to **Channels and communications → Outbound campaigns**
+4. Under **Set up custom actions**, use the **Lambda functions** dropdown to select your function
+5. Choose **Add Lambda Function**
+
+
+
+#### Step 5: Create a Journey and send
+
+1. Open the Connect console → Outbound campaigns → Create Journey
+2. Choose your segment (filter by profile attributes like `plan = premium`)
+3. Add a **Custom Action** block → select your `push-delivery` Lambda
+4. Run the Journey
+
+## Migrating `identifyUser`
+
+Amplify's `identifyUser` API mapped to Pinpoint's `UpdateEndpoint`. The replacement is creating or updating a Connect Customer Profile with the same attributes.
+
+| Pinpoint (`identifyUser`) field | Connect Customer Profile field |
+|---|---|
+| `name` | `FirstName` / `LastName` |
+| `email` | `EmailAddress` |
+| `plan` (custom attribute) | `Attributes.plan` |
+| Custom user attributes | `Attributes` map |
+
+```typescript
+import { CustomerProfilesClient, CreateProfileCommand } from '@aws-sdk/client-customer-profiles';
+
+const client = new CustomerProfilesClient({ region: 'us-east-1' });
+
+// Equivalent of identifyUser({ userId: 'user-001', name: 'Jane Doe', email: '...' })
+await client.send(new CreateProfileCommand({
+ DomainName: 'my-push-domain',
+ FirstName: 'Jane',
+ LastName: 'Doe',
+ EmailAddress: 'jane@example.com',
+ Attributes: { plan: 'premium', locale: 'en_US' }
+}));
+```
+
+## Registering devices from your mobile app
+
+Once your backend is set up, each device needs to register its push token with Connect Customer Profiles by calling `PutProfileObject` with the `AmplifyDevice` object type.
+
+
+
+
+
+```kotlin
+import aws.sdk.kotlin.services.customerprofiles.CustomerProfilesClient
+import aws.sdk.kotlin.services.customerprofiles.model.PutProfileObjectRequest
+import kotlinx.serialization.json.*
+
+val cpClient = CustomerProfilesClient { region = "us-east-1" }
+
+suspend fun registerDevice(userId: String, token: String, deviceId: String) {
+ val deviceObject = buildJsonObject {
+ put("userId", userId)
+ put("deviceId", deviceId)
+ put("deviceToken", token)
+ put("channelType", "GCM")
+ put("platform", "Android")
+ }
+
+ cpClient.putProfileObject(PutProfileObjectRequest {
+ domainName = "my-push-domain"
+ objectTypeName = "AmplifyDevice"
+ `object` = deviceObject.toString()
+ })
+}
+```
+
+
+
+
+
+```swift
+import AWSCustomerProfiles
+
+let cpClient = try CustomerProfilesClient(region: "us-east-1")
+
+func registerDevice(userId: String, token: String, deviceId: String) async throws {
+ let deviceObject: [String: String] = [
+ "userId": userId,
+ "deviceId": deviceId,
+ "deviceToken": token,
+ "channelType": "APNS",
+ "platform": "iOS"
+ ]
+
+ let objectJson = try JSONSerialization.data(withJSONObject: deviceObject)
+
+ let input = PutProfileObjectInput(
+ domainName: "my-push-domain",
+ object: String(data: objectJson, encoding: .utf8)!,
+ objectTypeName: "AmplifyDevice"
+ )
+ _ = try await cpClient.putProfileObject(input: input)
+}
+```
+
+
+
+
+
+```typescript
+// Flutter apps should call a backend endpoint that proxies to Customer Profiles.
+// Example backend Lambda (TypeScript):
+import { CustomerProfilesClient, PutProfileObjectCommand } from '@aws-sdk/client-customer-profiles';
+import type { APIGatewayProxyHandler } from 'aws-lambda';
+
+const client = new CustomerProfilesClient({});
+
+export const handler: APIGatewayProxyHandler = async (event) => {
+ const body = JSON.parse(event.body!);
+ await client.send(new PutProfileObjectCommand({
+ DomainName: 'my-push-domain',
+ ObjectTypeName: 'AmplifyDevice',
+ Object: JSON.stringify({
+ userId: body.userId,
+ deviceId: body.deviceId,
+ deviceToken: body.deviceToken,
+ channelType: body.channelType,
+ platform: body.platform,
+ })
+ }));
+ return { statusCode: 200, body: '' };
+};
+```
+
+```dart
+// Flutter client call:
+import 'package:http/http.dart' as http;
+import 'dart:convert';
+
+Future registerDevice({
+ required String userId,
+ required String deviceId,
+ required String token,
+ required String platform,
+}) async {
+ await http.post(
+ Uri.parse('https://your-api.execute-api.us-east-1.amazonaws.com/register-device'),
+ body: jsonEncode({
+ 'userId': userId,
+ 'deviceId': deviceId,
+ 'deviceToken': token,
+ 'channelType': platform == 'android' ? 'GCM' : 'APNS',
+ 'platform': platform,
+ }),
+ );
+}
+```
+
+
+
+
+
+The `UNIQUE` key on `deviceId` means re-registering with the same device ID updates the token in place (handles token refreshes).
+
+
+
+**New Amplify libraries for Connect are in development.** When available, they will provide `connectClient.registerDevice(token)` and `connectClient.identifyUser()` that handle this automatically. This guide will be updated at that time.
+
+
+
+## Pinpoint to Connect mapping
+
+| Pinpoint concept | Connect equivalent |
+|---|---|
+| Endpoint | Customer Profile + AmplifyDevice profile object |
+| Endpoint ID | `deviceId` on AmplifyDevice object |
+| Endpoint Address (push token) | `deviceToken` on AmplifyDevice object |
+| Endpoint Attributes | Profile Attributes map |
+| Segment | Connect Segment (Classic segmentation) |
+| Campaign (push) | Journey with Custom Action → Lambda → End User Messaging |
+| `identifyUser` / `UpdateEndpoint` | `CreateProfile` / `UpdateProfile` |