Node Push Notifications
A node.js module for interfacing with Apple Push Notification, Google Cloud Messaging, Windows Push Notification, Web-Push Notification and Amazon Device Messaging services.

Installation
npm install node-pushnotifications --save
Requirements
Node version >= 14.x.x
Features
- Powerful and intuitive.
- Multi platform push notifications.
- Automatically detects destination device type.
- Unified error handling.
- Written in ES6, compatible with ES5 through babel transpilation.
Usage
1. Import and setup push module
Include the settings for each device type. You should only include the settings for the devices that you expect to have. I.e. if your app is only available for Android or for iOS, you should only include fcm or apn respectively.
import PushNotifications from 'node-pushnotifications';
const settings = {
fcm: {
appName: 'localFcmAppName',
serviceAccountKey: require('../firebase-project-service-account-key.json'),
credential: null,
projectId: 'your-project-id',
databaseURL: 'https://your-database.firebaseio.com',
storageBucket: 'your-bucket.appspot.com',
serviceAccountId: 'your-email@your-project.iam.gserviceaccount.com',
httpAgent: undefined,
httpsAgent: undefined,
},
apn: {
token: {
key: './certs/key.p8',
keyId: 'ABCD',
teamId: 'EFGH',
},
production: false
...
},
adm: {
client_id: null,
client_secret: null,
...
},
wns: {
client_id: null,
client_secret: null,
notificationMethod: 'sendTileSquareBlock',
...
},
web: {
vapidDetails: {
subject: '< \'mailto\' Address or URL >',
publicKey: '< URL Safe Base64 Encoded Public Key >',
privateKey: '< URL Safe Base64 Encoded Private Key >',
},
TTL: 2419200,
contentEncoding: 'aes128gcm',
headers: {}
},
isAlwaysUseFCM: false,
};
const push = new PushNotifications(settings);
isAlwaysUseFCM: when set to true, will send all notifications through FCM instead of platform-specific services
iOS: It is recommended to use provider authentication tokens. You need the .p8 certificate that you can obtain in your account membership. You should ask for an Apple Push Notification Authentication Key (Sandbox & Production) or Apple Push Notification service SSL (Sandbox & Production). However, you can also use certificates. See node-apn to see how to prepare cert.pem and key.pem.
2. Define destination device ID
Registration id's should be defined as objects (or strings which is not recommended and should be used at your own risk, it is kept for backwards compatibility).
You can send to multiple devices, independently of platform, creating an array with different destination device IDs.
const registrationIds = 'INSERT_YOUR_DEVICE_ID';
const registrationIds = [];
registrationIds.push('INSERT_YOUR_DEVICE_ID');
registrationIds.push('INSERT_OTHER_DEVICE_ID');
The PN.send() method later detects device type and therefore used push method, based on the id stucture. Check out the method PN.getPushMethodByRegId how this detection works.
Actually there are several different supported reg id's:
Object regId
It can be of 2 types:
{
"id": "INSERT_YOUR_DEVICE_ID",
"type": "apn"
}
Where type can be one of: 'apn', 'fcm', 'adm', 'wns', 'webPush'. The types are available as constants:
import { WEB, WNS, ADM, FCM, APN } from 'node-pushnotifications';
const regId = {
id: 'INSERT_YOUR_DEVICE_ID',
type: APN,
};
In case of webPush, id needs to be as defined below for Web subscription.
{
"endpoint": "< Push Subscription URL >",
"keys": {
"p256dh": "< User Public Encryption Key >",
"auth": "< User Auth Secret >"
}
}
String regId (not recommended)
It is not recommended, as the reg id is of variable length, which makes it difficult to identify if it is an APN regId or FCM regId.
regId.substring(0, 4) === 'http': 'wns'
/^(amzn[0-9]*.adm)/i.test(regId): 'adm'
(regId.length === 64 || regId.length === 160) && /^[a-fA-F0-9]+$/.test(regId): 'apn'
regId.length > 64: 'fcm'
- otherwise: 'unknown' (the notification will not be sent)
Android:
- All Android notifications are sent through Firebase Cloud Messaging (FCM)
- If you provide more than 1.000 registration tokens, they will automatically be split into 1.000 chunks
- You are able to send to custom topics or conditions through FCM (see firebase-admin docs)
Example:
const data = { ...data, recipients };
3. Send the notification
Create a JSON object with a title and message and send the notification.
const data = {
title: 'New push notification',
topic: 'topic',
body: 'Powered by AppFeel',
custom: {
sender: 'AppFeel',
},
priority: 'high',
collapseKey: '',
contentAvailable: true,
delayWhileIdle: true,
restrictedPackageName: '',
dryRun: false,
directBootOk: false,
icon: '',
image: '',
style: '',
picture: '',
tag: '',
color: '',
clickAction: '',
locKey: '',
titleLocKey: '',
locArgs: undefined,
titleLocArgs: undefined,
retries: 1,
encoding: '',
badge: 2,
sound: 'ping.aiff',
android_channel_id: '',
notificationCount: 0,
ticker: '',
sticky: false,
visibility: 'public',
localOnly: false,
eventTimestamp: undefined,
notificationPriority: 'default',
vibrateTimingsMillis: undefined,
defaultVibrateTimings: false,
defaultSound: false,
lightSettings: undefined,
defaultLightSettings: false,
analyticsLabel: '',
alert: {
title: 'title',
body: 'body'
},
silent: false,
launchImage: '',
action: '',
category: '',
urlArgs: '',
truncateAtWordEnd: true,
mutableContent: 0,
threadId: '',
pushType: undefined,
expiry: Math.floor(Date.now() / 1000) + 28 * 86400,
timeToLive: 28 * 86400,
headers: [],
launch: '',
duration: '',
consolidationKey: 'my notification',
};
push.send(registrationIds, data, (err, result) => {
if (err) {
console.log(err);
} else {
console.log(result);
}
});
push.send(registrationIds, data)
.then((results) => { ... })
.catch((err) => { ... });
err will be null if all went fine, otherwise will return the error from the respective provider module.
result will contain an array with the following objects (one object for each device type found in device registration id's):
[
{
method: 'fcm',
multicastId: [],
success: 0,
failure: 0,
message: [{
messageId: '',
regId: value,
originalRegId: value,
error: new Error('unknown'),
errorMsg: 'some error',
}],
},
{
method: 'apn',
...
},
{
method: 'wns',
...
},
{
method: 'adm',
...
},
{
method: 'webPush',
...
},
]
FCM
All Android push notifications are sent through Firebase Cloud Messaging (FCM) using the firebase-admin library.
The following parameters are used to create an FCM Android message (following the Firebase Admin SDK AndroidConfig interface):
AndroidConfig properties:
collapseKey - Collapse key for message grouping
priority - Message priority: 'high' (default) or 'normal'
ttl - Time to live in milliseconds (converted from seconds)
restrictedPackageName - Package name restriction
directBootOk - Allow delivery in direct boot mode
data - Custom data fields (key-value pairs)
notification - Android notification properties (see below)
fcmOptions - FCM options including analyticsLabel
AndroidNotification properties:
title - Notification title
body - Notification body
icon - Notification icon resource
color - Notification color (#rrggbb format)
sound - Notification sound file
tag - Notification tag for replacing existing notifications
imageUrl - Image URL to display in notification
clickAction - Action to launch when notification is clicked
bodyLocKey / bodyLocArgs - Localized body text
titleLocKey / titleLocArgs - Localized title text
channelId - Android notification channel ID
notificationCount - Number of unread notifications
ticker - Ticker text for accessibility
sticky - Notification persists when clicked
visibility - Visibility level: 'public', 'private', or 'secret'
priority - Notification priority: 'min', 'low', 'default', 'high', or 'max'
eventTimestamp - Date object for event time
localOnly - Local-only notification (for Wear OS)
vibrateTimingsMillis - Vibration pattern (array of milliseconds)
defaultVibrateTimings - Use system default vibration
defaultSound - Use system default sound
lightSettings - LED light configuration object
defaultLightSettings - Use system default LED settings
proxy - Proxy setting: 'allow', 'deny', or 'if_priority_lowered'
Example usage:
const data = {
title: 'Title',
body: 'Body text',
icon: 'ic_notification',
color: '#FF0000',
sound: 'notification_sound',
clickAction: 'OPEN_ACTIVITY',
android_channel_id: 'default_channel',
tag: 'my_notification',
badge: 1,
notificationPriority: 'high',
ticker: 'New notification',
sticky: false,
visibility: 'public',
analyticsLabel: 'my_analytics_label',
custom: {
key: 'value',
},
};
APN
The following parameters are used to create an APN message:
{
retryLimit: data.retries || -1,
expiry: data.expiry || ((data.timeToLive || 28 * 86400) + Math.floor(Date.now() / 1000)),
priority: data.priority === 'normal' ? 5 : 10,
encoding: data.encoding,
payload: data.custom || {},
badge: data.silent === true ? undefined : data.badge,
badge: data.sound === true ? undefined : data.sound,
alert: data.sound === true ? undefined : data.alert || {
title: data.title,
body: data.body,
'title-loc-key': data.titleLocKey,
'title-loc-args': data.titleLocArgs,
'loc-key': data.locKey,
'loc-args': data.locArgs,
'launch-image': data.launchImage,
action: data.action,
},
topic: data.topic,
category: data.category || data.clickAction,
contentAvailable: data.contentAvailable,
mdm: data.mdm,
urlArgs: data.urlArgs,
truncateAtWordEnd: data.truncateAtWordEnd,
collapseId: data.collapseKey,
mutableContent: data.mutableContent || 0,
threadId: data.threadId,
pushType: data.pushType,
rawPayload: data.rawPayload,
interruptionLevel: data.interruptionLevel
}
data is the parameter in push.send(registrationIds, data)
Silent push notifications
iOS supports silent push notifications which are not displayed to the user but only used to transmit data.
Silent push notifications must not include sound, badge or alert and have normal priority.
By setting the silent property to true the values for sound, badge and alert will be overridden to undefined.
Priority will be overridden to normal.
const silentPushData = {
topic: 'yourTopic',
contentAvailable: true,
silent: true,
custom: {
yourKey: 'yourValue',
...
}
}
FCM
All Android push notifications are sent through Firebase Cloud Messaging (FCM) using the firebase-admin library.
Firebase Admin SDK App Options:
The following Firebase Admin SDK AppOptions are supported and can be passed in settings.fcm:
appName - Firebase app name (required)
serviceAccountKey - Firebase service account file use downloaded 'service-account-file.json'
credential - Firebase credential (one of serviceAccountKey or credential is required)
projectId - Explicitly set the Google Cloud project ID (optional)
databaseURL - Realtime Database URL (optional)
storageBucket - Cloud Storage bucket name (optional)
serviceAccountId - Service account email (optional)
databaseAuthVariableOverride - Auth variable override for Realtime Database (optional)
httpAgent - HTTP Agent for proxy support (optional, see Proxy section)
httpsAgent - HTTPS Agent for proxy support (optional, see Proxy section)
const tokens = ['e..Gwso:APA91.......7r910HljzGUVS_f...kbyIFk2sK6......D2s6XZWn2E21x'];
const notifications = {
collapseKey: Math.random().toString().replace('0.', ''),
priority: 'high',
sound: 'default',
title: 'Title 1',
body: 'Body 2',
custom: {
friend_id: 54657,
list_id: 'N7jSif1INyZkA7r910HljzGUVS',
},
};
pushNotifications.send(tokens, notifications, (error, result) => {
if (error) {
console.log('[error]', error);
throw error;
} else {
console.log('[result]', result, result.at(0));
}
});
fcm_notification - object that will be passed to FCM message notification field
Fcm object that will be sent to provider (Fcm message format) :
{
"data": {
"friend_id": "54657",
"list_id": "N7jSif1INyZkA7r910HljzGUVS"
},
"android": {
"collapse_key": "5658586678087056",
"priority": "high",
"notification": {
"title": "Title 1",
"body": "Body 2",
"sound": "default"
},
"ttl": 2419200000
},
"apns": {
"headers": {
"apns-expiration": "1697456586",
"apns-collapse-id": "5658586678087056"
},
"payload": {
"aps": {
"sound": "default",
"alert": {
"title": "Title 1",
"body": "Body 2"
}
}
}
},
"tokens": ["e..Gwso:APA91.......7r910HljzGUVS_f...kbyIFk2sK6......D2s6XZWn2E21x"]
}
WNS
The following fields are used to create a WNS message:
const notificationMethod = settings.wns.notificationMethod;
const opts = Object.assign({}, settings.wns);
opts.headers = data.headers || opts.headers;
opts.launch = data.launch || opts.launch;
opts.duration = data.duration || opts.duration;
delete opts.notificationMethod;
delete data.headers;
delete data.launch;
delete data.duration;
wns[notificationMethod](regId, data, opts, (err, response) => { ... });
data is the parameter in push.send(registrationIds, data)
Note: Please keep in mind that if data.accessToken is supplied, each push notification will be sent after the previous one has been responded. This is because Microsoft may send a new accessToken in the response and it should be used in successive requests. This can slow down the whole process depending on the number of devices to send.
ADM
The following parameters are used to create an ADM message:
const data = Object.assign({}, _data);
const consolidationKey = data.consolidationKey;
const expiry = data.expiry;
const timeToLive = data.timeToLive;
delete data.consolidationKey;
delete data.expiry;
delete data.timeToLive;
const ADMmesssage = {
expiresAfter: expiry - Math.floor(Date.now() / 1000) || timeToLive || 28 * 86400,
consolidationKey,
data,
};
data is the parameter in push.send(registrationIds, data)
Web-Push
Data can be passed as a simple string payload. If you do not pass a string, the parameter value will be stringified beforehand.
Settings are directly forwarded to webPush.sendNotification.
const payload = typeof data === 'string' ? data : JSON.stringify(data);
webPush.sendNotification(regId, payload, settings.web);
A working server example implementation can be found at https://github.com/alex-friedl/webpush-example/blob/master/server/index.js
Proxy
The module supports proxy configuration at two different levels:
Network Proxy (SDK-level)
To route Firebase Admin SDK network requests through a corporate proxy, configure HTTP/HTTPS agents:
import { HttpProxyAgent } from 'http-proxy-agent';
import { HttpsProxyAgent } from 'https-proxy-agent';
const settings = {
fcm: {
appName: 'myApp',
credential: { ... },
httpAgent: new HttpProxyAgent(`http://${env.proxy.host}:${env.proxy.port}`),
httpsAgent: new HttpsProxyAgent(`http://${env.proxy.host}:${env.proxy.port}`),
},
};
This affects how the SDK communicates with Google's servers and applies to all Firebase services.
Notification Proxy Behavior (Android-level)
To control how Android devices handle notifications in proxy scenarios, use the proxy property in the notification data:
const data = {
title: 'Notification',
body: 'Test',
proxy: 'allow',
};
push.send(registrationIds, data);
This is a notification-level setting that tells the Android system whether to deliver the notification when the device is on a proxy network.
Platform-Specific Proxy
For APN (Apple Push Notification), configure the proxy at the app settings level:
const settings = {
apn: {
token: { ... },
proxy: {
host: <proxy_address>,
port: <proxy_port>
}
}
};
Resources
LICENSE
The MIT License (MIT)
Copyright (c) 2016 AppFeel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Made in Barcelona with <3 and Code