1. Overview
In this codelab, you'll learn how to use Cloud Functions for Firebase to add functionality to a chat web app by sending notifications to users of the chat app.

What you'll learn
- Create Google Cloud Functions using the Firebase SDK.
- Trigger Cloud Functions based on Auth, Cloud Storage, and Cloud Firestore events.
- Add Firebase Cloud Messaging support to your web app.
What you'll need
- A credit card. Cloud Functions for Firebase requires the Firebase Blaze plan, which means you will have to enable billing on your Firebase project using a credit card.
- The IDE/text editor of your choice such as WebStorm , Atom or Sublime .
- A terminal to run shell commands with NodeJS v9 installed.
- A browser such as Chrome.
- The sample code. See next step for this.
2. Get the sample code
Clone the GitHub repository from the command line:
git clone https://github.com/firebase/friendlychat
Import the starter app
Using your IDE, open or import the
cloud-functions-start
directory from the sample code directory. This directory contains the starting code for the codelab which consists of a fully functional Chat Web App.
3. Create a Firebase project and Set up your app
Create project
- Sign into the Firebase console using your Google Account.
- Click the button to create a new project, and then enter a project name (for example,
FriendlyChat).
- Click Continue.
- If prompted, review and accept the Firebase terms , and then click Continue.
- (Optional) Enable AI assistance in the Firebase console (called "Gemini in Firebase").
- For this codelab, you do not need Google Analytics, so toggle off the Google Analytics option.
- Click Create project, wait for your project to provision, and then click Continue.
Upgrade to the Blaze plan
To use Cloud Functions for Firebase and Cloud Storage for Firebase, your Firebase project needs to be on the pay-as-you go (Blaze) pricing plan , which means it's linked to a Cloud Billing account .
- A Cloud Billing account requires a payment method, like a credit card.
- If you're new to Firebase and Google Cloud, check if you're eligible for a $300 credit and a Free Trial Cloud Billing account .
- If you're doing this codelab as part of an event, ask your organizer if there are any Cloud credits available.
If you do not have access to a credit card or are uncomfortable continuing with the Blaze pricing plan, consider using the Firebase Emulator Suite which will allow you to emulate Cloud Functions for free on your local machine.
All Firebase projects, including those on the Blaze pricing plan, still have access to no-cost usage quotas for Cloud Functions. The steps outlined in this codelab will fall within the free tier usage limits. However, you will see small charges ( about $0.03 ) from Cloud Storage which is used to host your Cloud Functions build images.
To upgrade your project to the Blaze plan, follow these steps:
- In the Firebase console, select to upgrade your plan .
- Select the Blaze plan. Follow the on-screen instructions to link a Cloud Billing account to your project.
If you needed to create a Cloud Billing account as part of this upgrade, you might need to navigate back to the upgrade flow in the Firebase console to complete the upgrade.
Enable Google Auth
To let users sign-in the app, we'll use Google auth which needs to be enabled.
In Firebase Console, open the Buildsection > Authentication> Sign-in methodtab (or click here to go there). Then, enable the GoogleSign-in Provider and click Save. This will allow users to sign in on the web app with their Google accounts.
Also, feel free to set the public facing name of your app to Friendly Chat:

Set up Cloud Storage for Firebase
The app uses Cloud Storage to upload pictures.
Here's how to set up Cloud Storage for Firebase in your Firebase project:
- In the left-panel of the Firebase console, expand Buildand then select Storage .
- Click Get started.
- Select a location for your default Storage bucket.
Buckets inUS-WEST1,US-CENTRAL1, andUS-EAST1can take advantage of the "Always Free" tier for Google Cloud Storage. Buckets in all other locations follow Google Cloud Storage pricing and usage . - Click Start in test mode. Read the disclaimer about the security rules.
Do not distribute or expose an app publicly without adding Security Rules for your Storage bucket. - Click Create.
Add a Web App
On Firebase Console, add a web app. To do so, go to Project Settings and scroll down to Add app. Pick web as the platform and check the box for setting up Firebase Hosting, then register the app and click Nextfor the remainder of the steps, lastly clicking on Continue to console.
4. Install the Firebase Command Line Interface
The Firebase Command Line Interface (CLI) will allow you to serve the web app locally and deploy your web app and Cloud Functions.
To install or upgrade the CLI run the following npm command:
npm
-
g
install
firebase
-
tools
To verify that the CLI has been installed correctly, open a console and run:
firebase --version
Make sure the version of the Firebase CLI is above 4.0.0so that it has all the latest features required for Cloud Functions. If not, run npm install -g firebase-tools
to upgrade as shown above.
Authorize the Firebase CLI by running:
firebase login
Make sure you are in the cloud-functions-start
directory, then set up the Firebase CLI to use your Firebase Project:
firebase use --add
Next, select your Project ID and follow the instructions. When prompted, you can choose any Alias, such as codelab
.
5. Deploy and run the web app
Now that you have imported and configured your project, you are ready to run the web app for the first time! Open a terminal window, navigate to the cloud-functions-start
folder, and deploy the web app to Firebase hosting using:
firebase deploy --except functions
This is the console output you should see:
i
deploying
database
,
storage
,
hosting
✔
database
:
rules
ready
to
deploy
.
i
storage
:
checking
rules
for
compilation
errors
...
✔
storage
:
rules
file
compiled
successfully
i
hosting
:
preparing
./
directory
for
upload
...
✔
hosting
:
./
folder
uploaded
successfully
✔
storage
:
rules
file
compiled
successfully
✔
hosting
:
8
files
uploaded
successfully
i
starting
release
process
(
may
take
several
minutes
)
...
✔
Deploy
complete
!
Project
Console
:
https
:
//
console
.
firebase
.
google
.
com
/
project
/
friendlychat
-
1234
/
overview
Hosting
URL
:
https
:
//
friendlychat
-
1234.
firebaseapp
.
com
Open the web app
The last line should display the Hosting URL.The web app should now be served from this URL, which should be of the form https://<project-id>.firebaseapp.com. Open it. You should see a chat app's functioning UI.
Sign-in to the app by using the SIGN-IN WITH GOOGLEbutton and feel free to add some messages and post images:

If you sign-in the app for the first time on a new browser, make sure you allow notifications when prompted:
We'll need to have notifications enabled at a later point.
If you have accidentally clicked Block, you can change this setting by clicking on the 🔒 Securebutton on the left of the URL in the Chrome Omnibar and toggling the bar next to Notifications:

Now, we'll be adding some functionality using the Firebase SDK for Cloud Functions.
6. The Functions Directory
Cloud Functions allows you to easily have code that runs in the Cloud without having to setup a server. We'll be walking through how to build functions that react to Firebase Auth, Cloud Storage, and Firebase Firestore database events. Let's start with Auth.
When using the Firebase SDK for Cloud Functions, your Functions code will live under the functions
directory (by default). Your Functions code is also a Node.js
app and therefore needs a package.json
that gives some information about your app and lists dependencies.
To make it easier for you, we've already created the functions/index.js
file where your code will go. Feel free to inspect this file before moving forward.
cd functions
ls
If you are not familiar with Node.js , learning more about it before continuing the codelab would be helpful.
The package.json
file already lists two required dependencies: the Firebase SDK for Cloud Functions
and the Firebase Admin SDK
. To install them locally, go to the functions
folder and run:
npm install
Let's now have a look at the index.js
file:
index.js
/**
*
Copyright
2017
Google
Inc
.
All
Rights
Reserved
.
*
...
*/
// TODO(DEVELOPER): Import the Cloud Functions for Firebase and the Firebase Admin modules here.
// TODO(DEVELOPER): Write the addWelcomeMessage Function here.
// TODO(DEVELOPER): Write the blurImages Function here.
// TODO(DEVELOPER): Write the sendNotification Function here.
We'll import the required modules and then write three Functions in place of the TODOs. Let's start with importing the required Node modules.
7. Import the Cloud Functions and Firebase Admin modules
Two modules will be required during this codelab: firebase-functions
enables writing Cloud Functions triggers and logs while firebase-admin
enables using the Firebase platform on a server with admin access to do actions such as writing to Cloud Firestore or sending FCM notifications.
In the index.js
file, replace the first TODO
with the following:
index.js
/**
*
Copyright
2017
Google
Inc
.
All
Rights
Reserved
.
*
...
*/
//
Import
the
Firebase
SDK
for
Google
Cloud
Functions
.
const
functions
=
require
(
'firebase-functions'
);
//
Import
and
initialize
the
Firebase
Admin
SDK
.
const
admin
=
require
(
'firebase-admin'
);
admin
.
initializeApp
();
//
TODO
(
DEVELOPER
):
Write
the
addWelcomeMessage
Function
here
.
//
TODO
(
DEVELOPER
):
Write
the
blurImages
Function
here
.
//
TODO
(
DEVELOPER
):
Write
the
sendNotification
Function
here
.
The Firebase Admin SDK can be configured automatically when deployed to a Cloud Functions environment or other Google Cloud Platform containers, and this happens when we call admin.initializeApp()
with no arguments.
Now, let's add a Function that runs when a user signs in for the first time in the chat app, and we'll add a chat message to welcome the user.
8. Welcome New Users
Chat messages structure
Messages posted to the FriendlyChat chat feed are stored in Cloud Firestore. Let's have a look at the data structure we use for a message. To do this, post a new message to the chat that reads "Hello World":

This should appear as:

In Firebase Console, click on Firestore Databaseunder the Buildsection. You should see the messages collection and one document containing the message that you wrote:

As you can see, chat messages are stored in Cloud Firestore as a document with name
, profilePicUrl
, text
, and timestamp
attributes added to the messages
collection.
Adding welcome messages
The first Cloud Function adds a message that welcomes new usersto the chat. For this, we can use the trigger functions.auth().onCreate
, which runs the function every time a user signs-in for the first time in the Firebase app. Add the addWelcomeMessages
function into your index.js
file:
index.js
//
Adds
a
message
that
welcomes
new
users
into
the
chat
.
exports
.
addWelcomeMessages
=
functions
.
auth
.
user
()
.
onCreate
(
async
(
user
)
=
>
{
functions
.
logger
.
log
(
'A new user signed in for the first time.'
);
const
fullName
=
user
.
displayName
||
'Anonymous'
;
//
Saves
the
new
welcome
message
into
the
database
//
which
then
displays
it
in
the
FriendlyChat
clients
.
await
admin
.
firestore
()
.
collection
(
'messages'
)
.
add
({
name
:
'Firebase Bot'
,
profilePicUrl
:
'/images/firebase-logo.png'
,
//
Firebase
logo
text
:
`
$
{
fullName
}
signed
in
for
the
first
time
!
Welcome
!
`
,
timestamp
:
admin
.
firestore
.
FieldValue
.
serverTimestamp
(),
});
functions
.
logger
.
log
(
'Welcome message written to database.'
);
});
Adding this function to the special exports
object is Node's way of making the function accessible outside of the current file and is required for Cloud Functions.
In the function above, we are adding a new welcome message posted by "Firebase Bot" to the list of chat messages. We are doing this by using the add
method on the messages
collection in Cloud Firestore, which is where the messages of the chat are stored.
Since this is an asynchronous operation, we need to return the Promise indicating when Cloud Firestore has finished writing so the Cloud Functions don't execute too early.
Deploy Cloud Functions
Cloud Functions will only be active after you've deployed them. To do so, run this on the command line:
firebase deploy --only functions
This is the console output you should see:
i
deploying
functions
i
functions
:
ensuring
necessary
APIs
are
enabled
...
⚠
functions
:
missing
necessary
APIs
.
Enabling
now
...
i
env
:
ensuring
necessary
APIs
are
enabled
...
⚠
env
:
missing
necessary
APIs
.
Enabling
now
...
i
functions
:
waiting
for
APIs
to
activate
...
i
env
:
waiting
for
APIs
to
activate
...
✔
env
:
all
necessary
APIs
are
enabled
✔
functions
:
all
necessary
APIs
are
enabled
i
functions
:
preparing
functions
directory
for
uploading
...
i
functions
:
packaged
functions
(
X
.
XX
KB
)
for
uploading
✔
functions
:
functions
folder
uploaded
successfully
i
starting
release
process
(
may
take
several
minutes
)...
i
functions
:
creating
function
addWelcomeMessages
...
✔
functions
[
addWelcomeMessages
]
:
Successful
create
operation
.
✔
functions
:
all
functions
deployed
successfully
!
✔
Deploy
complete
!
Project
Console
:
https
:
//
console
.
firebase
.
google
.
com
/
project
/
friendlypchat
-
1234
/
overview
Test the function
Once the function has deployed successfully, you'll need to have a user that signs in for the first time.
- Open your app in your browser using the hosting URL (in the form of
https://<project-id>.firebaseapp.com). - With a new user, sign in for the first time in your app using the Sign Inbutton.
- If you have already signed into the, app you can open Firebase Console Authentication and delete your account from the list of users. Then, sign in again.

- After you sign in, a welcome message should be displayed automatically:

9. Images moderation
Users can upload all type of images in the chat, and it is always important to moderate offensive images, especially in public social platforms. In FriendlyChat, the images that are being published to the chat are stored into Cloud Storage buckets.
With Cloud Functions, you can detect new image uploads using the functions.storage().onFinalize
trigger. This will run every time a new file is uploaded or modified in Cloud Storage.
To moderate images, we'll go through the following process:
- Check if the image is flagged as Adult or Violent using the Cloud Vision API .
- If the image has been flagged, download it on the running Functions instance.
- Blur the image using ImageMagick .
- Upload the blurred image to Cloud Storage.
Enable the Cloud Vision API
Since we'll be using the Google Cloud Vision API in this function, you must enable the API on your firebase project. Follow this link , then select your Firebase project and enable the API:

Install dependencies
To moderate images, we'll use the Google Cloud Vision Client Library for Node.js, @google-cloud/vision , to run images through the Cloud Vision API to detect inappropriate images.
To install this package into your Cloud Functions app, run the following npm install --save
command. Make sure that you do this from the functions
directory.
npm
install
--
save
@
google
-
cloud
/
vision
@2.4.0
This will install the package locally and add them as a declared dependency in your package.json
file.
Import and configure dependencies
To import the dependencies that were installed and some Node.js core modules ( path
, os
and fs
) that we'll need in this section, add the following lines to the top of your index.js
file:
index.js
const
Vision
=
require
(
'@google-cloud/vision'
);
const
vision
=
new
Vision
.
ImageAnnotatorClient
();
const
{
promisify
}
=
require
(
'util'
);
const
exec
=
promisify
(
require
(
'child_process'
)
.
exec
);
const
path
=
require
(
'path'
);
const
os
=
require
(
'os'
);
const
fs
=
require
(
'fs'
);
Since your function will run inside a Google Cloud environment, there is no need to configure the Cloud Storage and Cloud Vision libraries: they will be configured automatically to use your project.
Detecting inappropriate images
You'll be using the functions.storage.onChange
Cloud Functions trigger, which runs your code as soon as a file or folder is created or modified in a Cloud Storage bucket. Add the blurOffensiveImages
Function into your index.js
file:
index.js
//
Checks
if
uploaded
images
are
flagged
as
Adult
or
Violence
and
if
so
blurs
them
.
exports
.
blurOffensiveImages
=
functions
.
runWith
({
memory
:
'2GB'
})
.
storage
.
object
()
.
onFinalize
(
async
(
object
)
=
>
{
const
imageUri
=
`
gs
:
//$
{
object
.
bucket
}
/$
{
object
.
name
}
`
;
//
Check
the
image
content
using
the
Cloud
Vision
API
.
const
batchAnnotateImagesResponse
=
await
vision
.
safeSearchDetection
(
imageUri
);
const
safeSearchResult
=
batchAnnotateImagesResponse
[
0
]
.
safeSearchAnnotation
;
const
Likelihood
=
Vision
.
protos
.
google
.
cloud
.
vision
.
v1
.
Likelihood
;
if
(
Likelihood
[
safeSearchResult
.
adult
]
> =
Likelihood
.
LIKELY
||
Likelihood
[
safeSearchResult
.
violence
]
> =
Likelihood
.
LIKELY
)
{
functions
.
logger
.
log
(
'The image'
,
object
.
name
,
'has been detected as inappropriate.'
);
return
blurImage
(
object
.
name
);
}
functions
.
logger
.
log
(
'The image'
,
object
.
name
,
'has been detected as OK.'
);
});
Note that we added some configuration of the Cloud Functions instance that will run the function. With .runWith({memory: '2GB'})
, we're requesting that the instance gets 2GB of memory rather than the default, because this function is memory intensive.
When the function is triggered, the image is ran through the Cloud Vision API to detect if it is flagged as adult or violent. If the image is detected as inappropriate based on these criteria, we're blurring the image, which is done in the blurImage
function as we'll see next.
Blurring the image
Add the following blurImage
function in your index.js
file:
index.js
//
Blurs
the
given
image
located
in
the
given
bucket
using
ImageMagick
.
async
function
blurImage
(
filePath
)
{
const
tempLocalFile
=
path
.
join
(
os
.
tmpdir
(),
path
.
basename
(
filePath
));
const
messageId
=
filePath
.
split
(
path
.
sep
)[
1
];
const
bucket
=
admin
.
storage
()
.
bucket
();
//
Download
file
from
bucket
.
await
bucket
.
file
(
filePath
)
.
download
({
destination
:
tempLocalFile
});
functions
.
logger
.
log
(
'Image has been downloaded to'
,
tempLocalFile
);
//
Blur
the
image
using
ImageMagick
.
await
exec
(
`
convert
"${tempLocalFile}"
-
channel
RGBA
-
blur
0x24
"${tempLocalFile}"
`
);
functions
.
logger
.
log
(
'Image has been blurred'
);
//
Uploading
the
Blurred
image
back
into
the
bucket
.
await
bucket
.
upload
(
tempLocalFile
,
{
destination
:
filePath
});
functions
.
logger
.
log
(
'Blurred image has been uploaded to'
,
filePath
);
//
Deleting
the
local
file
to
free
up
disk
space
.
fs
.
unlinkSync
(
tempLocalFile
);
functions
.
logger
.
log
(
'Deleted local file.'
);
//
Indicate
that
the
message
has
been
moderated
.
await
admin
.
firestore
()
.
collection
(
'messages'
)
.
doc
(
messageId
)
.
update
({
moderated
:
true
});
functions
.
logger
.
log
(
'Marked the image as moderated in the database.'
);
}
In the above function, the image binary is downloaded from Cloud Storage. The image is then blurred using ImageMagick's convert
tool, and the blurred version is re-uploaded on the Storage Bucket. Next, we delete the file on the Cloud Functions instance to free up some disk space, and we do this because the same Cloud Functions instance can get re-used and if files are not cleaned up, it could run out of disk space. Finally, we add a boolean to the chat message indicating the image was moderated, and this will trigger a refresh of the message on the client.
Deploy the Function
The Function will only be active after you've deployed it. On the command line, run firebase deploy --only functions
:
firebase deploy --only functions
This is the console output you should see:
i
deploying
functions
i
functions
:
ensuring
necessary
APIs
are
enabled
...
✔
functions
:
all
necessary
APIs
are
enabled
i
functions
:
preparing
functions
directory
for
uploading
...
i
functions
:
packaged
functions
(
X
.
XX
KB
)
for
uploading
✔
functions
:
functions
folder
uploaded
successfully
i
starting
release
process
(
may
take
several
minutes
)...
i
functions
:
updating
function
addWelcomeMessages
...
i
functions
:
creating
function
blurOffensiveImages
...
✔
functions
[
addWelcomeMessages
]
:
Successful
update
operation
.
✔
functions
[
blurOffensiveImages
]
:
Successful
create
operation
.
✔
functions
:
all
functions
deployed
successfully
!
✔
Deploy
complete
!
Project
Console
:
https
:
//
console
.
firebase
.
google
.
com
/
project
/
friendlychat
-
1234
/
overview
Test the function
Once the function has deployed successfully:
- Open your app in your browser using the hosting URL (in the form of
https://<project-id>.firebaseapp.com). - Once signed into the app, upload an image:

- Choose your best offensive image to upload (or you can use this flesh eating Zombie
!) and after a few moments, you should see your post refresh with a blurred version of the image:

10. New Message Notifications
In this section, you will add a Cloud Function that sends notifications to participants of the chat when a new message is posted.
Using Firebase Cloud Messaging
(FCM), you can reliably send notifications to users across platforms. To send a notification to a user, you need their FCM device token. The chat web app that we are using already collects device tokens from users when they open the app for the first time on a new browser or device. These tokens are stored in Cloud Firestore in the fcmTokens
collection.
If you would like to learn how to get FCM device tokens on a web app, you can go through the Firebase Web Codelab .
Send notifications
To detect when new messages are posted, you'll be using the functions.firestore.document().onCreate
Cloud Functions trigger, which runs your code when a new object is created at a given path of Cloud Firestore. Add the sendNotifications
function into your index.js
file:
index.js
//
Sends
a
notifications
to
all
users
when
a
new
message
is
posted
.
exports
.
sendNotifications
=
functions
.
firestore
.
document
(
'messages/{messageId}'
)
.
onCreate
(
async
(
snapshot
)
=
>
{
//
Notification
details
.
const
text
=
snapshot
.
data
()
.
text
;
const
payload
=
{
notification
:
{
title
:
`
$
{
snapshot
.
data
()
.
name
}
posted
$
{
text
?
'a message'
:
'an image'
}
`
,
body
:
text
?
(
text
.
length
< =
100
?
text
:
text
.
substring
(
0
,
97
)
+
'...'
)
:
''
,
icon
:
snapshot
.
data
()
.
profilePicUrl
||
'/images/profile_placeholder.png'
,
click_action
:
`
https
:
//$
{
process
.
env
.
GCLOUD_PROJECT
}
.
firebaseapp
.
com
`
,
}
};
//
Get
the
list
of
device
tokens
.
const
allTokens
=
await
admin
.
firestore
()
.
collection
(
'fcmTokens'
)
.
get
();
const
tokens
=
[];
allTokens
.
forEach
((
tokenDoc
)
=
>
{
tokens
.
push
(
tokenDoc
.
id
);
});
if
(
tokens
.
length
>
0
)
{
//
Send
notifications
to
all
tokens
.
const
response
=
await
admin
.
messaging
()
.
sendToDevice
(
tokens
,
payload
);
await
cleanupTokens
(
response
,
tokens
);
functions
.
logger
.
log
(
'Notifications have been sent and tokens cleaned up.'
);
}
});
In the Function above, we are gathering all users' device tokens from the Cloud Firestore database and sending a notification to each of these using the admin.messaging().sendToDevice
function.
Cleanup the tokens
Lastly, we want to remove the tokens that are no longer valid. This happens when the token that we once got from the user is not being used by the browser or device anymore. For instance, this happens if the user has revoked the notification permission for the browser session. To do this, add the following cleanupTokens
function in your index.js
file:
index.js
//
Cleans
up
the
tokens
that
are
no
longer
valid
.
function
cleanupTokens
(
response
,
tokens
)
{
//
For
each
notification
we
check
if
there
was
an
error
.
const
tokensDelete
=
[]
;
response
.
results
.
forEach
((
result
,
index
)
=
>
{
const
error
=
result
.
error
;
if
(
error
)
{
functions
.
logger
.
error
(
'Failure sending notification to'
,
tokens
[
index
]
,
error
);
//
Cleanup
the
tokens
that
are
not
registered
anymore
.
if
(
error
.
code
===
'messaging/invalid-registration-token'
||
error
.
code
===
'messaging/registration-token-not-registered'
)
{
const
deleteTask
=
admin
.
firestore
().
collection
(
'fcmTokens'
).
doc
(
tokens
[
index
]
).
delete
();
tokensDelete
.
push
(
deleteTask
);
}
}
}
);
return
Promise
.
all
(
tokensDelete
);
}
Deploy the Function
The function will only be active after you've deployed it, and to deploy it, run this in command line:
firebase deploy --only functions
This is the console output you should see:
i
deploying
functions
i
functions
:
ensuring
necessary
APIs
are
enabled
...
✔
functions
:
all
necessary
APIs
are
enabled
i
functions
:
preparing
functions
directory
for
uploading
...
i
functions
:
packaged
functions
(
X
.
XX
KB
)
for
uploading
✔
functions
:
functions
folder
uploaded
successfully
i
starting
release
process
(
may
take
several
minutes
)...
i
functions
:
updating
function
addWelcomeMessages
...
i
functions
:
updating
function
blurOffensiveImages
...
i
functions
:
creating
function
sendNotifications
...
✔
functions
[
addWelcomeMessages
]
:
Successful
update
operation
.
✔
functions
[
blurOffensiveImages
]
:
Successful
updating
operation
.
✔
functions
[
sendNotifications
]
:
Successful
create
operation
.
✔
functions
:
all
functions
deployed
successfully
!
✔
Deploy
complete
!
Project
Console
:
https
:
//
console
.
firebase
.
google
.
com
/
project
/
friendlychat
-
1234
/
overview
Test the function
- Once the function has deployed successfully, open your app in your browser using the hosting URL (in the form of
https://<project-id>.firebaseapp.com). - If you sign-in the app for the first time, make sure you allow notifications when prompted:

- Close the chat app tab or display a different tab: Notifications appear only if the app is in the background. If you would like to learn how to receive messages while your app is in the foreground, have a look at our documentation .
- Using a different browser (or an Incognito window), sign into the app and post a message. You should see a notification displayed by the first browser:

11. Congratulations!
You have used the Firebase SDK for Cloud Functions and added server-side components to a chat app.
What we've covered
- Authoring Cloud Functions using the Firebase SDK for Cloud Functions.
- Trigger Cloud Functions based on Auth, Cloud Storage, and Cloud Firestore events.
- Add Firebase Cloud Messaging support to your web app.
- Deploy Cloud Functions using the Firebase CLI.
Next Steps
- Learn about other Cloud Function trigger types .
- Use Firebase and Cloud Functions with your own app.

