How to add push notifications to your Appwrite Cloud apps
Tags: firebase, cloud, flutter, appwrite
Published: 2023-12-07 14:38:00

In today's information-driven landscape, staying current is paramount. Enter the realm of push notifications — an avenue by which data arrives at our digital doorstep, like a knowledgeable neighbor extending a warm invitation. These little alerts have become one of the most essential features in modern-day applications as they update the user about the services that a given application handles. 

Let’s explore push notifications a bit further: messages or alerts sent from a server or backend system to a user's mobile device, computer, or other device. These notifications are "pushed" to the device rather than being requested or "pulled" by the user. 

In the case of our analogy above, the friendly neighbor is Appwrite. Appwrite is an open-source backend-as-a-service (BaaS) that simplifies repetitive development tasks through simple REST API. Appwrite has added this important feature to its services. In this article, we’ll take a closer look at how we can add push notifications to our Flutter applications using Appwrite's cloud functions.

Before we can proceed, you’ll need to have the following:

- An [Appwrite cloud](https://cloud.appwrite.io/register?utm_source=hackmamba&utm_medium=hackmamba-blog) account
- A [Firebase](https://console.firebase.google.com/u/1/?pli=1) account (subsequently, a [Gmail](https://accounts.google.com/v3/signin/identifier?continue=https://mail.google.com/mail/&service=mail&theme=glif&flowName=GlifWebSignIn&flowEntry=ServiceLogin) account)
- A good foundation in Flutter
- And some coffee for the cookies, of course. 😉

## Getting started

[Appwrite Cloud](https://cloud.appwrite.io/register?utm_source=hackmamba&utm_medium=hackmamba-blog) implements push notifications in its application by combining the **Firebase Cloud Messaging (FCM)** feature provided by **Firebase** and its own **Appwrite Cloud Function API**. Appwrite further simplifies this process programmatically by providing a serverless **Node.js** code template that allows us to connect our Flutter application to communicate with **Firebase Cloud Messaging**.

We’re going to get pretty granular in this tutorial, so here’s a helpful outline: 

- [Creating projects](#creating-projects):
    - [Create a Firebase project](#creating-a-firebase-project)
    - [Create an Appwrite project](#creating-an-appwrite-project)
    - [Create our Flutter project](#creating-a-flutter-project)
- [Setting up Firebase Cloud messaging](#setting-up-firebase-cloud-messaging):
    - [Generating a private key](#generating-a-private-key)
    - [Creating a Realtime database](#creating-a-realtime-database)
- [Setting up Appwrite](#setting-up-appwrite):
    - [Creating an Appwrite database](#creating-an-appwrite-database)
    - [Creating an Appwrite Cloud function FCM template](#creating-an-appwrite-cloud-function-fcm-template)
    - [Customizing the FCM template](#customizing-the-fcm-template)
- [Building the Flutter project](#building-the-flutter-project):
    - [Cloning the application for the notification device](#cloning-the-application-for-the-notification-device)
    - [Cloning the application for the admin device](#cloning-the-application-for-the-admin-device)

## Creating projects

Thus, without further ado, let’s create the Firebase project!

![Excited](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698480134782_excited-shaquille-o-neal-3isxv4tbjeeb3fej.gif)



## Creating a Firebase project

To create a [Firebase](https://console.firebase.google.com/u/1/?pli=1) project, click the earlier link and click **Create a project** on the page.


![Create project](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698481037670_create+project.png)


Then, Firebase prompts us to fill in a **project name**, **turn on or off analytics** (uncheck analytics as it is optional for this project), and finally, **continue**. That’s it! You have now successfully created a Firebase project.


![Add project name](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698482333216_project_name.PNG)

![Analytics](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698482333370_disabling_analytics.PNG)

![Continue](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698482333289_continue.PNG)

## Creating an Appwrite project

After creating an Appwrite cloud account,  log into the console, click **Create Project**, and fill in a project name and ID here.


> Note: ID can also be autogenerated.


![Create an Appwrite project](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698586002630_create+project.PNG)

## Creating a Flutter project

To create a Flutter project, open your terminal and type the command below:

```javascript
flutter create <project name>
```


> Note: Change the <project name> to a name of your choice.

The command above triggers the Flutter SDK to create a new boilerplate project; thus, we have successfully created a Firebase, Appwrite, and Flutter project.

## Setting up Firebase Cloud Messaging

To use the Firebase cloud messaging feature within our Appwrite cloud applications, we will need to get the **private key** and **database URL** from the Firebase console. 


## Generating a private key

Starting with the private key, we will navigate to the console's **Project settings** area by clicking the gear icon.


![Project settings](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698588391391_settings.png)


Next, we will copy the **project ID** to a safe place, as we will require it when creating the **FCM template** in Appwrite. We must provide the project ID as a variable, which we will then pass to the **FCM template** as a parameter.


![Project ID](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698588600368_projectId.png)


Next, we'll move to the **Service accounts** section of the **Project Settings** area and click **Generate new private key**, then **Generate key**. Doing this will download a JSON file containing important information to our PC.


![Generate private key](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698589270518_generate+private+key.png)

![Generate key](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698589270473_generate+key.png)

## Creating a Realtime database

There are two options for databases to select from within Firebase; for this project, either is effective. For this project, we will choose the **Realtime database** as our choice. Thus, enlarge the build section within the Firebase console, select **Realtime database,** and click **Create database.**

![Realtime database build](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698590435208_realtime+database+build.png)

![Create database](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698590740606_create+database.png)


This will prompt a pop-up asking us to set up the database. Select the **United States (us-central1)** as your preferred database location. Select **Start in** **Test mode** for the security rules, as we are not using the database for any production purpose. Then click **Enable** to create the **Realtime database.**


![Set up a database location](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698591130960_setup+database.PNG)

![Set up database security rules](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698591130799_security+rules.PNG)


Now, the database URL is essential for what we want to build — so let’s copy the URL to a safe place and move to the next item on the list.


![Realtime database URL](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698591856293_copy+database+url.png)



## Setting up Appwrite

Now that we have successfully gotten the **private key** and **database URL**, the next step is to create an Appwrite database and cloud function and customize the FCM cloud function template.


## Creating an Appwrite database

After [creating an Appwrite project](#creating-an-appwrite-project), navigate to the database section within the Appwrite console and click **Create database.** Next, we will create a collection with a single `String` attribute called **Token.** This attribute will be the placeholder for the device token generated from the device we intend to receive the push notification.

![create databases](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699890746001_create+database.png)

![Create collections](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699891045846_create+collection.png)
![Create attributes](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699891045887_attributes.png)


After, move to the collection's settings and add permissions by setting the role to **any** and selecting all the **CRUD** (create, read, update, and delete) permissions. Setting permissions allows anyone with the database ID and collection ID (in this case, the admin) to access the notification device token.


![Roles](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699891259594_permissions.png)
![Permissions](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699891259641_permissions+and+roles.png)

## Creating an Appwrite Cloud function FCM template

Appwrite's application of simple yet effective designs makes navigation relatively smooth — this is evident in the creation of **Functions,** as all that is required is to select **Functions** in the console from the navigation bar. To create the FCM template, select the **Create function** button within the function area.


![Functions](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699891477676_function.png)


Then, a pop-up appears, showing all kinds of functions available to the Appwrite cloud. We will proceed to select **All templates** in the bottom right corner.


![All templates](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699891621852_all+templates.png)


In the **All templates** section, we can filter our template search by **use case** or **runtime** or search it by a named keyword. Using the **use case** filter, we will select the messaging option, select **push notification with FCM** among the options given, and click **Create function**.


![fcm_functions](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699897042299_function+fcm.png)


Appwrite further prompts us to sort out the configuration of the function by setting a **name** (any name of our choosing) and **runtime** (Node.js 18.0). 

![Configurations](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699892062777_configuration.png)


The **Variables** section is where the primary business lies, where we must add some information in the **private key JSON file** and the **database URL** copied from the [Firebase project](#setting-up-firebase-cloud-messaging) earlier. So, from the [**private key JSON file**](#generating-a-private-key), we will copy out the **project ID** (alternatively, we can get the **project ID** from the Firebase project settings), **private key,** and **client_email.** Also, we will add the URL from the Realtime database — then, we are good to go.

![Variables](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699892227366_variables.PNG)

![Private key JSON](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698623398582_private+key+json+file.png)

In the **Connect** section, we can add the template to an available repository or create a new one. For the tutorial's sake, we will select **Create a new repository**, then click next to set up the **Git organization** and the **repository name**.


![Connect](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699892403895_connect.PNG)
![Repository](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699892403844_repository.png)


Finally, we can specify our preferred Git branch intended for the template (it is **main** by default). After completing all the steps, we can create a push notification FCM template.


![Branch](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699892790201_branch.PNG)


## Customzing the FCM template code

To customize the FCM template code, head to the repository containing the template code on GitHub, and from the **code** section, navigate to the **src** folder. The **src** folder contains two files: `main.js` and `utils.js`**.**

Update the `main.js` file with the code below:


```javascript
import { throwIfMissing, sendPushNotification } from './utils.js';

export default async ({ req, res, log, error }) => {
    throwIfMissing(process.env, [
        'FCM_PROJECT_ID',
        'FCM_PRIVATE_KEY',
        'FCM_CLIENT_EMAIL',
        'FCM_DATABASE_URL',
    ]);

    try {
        throwIfMissing(req.body, ['deviceToken', 'message']);
        throwIfMissing(req.body.message, ['title', 'body']);
    } catch (err) {
        return res.json({ ok: false, error: err.message }, 400);
    }

    log(`Sending message to device: ${process.env.FCM_PROJECT_ID}`);

    try {
        const response = await sendPushNotification({
            notification: {
                title: req.body.message.title,
                body: req.body.message.body,
            },
            token: req.body.deviceToken,
        });
        log(`Successfully sent message: ${response}`);

        return res.json({ ok: true, messageId: response });
    } catch (e) {
        error(e);
        return res.json({ ok: false, error: `Failed to send the message ${e}` }, 500);
    }
};

```

Also, we will update the `utils.js` file with the code below:


```javascript
import admin from 'firebase-admin';

/**
 * Throws an error if any of the keys are missing from the object
 * @param {*} obj
 * @param {string[]} keys
 * @throws {Error}
 */
export function throwIfMissing(obj, keys) {
    const missing = [];
    for (let key of keys) {
        if (!(key in obj) || !obj[key]) {
            missing.push(key);
        }
    }
    if (missing.length > 0) {
        throw new Error(`Missing required fields: ${missing.join(', ')}`);
    }
}

/**
 * @param {admin.messaging.Message} payload
 * @returns {Promise<string>}
 */

export async function sendPushNotification(payload) {
    if (!admin.apps.length) {
        admin.initializeApp({
            credential: admin.credential.cert({
                projectId: process.env.FCM_PROJECT_ID,
                clientEmail: process.env.FCM_CLIENT_EMAIL,
                privateKey: process.env.FCM_PRIVATE_KEY.replace(/\\n/gm, "\n"),
            }),
            databaseURL: process.env.FCM_DATABASE_URL,
        });
    }
    return await admin.messaging().send(payload);
}
```

After doing that, let’s commit our changes. Due to Appwrite’s connection to our GitHub, the commit automatically triggers the cloud Function to redeploy as it monitors changes in the attached repository.

Now, we’re ready to clone the Flutter applications — both the admin (trigger application) and push notification application (receiver application).


![Joy](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698625757155_2DV.gif)

## Building the Flutter project

Earlier in the [article](#getting-started), we indicated that we would build two Flutter applications during the project. One is the device receiving the push notification; the other will be an admin device that triggers the Appwrite cloud FCM template. Doing this gives us a better use case for push notifications programmatically. Let’s get into it. 
 
## Cloning the application for the notification device

In this section, we will clone the application for the notification device from this [repository](https://github.com/muyiwexy/push_notification_app). The application’s UI contains a button that uploads the phone token obtained from an FCM request.

After cloning the application to local storage, open it in your preferred code editor and run the command below:

```javascript
flutter pub get
```

This command obtains all the dependencies listed in the `pubspec.yaml` file in the current working directory and their transitive dependencies. Next, run the command `flutter run`, and the application should look like the video below:

{% embed https://www.loom.com/share/f5638d03f3294a8f8441868703ce4e77?sid=238b15f3-c79b-4ee8-ae57-446fb7c2d531
%}


To send a push notification, a token from the recipient device must be available to the Firebase cloud messaging service. The question now is,  how can we achieve that? 

The first step involves adding our [Flutter project](#creating-a-flutter-project) to the [Firebase project](#creating-a-firebase-project) created earlier. So, starting with that, we can achieve that manually through the Firebase console or using the **Firebase CLI** (command line interface).

The **Firebase CLI** is a simple tool that allows easy interactions with Firebase using the command line. The **Firebase CLI** provides commands that let us send specific requests to Firebase and get adequate responses. Some of these requests include the following:


- Project Setup
- Authentication and Authorization
- Real-time Database
- Hosting
- Cloud Functions
- Cloud Storage
- Firestore
- Test Lab
- Analytics

Thus, to use the Firebase CLI for project setup within a Flutter project, let’s head back to the [Firebase console](#creating-a-firebase-project). Within the base console are two options for connecting an Android application to Firebase. So, we will select the second option that says **Flutter.**


![flutter project](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698698126048_create+flutter+project.png)


When we click the option, the first step asks that we install the [Firebase CLI.](https://firebase.google.com/docs/cli?hl=en&authuser=0&_gl=1*tcd4ob*_ga*MTc5MzYyNzA1NC4xNjk4MDYyNDUz*_ga_CW55HF8NVT*MTY5ODY5NzgzMC4yNC4xLjE2OTg2OTgxMzUuNjAuMC4w#windows-standalone-binary) According to the link, there are several methods we can follow to install the [Firebase CLI](https://firebase.google.com/docs/cli?hl=en&authuser=0&_gl=1*tcd4ob*_ga*MTc5MzYyNzA1NC4xNjk4MDYyNDUz*_ga_CW55HF8NVT*MTY5ODY5NzgzMC4yNC4xLjE2OTg2OTgxMzUuNjAuMC4w#windows-standalone-binary), depending on our device’s operating system. We will use the node package manager (npm) to install the CLI for uniformity. Here is a guide on [how to install Node.js](https://www.pluralsight.com/guides/getting-started-with-nodejs) on your device.

After installing Node.js, run the command below within your terminal:

```javascript
npm install -g firebase-tools
```


![firebase cli](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698698762380_installing+firebase+cli.PNG)

Doing this automatically installs the **Firebase CLI** to our preferred device, and with that, we can proceed to the next step of logging into our Firebase console via the CLI. To do that, we will use the command:

```javascript
firebase login
```

After logging into the **Firebase CLI**, we must install the [FlutterFire plugin](https://firebase.flutter.dev/docs/overview/#:~:text=FlutterFire%20is%20a%20set%20of,your%20Flutter%20application%20to%20Firebase.) to create a new Firebase project in Dart. FlutterFire is a set of plugins that connects our Flutter project to Firebase. To activate the [FlutterFire plugin](https://firebase.flutter.dev/docs/overview/#:~:text=FlutterFire%20is%20a%20set%20of,your%20Flutter%20application%20to%20Firebase.) on our PC, use the following command:

```javascript
dart pub global activate flutterfire_cli
```

To use the [FlutterFire plugin](https://firebase.flutter.dev/docs/overview/#:~:text=FlutterFire%20is%20a%20set%20of,your%20Flutter%20application%20to%20Firebase.) to configure our Firebase project within the Flutter app, we must open a terminal within the Flutter project folder and then run this command:

```javascript
flutterfire configure --project=<Firebase Project ID>
```


> Note: Remember to change the `<Firebase Project ID>` in the command above to the ID of the Firebase project.


![flutter_fire](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698700121567_flutter+fire1.PNG)

![flutter_fire_2](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698700121500_flutter+fire2.PNG)


After selecting what platform(s) the configuration should support, the CLI will add some essential files to the Flutter project, and we are good to proceed.

Next, we will connect our Flutter application to Appwrite. We do this to upload the generated token from our notification device to a general database — this allows a central admin to access the token and send push notifications accordingly to several devices.

Here is how to connect an IOS or Android device in Flutter to Appwrite:



## iOS

First, obtain the `bundle ID` by navigating to the `project.pbxproj` file (`ios > Runner.xcodeproj > project.pbxproj`) and searching for the `PRODUCT_BUNDLE_IDENTIFIER`.

Next, navigate to the `Runner.xcworkspace` folder in the application’s iOS folder in the project directory on [Xcode](https://developer.apple.com/xcode/). To select the runner target, choose the **Runner** project in the Xcode project navigator and find the `Runner target`. Next, select `General and IOS 11.0` as the target in the deployment info section.


![iOS](https://paper-attachments.dropboxusercontent.com/s_973FE6248EEDD7529E7A11435E297ADACD4E1B7483EB53A8303EEED9486C6A4E_1677590542497_file.jpeg)



## Android

For Android, copy the XML script below and paste it below the activity tag in the `Androidmanifest.xml` file (to find this file, head to `android > app > src > main`).

{% embed https://gist.github.com/muyiwexy/f1a0f6c59329d25d37c353f34a4fa9aa %}


> Note: change [PROJECT-ID] to the ID you used when creating the Appwrite project.

We will also need to set up a platform within the Appwrite console. Follow the steps below to do so.

- Within the Appwrite console, select `Create Platform` and choose `Flutter` for the platform type.
- Specify the operating system: in this case, Android.
- Finally, provide the application and package names (found in the app-level `build.gradle` file).

![Create platform 1](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699897340142_account+information.png)

![Create platform 2](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699897340061_platform.png)


## Cloning the application for the admin device

In this section, we will clone the application for the admin device. The application’s UI contains a button that triggers the cloud function.  Let’s clone the [repository](https://github.com/muyiwexy/application_admin) specified in the prerequisites. 

After cloning the application to local storage, we will open it in our preferred code editor and run the command below:

```javascript
flutter pub get
```

This command obtains all the dependencies listed in the `pubspec.yaml` file in the current working directory and their transitive dependencies. Next, run the command `flutter run`, and our application should look like the images below:


![admin](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698704216806_admin+app+login+page.png)

![send_push_notification](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698704277536_send+push+notification.PNG)


So, when we click the `Send Push Notification` button, it triggers this function in the `app_controller.dart` file:


```javascript
void sendNotification(String token) async {
    try {
      final Map < String, dynamic > requestBody = {
            'deviceToken': token,
                'message': {
                'title': 'Notification Title',
                    'body': 'Notification Body',
        },
        };
      final result = await functions.createExecution(
            functionId: Appconstants.functionId,
            body: jsonEncode(requestBody),
            path: '/',
            method: 'POST',
            headers: {
            'Content-Type': 'application/json',
        },
        );
    } catch (e) {
        print(e);
    }
}
```

This function encodes a `Map<String, dynamic>` into a `JSON` and programmatically sends a `POST` request to the Appwrite Function. Without an admin page, we can trigger these notifications within the Appwrite console.

To do this, navigate to the Function section of the console, and within the FCM cloud function template, select `Execute now`.


![function_fcm](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699897736717_function+fcm.png)
![execute_fcm](https://paper-attachments.dropboxusercontent.com/s_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699897736659_execute+function.png)


We will leave the **Path** as it is in the pop-up, but we‘ll change the method to **POST**. In the **Advanced settings** section within the pop-up, add a Header with its name being **Content-Type** and value being `application/json`. Finally, in the body section, we will add a `JSON` that looks like the format below:

```javascript
{
    "deviceToken": "<notification device token>",
        "message": {
        "title": "hi",
            "body": "how are you"
    }
}
```

Then we will execute the function, and the result should look like the GIF below:

{% embed https://www.loom.com/share/3cfab1bb1a8d440787a2b910b1235d46?sid=0f06f132-6d55-4202-838b-e99715e03eb1
%}

## Conclusion

Push notifications are hugely important in modern applications. By incorporating push notifications into our Appwrite Cloud applications, we can keep our users informed and engaged. Leveraging this powerful communication channel ensures that our audience receives timely updates, personalized messages, and essential information — enhancing their overall experience. 

With our backend configuration and error handling in place, we can reliably deliver push notifications while minimizing potential issues. Integrating push notifications into our applications is a valuable strategy for boosting user engagement and ensuring effective communication with our user base.

## Resources

Here are some additional resources that you might find useful.

- [Appwrite databases](https://appwrite.io/docs/references/cloud/client-web/databases?utm_source=hackmamba&utm_medium=hackmamba-blog)
- [Appwrite functions](https://appwrite.io/docs/references/cloud/client-web/functions?utm_source=hackmamba&utm_medium=hackmamba-blog)
- [Appwrite account](https://appwrite.io/docs/references/cloud/client-web/account?utm_source=hackmamba&utm_medium=hackmamba-blog)
- [Serverless notifications with Cloud Functions for Firebase](https://medium.com/android-news/serverless-notifications-with-cloud-functions-for-firebase-685d7c327cd4?utm_source=hackmamba&utm_medium=hackmamba-blog)