A node.js module for interfacing with Apple Push Notification, Google Cloud Messaging, Windows Push Notification, Web-Push Notification and Amazon Device Messaging services.
npm install node-pushnotifications --saveNode version >= 20.x.x
- Powerful and intuitive.
- Multi platform push notifications.
- Automatically detects destination device type.
- Unified error handling.
- Written in ES6, compatible with ES5 through babel transpilation.
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.
importPushNotificationsfrom'node-pushnotifications';constsettings={fcm: {appName: 'localFcmAppName',serviceAccountKey: require('../firebase-project-service-account-key.json'),// firebase service-account-file.json,credential: null,// 'firebase-admin' Credential interface// Optional Firebase Admin SDK AppOptionsprojectId: 'your-project-id',// Explicitly set the Google Cloud project IDdatabaseURL: 'https://your-database.firebaseio.com',// Realtime Database URL (optional)storageBucket: 'your-bucket.appspot.com',// Cloud Storage bucket (optional)serviceAccountId: 'your-email@your-project.iam.gserviceaccount.com',// Service account email (optional)httpAgent: undefined,// HTTP Agent for proxy support (optional)httpsAgent: undefined,// HTTPS Agent for proxy support (optional)},apn: {token: {key: './certs/key.p8',// optionally: fs.readFileSync('./certs/key.p8')keyId: 'ABCD',teamId: 'EFGH',},production: false// true for APN production environment, false for APN sandbox environment,...},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,// true all messages will be sent through FCM API};constpush=newPushNotifications(settings);- FCM options: see firebase-admin (read FCM section below!) - used for Android and fallback for other platforms
- APN options: see node-apn
- ADM options: see node-adm
- WNS options: see wns
- Web-push options: see web-push
isAlwaysUseFCM: when set totrue, 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.
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.
// Single destinationconstregistrationIds='INSERT_YOUR_DEVICE_ID';// Multiple destinationsconstregistrationIds=[];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:
It can be of 2 types:
- Mobile regId:
{
"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';constregId={id: 'INSERT_YOUR_DEVICE_ID',type: APN,};In case of webPush, id needs to be as defined below for Web subscription.
- Web subscription see web-push
{
"endpoint": "< Push Subscription URL >",
"keys": {
"p256dh": "< User Public Encryption Key >",
"auth": "< User Auth Secret >"
}
}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:
constdata={ ...data, recipients };Create a JSON object with a title and message and send the notification.
constdata={title: 'New push notification',// REQUIRED for Androidtopic: 'topic',// REQUIRED for iOS (apn and fcm)/* The topic of the notification. When using token-based authentication, specify the bundle ID of the app. * When using certificate-based authentication, the topic is usually your app's bundle ID. * More details can be found under https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns */body: 'Powered by AppFeel',custom: {sender: 'AppFeel',},priority: 'high',// fcm, apn. Supported values are 'high' or 'normal' (fcm). Will be translated to 10 and 5 for apn. Defaults to 'high'collapseKey: '',// fcm for android, used as collapseId in apncontentAvailable: true,// fcm, apn. node-apn will translate true to 1 as required by apn.delayWhileIdle: true,// fcm for androidrestrictedPackageName: '',// fcm for androiddryRun: false,// fcm for androiddirectBootOk: false,// fcm for android. Allows direct boot modeicon: '',// fcm for androidimage: '',// fcm for androidstyle: '',// fcm for androidpicture: '',// fcm for androidtag: '',// fcm for androidcolor: '',// fcm for androidclickAction: '',// fcm for android. In ios, category will be used if not suppliedlocKey: '',// fcm, apntitleLocKey: '',// fcm, apnlocArgs: undefined,// fcm, apn. Expected format: Stringified ArraytitleLocArgs: undefined,// fcm, apn. Expected format: Stringified Arrayretries: 1,// fcm, apnencoding: '',// apnbadge: 2,// fcm for ios, apnsound: 'ping.aiff',// fcm, apnandroid_channel_id: '',// fcm - Android Channel IDnotificationCount: 0,// fcm for android. badge can be used for both fcm and apnticker: '',// fcm for android. Ticker text for accessibilitysticky: false,// fcm for android. Notification persists when clickedvisibility: 'public',// fcm for android. Can be 'public', 'private', or 'secret'localOnly: false,// fcm for android. Local-only notification (Wear OS)eventTimestamp: undefined,// fcm for android. Date object for event timenotificationPriority: 'default',// fcm for android. Can be 'min', 'low', 'default', 'high', 'max'vibrateTimingsMillis: undefined,// fcm for android. Array of vibration durations in millisecondsdefaultVibrateTimings: false,// fcm for android. Use system default vibrationdefaultSound: false,// fcm for android. Use system default soundlightSettings: undefined,// fcm for android. LED light settings objectdefaultLightSettings: false,// fcm for android. Use system default LED settingsanalyticsLabel: '',// fcm for android. Analytics label for FCMalert: {// apn, will take precedence over title and bodytitle: 'title',body: 'body'// details: https://github.com/node-apn/node-apn/blob/master/doc/notification.markdown#convenience-setters},silent: false,// fcm, apn, will override badge, sound, alert and priority if set to true on iOS, will omit `notification` property and send as data-only on Android/FCM/* * A string is also accepted as a payload for alert * Your notification won't appear on ios if alert is empty object * If alert is an empty string the regular 'title' and 'body' will show in Notification */// alert: '',launchImage: '',// apn and fcm for iosaction: '',// apn and fcm for ioscategory: '',// apn and fcm for ios// mdm: '', // apn and fcm for ios. Use this to send Mobile Device Management commands.// https://developer.apple.com/library/content/documentation/Miscellaneous/Reference/MobileDeviceManagementProtocolRef/3-MDM_Protocol/MDM_Protocol.htmlurlArgs: '',// apn and fcm for iostruncateAtWordEnd: true,// apn and fcm for iosmutableContent: 0,// apnthreadId: '',// apnpushType: undefined,// apn. valid values are 'alert' and 'background' (https://github.com/parse-community/node-apn/blob/master/doc/notification.markdown#notificationpushtype)expiry: Math.floor(Date.now()/1000)+28*86400,// unit is seconds. if both expiry and timeToLive are given, expiry will take precedencetimeToLive: 28*86400,headers: [],// wnslaunch: '',// wnsduration: '',// wnsconsolidationKey: 'my notification',// ADM};// You can use it in node callback stylepush.send(registrationIds,data,(err,result)=>{if(err){console.log(err);}else{console.log(result);}});// Or you could use it as a promise:push.send(registrationIds,data).then((results)=>{ ... }).catch((err)=>{ ... });errwill be null if all went fine, otherwise will return the error from the respective provider module.resultwill contain an array with the following objects (one object for each device type found in device registration id's):
[{method: 'fcm',// The method used send notifications and which this info is related tomulticastId: [],// (only Android) Array with unique ID (number) identifying the multicast message, one identifier for each chunk of 1.000 notifications)success: 0,// Number of notifications that have been successfully sent. It does not mean that the notification has been deliveried.failure: 0,// Number of notifications that have been failed to be send.message: [{messageId: '',// (only for android) String specifying a unique ID for each successfully processed message or undefined if errorregId: value,// The current registrationId (device token id). Beware: For Android this may change if Google invalidates the previous device token. Use "originalRegId" if you are interested in when this changed occurs.originalRegId: value,// (only for android) The registrationId that was sent to the push.send() method. Compare this with field "regId" in order to know when the original registrationId (device token id) gets changed.error: newError('unknown'),// If any, there will be an Error object here for debugging purposeserrorMsg: 'some error',// If any, will include the error message from the respective provider module}],},{method: 'apn',
... // Same structure here, except for message.orignalRegId},{method: 'wns',
... // Same structure here, except for message.orignalRegId},{method: 'adm',
... // Same structure here, except for message.orignalRegId},{method: 'webPush',
... // Same structure here, except for message.orignalRegId},]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 groupingpriority- Message priority: 'high' (default) or 'normal'ttl- Time to live in milliseconds (converted from seconds)restrictedPackageName- Package name restrictiondirectBootOk- Allow delivery in direct boot modedata- Custom data fields (key-value pairs)notification- Android notification properties (see below)fcmOptions- FCM options includinganalyticsLabel
AndroidNotification properties:
title- Notification titlebody- Notification bodyicon- Notification icon resourcecolor- Notification color (#rrggbb format)sound- Notification sound filetag- Notification tag for replacing existing notificationsimageUrl- Image URL to display in notificationclickAction- Action to launch when notification is clickedbodyLocKey/bodyLocArgs- Localized body texttitleLocKey/titleLocArgs- Localized title textchannelId- Android notification channel IDnotificationCount- Number of unread notificationsticker- Ticker text for accessibilitysticky- Notification persists when clickedvisibility- Visibility level: 'public', 'private', or 'secret'priority- Notification priority: 'min', 'low', 'default', 'high', or 'max'eventTimestamp- Date object for event timelocalOnly- Local-only notification (for Wear OS)vibrateTimingsMillis- Vibration pattern (array of milliseconds)defaultVibrateTimings- Use system default vibrationdefaultSound- Use system default soundlightSettings- LED light configuration objectdefaultLightSettings- Use system default LED settingsproxy- Proxy setting: 'allow', 'deny', or 'if_priority_lowered'
Example usage:
constdata={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',},};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,// Requiredcategory: 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)
- See node-apn fields
- Please note that
topicis required (see node-apn docs). When using token-based authentication, specify the bundle ID of the app. When using certificate-based authentication, the topic is usually your app's bundle ID. More details can be found under https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns rawPayload(hidden 'node-apn' lib notification param) source code this param will replace all payload
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.
constsilentPushData={topic: 'yourTopic',contentAvailable: true,silent: true,custom: {yourKey: 'yourValue',
...
}}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 ofserviceAccountKeyorcredentialis 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)
consttokens=['e..Gwso:APA91.......7r910HljzGUVS_f...kbyIFk2sK6......D2s6XZWn2E21x'];constnotifications={collapseKey: Math.random().toString().replace('0.',''),priority: 'high',sound: 'default',title: 'Title 1',body: 'Body 2',// titleLocKey: 'GREETING',// titleLocArgs: ['Smith', 'M'],// fcm_notification: {// title: 'Title 1',// body: 'Body 2',// sound: 'default',// default_vibrate_timings: true,// },// alert: {// title: 'Title 2',// body: 'Body 2'// },custom: {friend_id: 54657,list_id: 'N7jSif1INyZkA7r910HljzGUVS',},};pushNotifications.send(tokens,notifications,(error,result)=>{if(error){console.log('[error]',error);throwerror;}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"]
}The following fields are used to create a WNS message:
constnotificationMethod=settings.wns.notificationMethod;constopts=Object.assign({},settings.wns);opts.headers=data.headers||opts.headers;opts.launch=data.launch||opts.launch;opts.duration=data.duration||opts.duration;deleteopts.notificationMethod;deletedata.headers;deletedata.launch;deletedata.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.
The following parameters are used to create an ADM message:
constdata=Object.assign({},_data);// _data is the data passed as method parameterconstconsolidationKey=data.consolidationKey;constexpiry=data.expiry;consttimeToLive=data.timeToLive;deletedata.consolidationKey;deletedata.expiry;deletedata.timeToLive;constADMmesssage={expiresAfter: expiry-Math.floor(Date.now()/1000)||timeToLive||28*86400,
consolidationKey,
data,};data is the parameter in push.send(registrationIds, data)
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.
constpayload=typeofdata==='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
The module supports proxy configuration at two different levels:
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';constsettings={fcm: {appName: 'myApp',credential: { ... },// Route all Firebase Admin SDK network traffic through proxyhttpAgent: newHttpProxyAgent(`http://${env.proxy.host}:${env.proxy.port}`),httpsAgent: newHttpsProxyAgent(`http://${env.proxy.host}:${env.proxy.port}`),},};This affects how the SDK communicates with Google's servers and applies to all Firebase services.
To control how Android devices handle notifications in proxy scenarios, use the proxy property in the notification data:
constdata={title: 'Notification',body: 'Test',proxy: 'allow',// Can be 'allow', 'deny', or 'if_priority_lowered'};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.
For APN (Apple Push Notification), configure the proxy at the app settings level:
constsettings={apn: {token: { ... },proxy: {host: <proxy_address>,
port: <proxy_port>}}};- Crossplatform integration example using this library and a React Native app
- Web-Push client/server example
- Node Push Notify from alexlds
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.