Setting Up Notifications With AWS Amplify Gen 1

Authors
Vladislav Bataev
Software Engineer
@
Callstack

Exploring live messaging and push notifications led me to AWS Amplify—a robust service with all-in-one features that's been on my radar. However, I found the setup process frustrating—clear, step-by-step guides are scarce, and the documentation can be overwhelming.

To help others navigate this, I’ve put together a guide for integrating Amplify with React Native, focusing on Android. If this resonates, I may follow up with an iOS guide.

Setup Process

Here are the steps to take:

  1. Set up IAM user for local development and initialize Amplify on the local machine
  2. Create a project with Amplify
  3. Add authentication via AWS
  4. Add notifications

Set up IAM user for local development

First, we will need to create an AWS profile; after that, we will start our deployment. You can register at the AWS console.

After verifying your account, you will be in the AWS console. Once you are, go ahead and install Amplify locally:

npm install -g @aws-amplify/cli

Resolve EACCES permissions when installing packages globally with npm if needed.

Next, we need to configure our user using the following command: amplify configure.

> amplify configure
Follow these steps to set up access to your AWS account:
Sign in to your AWS administrator account:
https://console.aws.amazon.com/
Press Enter to continue
Specify the AWS Region
? region:
sa-east-1
us-east-1
> us-east-2
us-west-1
us-west-2
eu-north-1
eu-south-1
view raw configure.sh hosted with ❤ by GitHub

You should be redirected to your account and the IAM account section. If not, follow this link.

Here are fully described steps on how to set up a profile for local development.

Step 1

First, you will be prompted to choose a name; choose the one that is easiest for you to remember.

Creating IAM user

Step 2

Decide which accesses to give to this user. Note that we only need one AdministratorAccess-Amplify permission.

Admin access selection

Step 3

After that, we can see the details of the user we are creating. It will look like this:

Account creation review

Step 4

Now we are in the console of our users, where we will need to select the user we just created. If this is your first user, it may redirect you to the details right away. Below is an example of what a list of users looks like.

IAM Users list

Step 5

Next we need to go into the user details, and get the secret keys that we will later add to our user that we configure locally on the machine. So just click: create access key.

Step 6

In the next step, we need to select Command Line Interface CLI to access our locally installed Amplify.

Step 7

Tags are optional, but I always add them for clearer handling in the future (to understand what this key is for, etc.). So now press “Create access key,” and we’re done!

Adding tags

Step 8

Finally, you will see the access key and secret access key. We will add them through the console soon.

Retrieving secret keys

Enter the values you just copied into the corresponding CLI prompts, and that's it!

Follow these steps to set up access to your AWS account:
Sign in to your AWS administrator account:
https://console.aws.amazon.com/
Press Enter to continue
Specify the AWS Region
? region: us-east-1
Follow the instructions at
https://docs.amplify.aws/cli/start/install/#configure-the-amplify-cli
to complete the user creation in the AWS console
https://console.aws.amazon.com/iamv2/home#/users/create
Press Enter to continue
Enter the access key of the newly created user:
? accessKeyId: ********************
? secretAccessKey: ********************
This would update/create the AWS Profile in your local machine
? Profile Name: ck-example
Successfully set up the new user.
view raw login.sh hosted with ❤ by GitHub

Just to double check open ~/.aws/config to see if you have there added user. You will see something like this:

[profile dev]
region=us-east-1
view raw profile.sh hosted with ❤ by GitHub

If you see this and file is available, we can proceed to creating a project!

Create a project with Amplify

Create a project using CLI:

❯ npx @react-native-community/cli@latest init AWSomeProject --version 0.75.0
cd AWSomeProject
view raw create.sh hosted with ❤ by GitHub

Now we need to install amplify in our project correctly, so first, we need to run the command: amplify init

Remember to choose Amplify Gen 1; of the 2nd Gen, we don't have Notifications, yet 🙂

You will have something like this. Be advised to set up properly a directory path to “ / ”

? Enter a name for the project (AWSomeProject)
The following configuration will be applied:
Project information
| Name: AWSomeProject
| Environment: dev
| Default editor: Visual Studio Code
| App type: javascript
| Javascript framework: react-native
| Source Directory Path: /
| Distribution Directory Path: /
| Build Command: npm run-script build
| Start Command: npm run-script start
? Initialize the project with the above configuration? Yes
Using default provider awscloudformation
? Select the authentication method you want to use: AWS profile
? Please choose the profile you want to use default
view raw setup.sh hosted with ❤ by GitHub

After this, you'll notice an amplify folder has been added to your project. This folder stores the backend configuration of your project, and as you add features like authentication or notifications, new files will be created within it.

You also will see a new file in the root directory calling amplifyconfiguration.json

With this helper, json react-native app will understand that we use amplify packages.

It will look like this:

creating a file calling amplifyconfiguration.json

Add libraries that we need to init Amplify on react-native part of the app:

npm install aws-amplify @aws-amplify/react-native @react-native-community/netinfo @react-native-async-storage/async-storage react-native-get-random-values

After all these settings, we need to add Amplify to the application and make sure that everything works well. For this purpose, we need to initialize Amplify in the index file (the earlier, the better).

// index.js
import { Amplify } from 'aws-amplify';
import amplifyconfig from './amplifyconfiguration.json';
Amplify.configure(amplifyconfig);
view raw index.js hosted with ❤ by GitHub

Now that we are done, let's move on and enable authentication! (You can check the app before adding auth, though.)

Add authentication via Amplify

Authentication is critical for notifications in Amazon Amplify to ensure they are delivered securely to targeted, authorized users. Authentication also provides seamless integration with AWS services, making notification processing secure and efficient.

To add authentication to your app, run this command: amplify add auth

Specify ‘sign in’ using Username, and without any additional configuration.

? Do you want to use the default authentication and security configuration?
Default configuration
Warning: you will not be able to edit these selections.
? How do you want users to be able to sign in? Username
? Do you want to configure advanced settings? No, I am done.

After this, Amplify will update the backend on the servers. However, if it doesn’t happen, you can double-check by using the amplify pushcommand.

Adding login form from Amplify

The @aws-amplify/ui-react-native package includes React Native-specific UI components you'll use to build your app. Install it with the following command:

npm install @aws-amplify/ui-react-native react-native-safe-area-context
view raw aws.sh hosted with ❤ by GitHub

Then we will add auth to our Main.tsx folder, the full file will look like this:

import React from 'react';
import {Pressable, StyleSheet, Text, View} from 'react-native';
import {
withAuthenticator,
useAuthenticator,
} from '@aws-amplify/ui-react-native';
import {SafeAreaView} from 'react-native-safe-area-context';
const userSelector = (context: {user: any}) => [context.user];
const SignOutButton = () => {
const { user, signOut } = useAuthenticator(userSelector);
return (
<Pressable onPress={signOut} style={styles.buttonContainer}>
<Text style={styles.buttonText}>
Hello, {user.username}! Click here to sign out!
</Text>
</Pressable>
);
};
const Main: React.FC = () => {
return (
<SafeAreaView style={styles.container}>
<View style={styles.container}>
<SignOutButton />
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: { width: 400, flex: 1, padding: 20, alignSelf: 'center' },
buttonContainer: {
alignSelf: 'center',
backgroundColor: 'black',
paddingHorizontal: 8,
},
buttonText: { color: 'white', padding: 16, fontSize: 18 },
tokenText: { marginTop: 20, color: 'gray', fontSize: 14 },
});
export default withAuthenticator(Main);
view raw Main.tsx hosted with ❤ by GitHub
import React from 'react';
import Main from './src/Main.tsx';
const App = () => {
return <Main />;
};
export default App;
view raw App.tsx hosted with ❤ by GitHub

After installing, rebuild the app: npm run android

In this example you can see that we are using HOC withAuthenticator to wrap our app. Next, we will need to restart the app and see if we have a login form in the app. If we do, we will just need to create an account and then we will be inside our app!

screenshots with a login form

Notifications using Amplify

Adding Google Services

First, we need to add Google services because we'll still access our notifications via Firebase token. We need to add the following to the build.gradle:

classpath 'com.google.gms:google-services:4.4.2'
view raw classpath.kt hosted with ❤ by GitHub

And in app/build.gradle, at the top, we add:

apply plugin: 'com.google.gms.google-services'
view raw apply.kt hosted with ❤ by GitHub

Also we need to add google-services.json in the android/app folder like so:

folder showing google-services.json

Now, let's try to build an app and check how it works!

Adding notifications on the Amplify

amplify add notifications

We need to choose FCM  | » Firebase Push Notifications

  • After you need to name your pinpoint resource name, basically we could name it push.
  • Prompt will ask you about sending analytics, etc; just press Y for easier setup.
  • After pushing notifications to the Amplify servers part, we will need to provide a service account key (json file) path.

You can get it from a Firebase account; we will not cover the setup of Firebase here, but here are small steps to follow if you already created an account in the Firebase console:

  1. Open Project settings
  2. Click on Service accounts
  3. Generate new private key
  4. Json file was generated

Pass this file to the iTerm or terminal, and you will see an absolute file path like:

users/Desktop/secret_key12345.json

Copy this path and paste it to the Amplify initialization of Notification. You will see something like this:

Initializing notifications

Next, we need to install the missing packages in our application and initialize the notification service. Packages' installations:

npm install aws-amplify @aws-amplify/react-native @aws-amplify/rtn-push-notification @react-native-async-storage/async-storage react-native-get-random-values
view raw npm.sh hosted with ❤ by GitHub

Reinstall app and start it, but add the following to the index.js:

// index.js
// ...
import { initializePushNotifications } from 'aws-amplify/push-notifications';
initializePushNotifications();
// ...
view raw update.js hosted with ❤ by GitHub

It will result in something like this:

import { AppRegistry } from 'react-native';
import App from './App';
import { name as appName } from './app.json';
import { Amplify } from 'aws-amplify';
import { initializePushNotifications } from 'aws-amplify/push-notifications';
import amplifyconfig from './src/amplifyconfiguration.json';
Amplify.configure(amplifyconfig);
initializePushNotifications();
AppRegistry.registerComponent(appName, () => App);
view raw index_v2.js hosted with ❤ by GitHub

Request permissions

Yeah, you will also need to handle permissions 😭

First of all, let’s add this to manifest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Required permissions for push notifications -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.VIBRATE" />
<!-- Required permission for notifications on Android 13 and above -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme"
android:supportsRtl="true">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
view raw android.xml hosted with ❤ by GitHub

Simplified flow of retrieving permissions will be something like this:

import { useState, useEffect } from 'react';
import {
getPermissionStatus,
requestPermissions,
} from 'aws-amplify/push-notifications';
export type PushNotificationPermissionStatus =
| 'denied'
| 'granted'
| 'shouldRequest'
| 'shouldExplainThenRequest'
| undefined;
export const usePushNotificationPermissions = () => {
const [status, setStatus] = useState<PushNotificationPermissionStatus>(undefined);
const handlePermissions = async () => {
try {
const permissionStatus = await getPermissionStatus();
switch (permissionStatus) {
case 'granted':
setStatus('granted');
break;
case 'denied':
setStatus('denied');
break;
case 'shouldRequest':
setStatus('shouldRequest');
await requestPermissions();
break;
case 'shouldExplainThenRequest':
setStatus('shouldExplainThenRequest');
await requestPermissions();
break;
default:
setStatus(undefined);
}
} catch (error) {
console.error('Error handling push notification permissions:', error);
setStatus(undefined);
}
};
useEffect(() => {
handlePermissions();
}, []);
return status;
};
view raw permissions.tsx hosted with ❤ by GitHub

After that, we will need to get our FCM token to test push notifications:

import { useEffect, useState } from 'react';
import {
onTokenReceived,
OnTokenReceivedInput,
OnTokenReceivedOutput,
} from 'aws-amplify/push-notifications';
export const useToken = () => {
const [token, setToken] = useState<string>('');
useEffect(() => {
const myTokenReceivedHandler: OnTokenReceivedInput = (receivedToken) => {
setToken(receivedToken);
console.log('Push Notification Token:', receivedToken);
};
const listener: OnTokenReceivedOutput = onTokenReceived(myTokenReceivedHandler);
return () => {
listener.remove();
};
}, []);
return token;
};
view raw useToken.tsx hosted with ❤ by GitHub

Receiving notifications

Well, we are almost at the final; now, I will show you how to create a hook to work with push notifications. You will need to fix it for your needs if necessary.

import { useEffect } from 'react';
import {
onNotificationReceivedInForeground,
onNotificationReceivedInBackground,
onNotificationOpened,
getLaunchNotification,
} from 'aws-amplify/push-notifications';
import {Alert} from 'react-native';
export const useNotificationListener = () => {
useEffect(() => {
const foregroundNotificationHandler = (notification: any) => {
console.log('Notification received in foreground:', notification);
Alert.alert('Foreground Message', JSON.stringify(notification));
};
onNotificationReceivedInForeground(foregroundNotificationHandler);
const backgroundNotificationHandler = async (notification: any) => {
console.log('Notification received in background:', notification);
};
onNotificationReceivedInBackground(backgroundNotificationHandler);
const notificationOpenedHandler = (notification: any) => {
console.log('Notification opened:', notification);
};
onNotificationOpened(notificationOpenedHandler);
const checkLaunchNotification = async () => {
const launchNotification = await getLaunchNotification();
if (launchNotification) {
console.log('App launched from terminated state by notification:', launchNotification);
}
};
checkLaunchNotification();
}, []);
};

Test push notifications

Get FCA token

And now we will test it how it works! First of all you need to get a token from a console.

It will be something like this string:

foN_4dzDRUu0VFGG3tM:APA91bFArqe12345zVTA8ePeZq1YBxyJMnlPD4mO34kDtDy93OkEMJ-HJWgnGRwtERDejYQW-WDtuFs6GxVmDEG_DXbaIftwNp-C12345b_-mAo122PY

Put token

Now we need to put this token in the pinpoint console. It looks like this:

Pinpointing console

Then you need to find "Test messaging" and choose "Push notifications." We will test our "Notifications" using "Device tokens" in "Destinations." There you need to specify token and choose the service FCM.

The next step is to specify our Message content:

Specifying message content

Then we press "Send Message," and voilà! We made it!

AWS notifications set

Final Notes

Implementing push notifications with AWS Amplify can be a challenging journey, and it’s not always easy to grasp everything on the first try. That’s why I created this article—to help anyone getting started with this type of notification. You can check out the fully working project I created to further guide you through this process.

Insights

Learn more about Backend

cover

Aug 10Podcast

Databases for Mobile Apps: React Native & Realm

Join us on a deep-dive into the complex world of databases for mobile apps, and take a closer look at what the marriage of React Native, Realm & MongoDB can bring.

cover

Dec 28Article

Simple Chat App With React Native - Part II

Read the article and learn how to connect the frontend of the messaging app with its backend.

cover

Oct 23Article

Simple Chat App With React Native - Part I

Learn how to create the backend for a messaging app in React Native with our blog post. We cover the topic in a two-part series.

cover

Oct 3Article

React Native, Firebase and You

Learn how to build a full-stack project in React Native with the Firebase support. Check the benefits of using the react-native-firebase module.

cover

Mar 19Tutorial

The Hard Way vs. The React Native AI SDK Way: Stop Writing Custom Modules for Every Model

Learn how React Native AI uses a unified provider model to switch between cloud and on-device LLMs without rewriting application logic, enabling reliable AI experiences online and offline.

cover

Mar 12Tutorial

Build Smarter Apps: Tool Calling & AI Orchestration Explained

Learn how on-device models in React Native can call tools, interact with external APIs, and return structured outputs you can use directly in application logic.

cover

Mar 5Tutorial

MLC LLM + React Native: On-Device AI Without the Pain

Learn how to run third-party on-device LLMs in React Native using MLC LLM. Choose your models, run them efficiently across platforms, and keep a unified JavaScript API with React Native AI.

cover

Feb 24Tutorial

Intelligent Fallbacks with Apple Intelligence in React Native

Learn how to use Apple’s built-in Foundation Models in React Native apps, reduce memory usage, and enable fast, fully on-device AI with React Native AI Apple.

cover

Feb 10Tutorial

What Is the React Native AI SDK? A Complete Intro & Quickstart

Learn why on-device AI matters for React Native apps, how local LLMs behave offline, and what problems React Native AI is designed to solve from day one.

cover

Jan 29Tutorial

Implementing an Android TurboModule with Kotlin

Learn how to implement a React Native TurboModule on Android, from the TypeScript spec and Codegen to the Kotlin implementation and package registration.

cover

Jan 19Tutorial

Working with Different Threads in Swift TurboModules

Learn how JavaScript, native module, background, and main threads interact in React Native TurboModules, and how to use GCD queues to run async work safely in Swift.

cover

Jan 9Tutorial

How to Add Type-Safe Constants to Swift TurboModules

Learn how to expose typed, immutable constants from a Swift TurboModule using Codegen, and get full end-to-end type safety between native and JavaScript.

cover

Dec 30Tutorial

Adding Event Emitters to Your TurboModule in Swift

Learn how to emit native events from a Swift TurboModule and subscribe to them in JavaScript, including proper memory management and Codegen integration.

cover

Dec 22Tutorial

Writing Your First TurboModule in Swift

Learn how to build a fully working TurboModule in Swift, integrate it with Codegen, and bridge it through Objective‑C inside an Expo app.