{"id":13447513,"url":"https://github.com/appfeel/node-pushnotifications","last_synced_at":"2026-04-18T09:07:14.574Z","repository":{"id":22247061,"uuid":"25580544","full_name":"appfeel/node-pushnotifications","owner":"appfeel","description":"Push notifications for GCM, APNS, MPNS, AMZ (automatic detection from device token)","archived":false,"fork":false,"pushed_at":"2026-03-29T12:39:28.000Z","size":4158,"stargazers_count":551,"open_issues_count":5,"forks_count":127,"subscribers_count":17,"default_branch":"master","last_synced_at":"2026-03-29T15:52:55.122Z","etag":null,"topics":["apn","apns","apns2","fcm","gcm","node","node-adm","node-apn","node-fcm","node-gcm","node-pushnotifications","push-notifications"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/appfeel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2014-10-22T12:36:59.000Z","updated_at":"2026-03-29T12:39:26.000Z","dependencies_parsed_at":"2023-12-07T22:02:53.703Z","dependency_job_id":"9b6a6e04-b057-46f9-a13c-a3b325423bce","html_url":"https://github.com/appfeel/node-pushnotifications","commit_stats":{"total_commits":328,"total_committers":35,"mean_commits":9.371428571428572,"dds":0.5152439024390244,"last_synced_commit":"b7d7328f8125efa04c0b88cf596dba5270d6386c"},"previous_names":[],"tags_count":80,"template":false,"template_full_name":null,"purl":"pkg:github/appfeel/node-pushnotifications","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appfeel%2Fnode-pushnotifications","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appfeel%2Fnode-pushnotifications/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appfeel%2Fnode-pushnotifications/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appfeel%2Fnode-pushnotifications/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/appfeel","download_url":"https://codeload.github.com/appfeel/node-pushnotifications/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appfeel%2Fnode-pushnotifications/sbom","scorecard":{"id":203497,"data":{"date":"2025-08-11","repo":{"name":"github.com/appfeel/node-pushnotifications","commit":"7d4e6d9c177ff8cea7a8cdc5ac216e516a3d703a"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.8,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":1,"reason":"Found 2/16 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":3,"reason":"dependency not pinned by hash detected -- score normalized to 3","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/appfeel/node-pushnotifications/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/appfeel/node-pushnotifications/ci.yml/master?enable=pin","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   1 out of   1 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 17 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"17 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-x4c5-c7rf-jjgv","Warn: Project is vulnerable to: GHSA-h5c3-5r3r-rr8q","Warn: Project is vulnerable to: GHSA-rmvr-2pp2-xj38","Warn: Project is vulnerable to: GHSA-xx4v-prfh-6cgc","Warn: Project is vulnerable to: GHSA-8hc4-vh64-cxmj","Warn: Project is vulnerable to: GHSA-jr5f-v2jv-69x6","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-76p7-773f-r4q5","Warn: Project is vulnerable to: GHSA-pq67-2wwv-3xjx","Warn: Project is vulnerable to: GHSA-8cj5-5rvv-wf4v","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-16T23:14:07.360Z","repository_id":22247061,"created_at":"2025-08-16T23:14:07.360Z","updated_at":"2025-08-16T23:14:07.360Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31290957,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["apn","apns","apns2","fcm","gcm","node","node-adm","node-apn","node-fcm","node-gcm","node-pushnotifications","push-notifications"],"created_at":"2024-07-31T05:01:19.759Z","updated_at":"2026-04-18T09:07:14.561Z","avatar_url":"https://github.com/appfeel.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# Node Push Notifications\n\nA node.js module for interfacing with Apple Push Notification, Google Cloud Messaging, Windows Push Notification, Web-Push Notification and Amazon Device Messaging services.\n\n[![License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://npmjs.org/package/node-pushnotifications)\n[![NPM version](http://img.shields.io/npm/v/node-pushnotifications.svg?style=flat)](https://npmjs.org/package/node-pushnotifications)\n[![Downloads](http://img.shields.io/npm/dm/node-pushnotifications.svg?style=flat)](https://npmjs.org/package/node-pushnotifications)\n[![node-pushnotifications CI](https://github.com/appfeel/node-pushnotifications/actions/workflows/ci.yml/badge.svg)](https://github.com/appfeel/node-pushnotifications/actions/workflows/ci.yml)\n[![Coverage Status](https://coveralls.io/repos/github/appfeel/node-pushnotifications/badge.svg?branch=master)](https://coveralls.io/github/appfeel/node-pushnotifications?branch=master)\n[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)\n\n- [Installation](#installation)\n- [Requirements](#requirements)\n- [Features](#features)\n- [Usage](#usage)\n- [FCM](#fcm)\n- [APN](#apn)\n- [WNS](#wns)\n- [ADM](#adm)\n- [Web-Push](#web-push)\n- [Resources](#resources)\n- [Proxy](#proxy)\n- [LICENSE](#license)\n\n## Installation\n\n```bash\nnpm install node-pushnotifications --save\n```\n\n## Requirements\n\nNode version \u003e= 18.x.x\n\n## Features\n\n- Powerful and intuitive.\n- Multi platform push notifications.\n- Automatically detects destination device type.\n- Unified error handling.\n- Written in ES6, compatible with ES5 through babel transpilation.\n\n## Usage\n\n### 1. Import and setup push module\n\nInclude 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.\n\n```js\nimport PushNotifications from 'node-pushnotifications';\n\nconst settings = {\n    fcm: {\n        appName: 'localFcmAppName',\n        serviceAccountKey: require('../firebase-project-service-account-key.json'), // firebase service-account-file.json,\n        credential: null, // 'firebase-admin' Credential interface\n        // Optional Firebase Admin SDK AppOptions\n        projectId: 'your-project-id', // Explicitly set the Google Cloud project ID\n        databaseURL: 'https://your-database.firebaseio.com', // Realtime Database URL (optional)\n        storageBucket: 'your-bucket.appspot.com', // Cloud Storage bucket (optional)\n        serviceAccountId: 'your-email@your-project.iam.gserviceaccount.com', // Service account email (optional)\n        httpAgent: undefined, // HTTP Agent for proxy support (optional)\n        httpsAgent: undefined, // HTTPS Agent for proxy support (optional)\n    },\n    apn: {\n        token: {\n            key: './certs/key.p8', // optionally: fs.readFileSync('./certs/key.p8')\n            keyId: 'ABCD',\n            teamId: 'EFGH',\n        },\n        production: false // true for APN production environment, false for APN sandbox environment,\n        ...\n    },\n    adm: {\n        client_id: null,\n        client_secret: null,\n        ...\n    },\n    wns: {\n        client_id: null,\n        client_secret: null,\n        notificationMethod: 'sendTileSquareBlock',\n        ...\n    },\n    web: {\n        vapidDetails: {\n            subject: '\u003c \\'mailto\\' Address or URL \u003e',\n            publicKey: '\u003c URL Safe Base64 Encoded Public Key \u003e',\n            privateKey: '\u003c URL Safe Base64 Encoded Private Key \u003e',\n        },\n        TTL: 2419200,\n        contentEncoding: 'aes128gcm',\n        headers: {}\n    },\n    isAlwaysUseFCM: false, // true all messages will be sent through FCM API\n\n};\nconst push = new PushNotifications(settings);\n```\n\n- FCM options: see [firebase-admin](https://firebase.google.com/docs/admin/setup) (read [FCM](#fcm) section below!) - used for Android and fallback for other platforms\n- APN options: see [node-apn](https://github.com/node-apn/node-apn/blob/master/doc/provider.markdown)\n- ADM options: see [node-adm](https://github.com/umano/node-adm)\n- WNS options: see [wns](https://github.com/tjanczuk/wns)\n- Web-push options: see [web-push](https://github.com/web-push-libs/web-push)\n\n* `isAlwaysUseFCM`: when set to `true`, will send all notifications through FCM instead of platform-specific services\n\n_iOS:_ It is recommended to use [provider authentication tokens](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html). You need the .p8 certificate that you can obtain in your [account membership](https://cloud.githubusercontent.com/assets/8225312/20380437/599a767c-aca2-11e6-82bd-3cbfc2feee33.png). You should ask for an _Apple Push Notification Authentication Key (Sandbox \u0026 Production)_ or _Apple Push Notification service SSL (Sandbox \u0026 Production)_. However, you can also use certificates. See [node-apn](https://github.com/node-apn/node-apn/wiki/Preparing-Certificates) to see how to prepare cert.pem and key.pem.\n\n### 2. Define destination device ID\n\nRegistration 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).\n\nYou can send to multiple devices, independently of platform, creating an array with different destination device IDs.\n\n```js\n// Single destination\nconst registrationIds = 'INSERT_YOUR_DEVICE_ID';\n\n// Multiple destinations\nconst registrationIds = [];\nregistrationIds.push('INSERT_YOUR_DEVICE_ID');\nregistrationIds.push('INSERT_OTHER_DEVICE_ID');\n```\n\nThe `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.\n\nActually there are several different supported reg id's:\n\n#### Object regId\n\nIt can be of 2 types:\n\n- Mobile regId:\n\n```json\n{\n  \"id\": \"INSERT_YOUR_DEVICE_ID\",\n  \"type\": \"apn\"\n}\n```\n\nWhere type can be one of: 'apn', 'fcm', 'adm', 'wns', 'webPush'. The types are available as constants:\n\n```js\nimport { WEB, WNS, ADM, FCM, APN } from 'node-pushnotifications';\n\nconst regId = {\n  id: 'INSERT_YOUR_DEVICE_ID',\n  type: APN,\n};\n```\n\nIn case of webPush, `id` needs to be as defined below for `Web subscription`.\n\n- Web subscription see [web-push](https://www.npmjs.com/package/web-push)\n\n```json\n{\n  \"endpoint\": \"\u003c Push Subscription URL \u003e\",\n  \"keys\": {\n    \"p256dh\": \"\u003c User Public Encryption Key \u003e\",\n    \"auth\": \"\u003c User Auth Secret \u003e\"\n  }\n}\n```\n\n#### String regId (not recommended)\n\nIt is not recommended, as the [reg id is of variable length](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622958-application), which makes it difficult to identify if it is an APN regId or FCM regId.\n\n- `regId.substring(0, 4) === 'http'`: 'wns'\n- `/^(amzn[0-9]*.adm)/i.test(regId)`: 'adm'\n- `(regId.length === 64 || regId.length === 160) \u0026\u0026 /^[a-fA-F0-9]+$/.test(regId)`: 'apn'\n- `regId.length \u003e 64`: 'fcm'\n- otherwise: 'unknown' (the notification will not be sent)\n\n**Android:**\n\n- All Android notifications are sent through Firebase Cloud Messaging (FCM)\n- If you provide more than 1.000 registration tokens, they will automatically be split into 1.000 chunks\n- You are able to send to custom topics or conditions through FCM (see [firebase-admin docs](https://firebase.google.com/docs/cloud-messaging))\n\nExample:\n\n```javascript\nconst data = { ...data, recipients };\n```\n\n### 3. Send the notification\n\nCreate a JSON object with a title and message and send the notification.\n\n```js\nconst data = {\n    title: 'New push notification', // REQUIRED for Android\n    topic: 'topic', // REQUIRED for iOS (apn and fcm)\n    /* The topic of the notification. When using token-based authentication, specify the bundle ID of the app.\n     * When using certificate-based authentication, the topic is usually your app's bundle ID.\n     * More details can be found under https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns\n     */\n    body: 'Powered by AppFeel',\n    custom: {\n        sender: 'AppFeel',\n    },\n    priority: 'high', // fcm, apn. Supported values are 'high' or 'normal' (fcm). Will be translated to 10 and 5 for apn. Defaults to 'high'\n    collapseKey: '', // fcm for android, used as collapseId in apn\n    contentAvailable: true, // fcm, apn. node-apn will translate true to 1 as required by apn.\n    delayWhileIdle: true, // fcm for android\n    restrictedPackageName: '', // fcm for android\n    dryRun: false, // fcm for android\n    directBootOk: false, // fcm for android. Allows direct boot mode\n    icon: '', // fcm for android\n    image: '', // fcm for android\n    style: '', // fcm for android\n    picture: '', // fcm for android\n    tag: '', // fcm for android\n    color: '', // fcm for android\n    clickAction: '', // fcm for android. In ios, category will be used if not supplied\n    locKey: '', // fcm, apn\n    titleLocKey: '', // fcm, apn\n    locArgs: undefined, // fcm, apn. Expected format: Stringified Array\n    titleLocArgs: undefined, // fcm, apn. Expected format: Stringified Array\n    retries: 1, // fcm, apn\n    encoding: '', // apn\n    badge: 2, // fcm for ios, apn\n    sound: 'ping.aiff', // fcm, apn\n    android_channel_id: '', // fcm - Android Channel ID\n    notificationCount: 0, // fcm for android. badge can be used for both fcm and apn\n    ticker: '', // fcm for android. Ticker text for accessibility\n    sticky: false, // fcm for android. Notification persists when clicked\n    visibility: 'public', // fcm for android. Can be 'public', 'private', or 'secret'\n    localOnly: false, // fcm for android. Local-only notification (Wear OS)\n    eventTimestamp: undefined, // fcm for android. Date object for event time\n    notificationPriority: 'default', // fcm for android. Can be 'min', 'low', 'default', 'high', 'max'\n    vibrateTimingsMillis: undefined, // fcm for android. Array of vibration durations in milliseconds\n    defaultVibrateTimings: false, // fcm for android. Use system default vibration\n    defaultSound: false, // fcm for android. Use system default sound\n    lightSettings: undefined, // fcm for android. LED light settings object\n    defaultLightSettings: false, // fcm for android. Use system default LED settings\n    analyticsLabel: '', // fcm for android. Analytics label for FCM\n    alert: { // apn, will take precedence over title and body\n        title: 'title',\n        body: 'body'\n        // details: https://github.com/node-apn/node-apn/blob/master/doc/notification.markdown#convenience-setters\n    },\n    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\n    /*\n     * A string is also accepted as a payload for alert\n     * Your notification won't appear on ios if alert is empty object\n     * If alert is an empty string the regular 'title' and 'body' will show in Notification\n     */\n    // alert: '',\n    launchImage: '', // apn and fcm for ios\n    action: '', // apn and fcm for ios\n    category: '', // apn and fcm for ios\n    // mdm: '', // apn and fcm for ios. Use this to send Mobile Device Management commands.\n    // https://developer.apple.com/library/content/documentation/Miscellaneous/Reference/MobileDeviceManagementProtocolRef/3-MDM_Protocol/MDM_Protocol.html\n    urlArgs: '', // apn and fcm for ios\n    truncateAtWordEnd: true, // apn and fcm for ios\n    mutableContent: 0, // apn\n    threadId: '', // apn\n    pushType: undefined, // apn. valid values are 'alert' and 'background' (https://github.com/parse-community/node-apn/blob/master/doc/notification.markdown#notificationpushtype)\n    expiry: Math.floor(Date.now() / 1000) + 28 * 86400, // unit is seconds. if both expiry and timeToLive are given, expiry will take precedence\n    timeToLive: 28 * 86400,\n    headers: [], // wns\n    launch: '', // wns\n    duration: '', // wns\n    consolidationKey: 'my notification', // ADM\n};\n\n// You can use it in node callback style\npush.send(registrationIds, data, (err, result) =\u003e {\n    if (err) {\n        console.log(err);\n    } else {\n\t    console.log(result);\n    }\n});\n\n// Or you could use it as a promise:\npush.send(registrationIds, data)\n    .then((results) =\u003e { ... })\n    .catch((err) =\u003e { ... });\n```\n\n- `err` will be null if all went fine, otherwise will return the error from the respective provider module.\n- `result` will contain an array with the following objects (one object for each device type found in device registration id's):\n\n```js\n[\n    {\n        method: 'fcm', // The method used send notifications and which this info is related to\n        multicastId: [], // (only Android) Array with unique ID (number) identifying the multicast message, one identifier for each chunk of 1.000 notifications)\n        success: 0, // Number of notifications that have been successfully sent. It does not mean that the notification has been deliveried.\n        failure: 0, // Number of notifications that have been failed to be send.\n        message: [{\n            messageId: '', // (only for android) String specifying a unique ID for each successfully processed message or undefined if error\n            regId: 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.\n            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.\n            error: new Error('unknown'), // If any, there will be an Error object here for debugging purposes\n            errorMsg: 'some error', // If any, will include the error message from the respective provider module\n        }],\n    },\n    {\n        method: 'apn',\n        ... // Same structure here, except for message.orignalRegId\n    },\n    {\n        method: 'wns',\n        ... // Same structure here, except for message.orignalRegId\n    },\n    {\n        method: 'adm',\n        ... // Same structure here, except for message.orignalRegId\n    },\n    {\n        method: 'webPush',\n        ... // Same structure here, except for message.orignalRegId\n    },\n]\n```\n\n## FCM\n\nAll Android push notifications are sent through Firebase Cloud Messaging (FCM) using the [firebase-admin](https://github.com/firebase/firebase-admin-node) library.\n\nThe following parameters are used to create an FCM Android message (following the [Firebase Admin SDK AndroidConfig interface](https://firebase.google.com/docs/reference/admin/node/admin.messaging.AndroidConfig)):\n\n**AndroidConfig properties:**\n\n- `collapseKey` - Collapse key for message grouping\n- `priority` - Message priority: 'high' (default) or 'normal'\n- `ttl` - Time to live in milliseconds (converted from seconds)\n- `restrictedPackageName` - Package name restriction\n- `directBootOk` - Allow delivery in direct boot mode\n- `data` - Custom data fields (key-value pairs)\n- `notification` - Android notification properties (see below)\n- `fcmOptions` - FCM options including `analyticsLabel`\n\n**AndroidNotification properties:**\n\n- `title` - Notification title\n- `body` - Notification body\n- `icon` - Notification icon resource\n- `color` - Notification color (#rrggbb format)\n- `sound` - Notification sound file\n- `tag` - Notification tag for replacing existing notifications\n- `imageUrl` - Image URL to display in notification\n- `clickAction` - Action to launch when notification is clicked\n- `bodyLocKey` / `bodyLocArgs` - Localized body text\n- `titleLocKey` / `titleLocArgs` - Localized title text\n- `channelId` - Android notification channel ID\n- `notificationCount` - Number of unread notifications\n- `ticker` - Ticker text for accessibility\n- `sticky` - Notification persists when clicked\n- `visibility` - Visibility level: 'public', 'private', or 'secret'\n- `priority` - Notification priority: 'min', 'low', 'default', 'high', or 'max'\n- `eventTimestamp` - Date object for event time\n- `localOnly` - Local-only notification (for Wear OS)\n- `vibrateTimingsMillis` - Vibration pattern (array of milliseconds)\n- `defaultVibrateTimings` - Use system default vibration\n- `defaultSound` - Use system default sound\n- `lightSettings` - LED light configuration object\n- `defaultLightSettings` - Use system default LED settings\n- `proxy` - Proxy setting: 'allow', 'deny', or 'if_priority_lowered'\n\nExample usage:\n\n```js\nconst data = {\n  title: 'Title',\n  body: 'Body text',\n  icon: 'ic_notification',\n  color: '#FF0000',\n  sound: 'notification_sound',\n  clickAction: 'OPEN_ACTIVITY',\n  android_channel_id: 'default_channel',\n  tag: 'my_notification',\n  badge: 1,\n  notificationPriority: 'high',\n  ticker: 'New notification',\n  sticky: false,\n  visibility: 'public',\n  analyticsLabel: 'my_analytics_label',\n  custom: {\n    key: 'value',\n  },\n};\n```\n\n## APN\n\nThe following parameters are used to create an APN message:\n\n```js\n{\n    retryLimit: data.retries || -1,\n    expiry: data.expiry || ((data.timeToLive || 28 * 86400) + Math.floor(Date.now() / 1000)),\n    priority: data.priority === 'normal' ? 5 : 10,\n    encoding: data.encoding,\n    payload: data.custom || {},\n    badge: data.silent === true ? undefined : data.badge,\n    badge: data.sound === true ? undefined : data.sound,\n    alert: data.sound === true ? undefined : data.alert || {\n        title: data.title,\n        body: data.body,\n        'title-loc-key': data.titleLocKey,\n        'title-loc-args': data.titleLocArgs,\n        'loc-key': data.locKey,\n        'loc-args': data.locArgs,\n        'launch-image': data.launchImage,\n        action: data.action,\n    },\n    topic: data.topic, // Required\n    category: data.category || data.clickAction,\n    contentAvailable: data.contentAvailable,\n    mdm: data.mdm,\n    urlArgs: data.urlArgs,\n    truncateAtWordEnd: data.truncateAtWordEnd,\n    collapseId: data.collapseKey,\n    mutableContent: data.mutableContent || 0,\n    threadId: data.threadId,\n    pushType: data.pushType,\n    rawPayload: data.rawPayload,\n    interruptionLevel: data.interruptionLevel\n}\n```\n\n_data is the parameter in `push.send(registrationIds, data)`_\n\n- [See node-apn fields](https://github.com/node-apn/node-apn/blob/master/doc/notification.markdown)\n- **Please note** that `topic` is required ([see node-apn docs](https://github.com/node-apn/node-apn/blob/master/doc/notification.markdown#notificationtopic)). When using token-based authentication, specify the bundle ID of the app.\n  When using certificate-based authentication, the topic is usually your app's bundle ID.\n  More details can be found under https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns\n- `rawPayload` (hidden 'node-apn' lib notification param) [source code](https://github.com/node-apn/node-apn/blob/master/lib/notification/index.js#L99) this param will replace all payload\n\n### Silent push notifications\n\niOS supports silent push notifications which are not displayed to the user but only used to transmit data.\n\nSilent push notifications must not include sound, badge or alert and have normal priority.\n\nBy setting the `silent` property to `true` the values for `sound`, `badge` and `alert` will be overridden to `undefined`.\n\nPriority will be overridden to `normal`.\n\n```js\nconst silentPushData = {\n    topic: 'yourTopic',\n    contentAvailable: true,\n    silent: true,\n    custom: {\n        yourKey: 'yourValue',\n        ...\n    }\n}\n```\n\n## FCM\n\nAll Android push notifications are sent through Firebase Cloud Messaging (FCM) using the [firebase-admin](https://github.com/firebase/firebase-admin-node) library.\n\n**Firebase Admin SDK App Options:**\n\nThe following Firebase Admin SDK `AppOptions` are supported and can be passed in `settings.fcm`:\n\n- `appName` - [Firebase app name](https://firebase.google.com/docs/reference/admin/node/firebase-admin.app.app#appname) (required)\n- `serviceAccountKey` - [Firebase service account file](https://firebase.google.com/docs/admin/setup#initialize_the_sdk_in_non-google_environments) use downloaded 'service-account-file.json'\n- `credential` - [Firebase credential](https://firebase.google.com/docs/reference/admin/node/firebase-admin.app.credential) (one of `serviceAccountKey` or `credential` is required)\n- `projectId` - Explicitly set the Google Cloud project ID (optional)\n- `databaseURL` - Realtime Database URL (optional)\n- `storageBucket` - Cloud Storage bucket name (optional)\n- `serviceAccountId` - Service account email (optional)\n- `databaseAuthVariableOverride` - Auth variable override for Realtime Database (optional)\n- `httpAgent` - HTTP Agent for proxy support (optional, see [Proxy](#proxy) section)\n- `httpsAgent` - HTTPS Agent for proxy support (optional, see [Proxy](#proxy) section)\n\n```js\nconst tokens = ['e..Gwso:APA91.......7r910HljzGUVS_f...kbyIFk2sK6......D2s6XZWn2E21x'];\n\nconst notifications = {\n  collapseKey: Math.random().toString().replace('0.', ''),\n  priority: 'high',\n  sound: 'default',\n  title: 'Title 1',\n  body: 'Body 2',\n  // titleLocKey: 'GREETING',\n  // titleLocArgs: ['Smith', 'M'],\n  // fcm_notification: {\n  //   title: 'Title 1',\n  //   body: 'Body 2',\n  //   sound: 'default',\n  //   default_vibrate_timings: true,\n  // },\n  // alert: {\n  //   title: 'Title 2',\n  //   body: 'Body 2'\n  // },\n  custom: {\n    friend_id: 54657,\n    list_id: 'N7jSif1INyZkA7r910HljzGUVS',\n  },\n};\n\npushNotifications.send(tokens, notifications, (error, result) =\u003e {\n  if (error) {\n    console.log('[error]', error);\n    throw error;\n  } else {\n    console.log('[result]', result, result.at(0));\n  }\n});\n```\n\n`fcm_notification` - object that will be passed to FCM message notification field\n\nFcm object that will be sent to provider ([Fcm message format](https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages?authuser=0#Message)) :\n\n```json\n{\n  \"data\": {\n    \"friend_id\": \"54657\",\n    \"list_id\": \"N7jSif1INyZkA7r910HljzGUVS\"\n  },\n  \"android\": {\n    \"collapse_key\": \"5658586678087056\",\n    \"priority\": \"high\",\n    \"notification\": {\n      \"title\": \"Title 1\",\n      \"body\": \"Body 2\",\n      \"sound\": \"default\"\n    },\n    \"ttl\": 2419200000\n  },\n  \"apns\": {\n    \"headers\": {\n      \"apns-expiration\": \"1697456586\",\n      \"apns-collapse-id\": \"5658586678087056\"\n    },\n    \"payload\": {\n      \"aps\": {\n        \"sound\": \"default\",\n        \"alert\": {\n          \"title\": \"Title 1\",\n          \"body\": \"Body 2\"\n        }\n      }\n    }\n  },\n  \"tokens\": [\"e..Gwso:APA91.......7r910HljzGUVS_f...kbyIFk2sK6......D2s6XZWn2E21x\"]\n}\n```\n\n## WNS\n\nThe following fields are used to create a WNS message:\n\n```js\nconst notificationMethod = settings.wns.notificationMethod;\nconst opts = Object.assign({}, settings.wns);\nopts.headers = data.headers || opts.headers;\nopts.launch = data.launch || opts.launch;\nopts.duration = data.duration || opts.duration;\n\ndelete opts.notificationMethod;\ndelete data.headers;\ndelete data.launch;\ndelete data.duration;\n\nwns[notificationMethod](regId, data, opts, (err, response) =\u003e { ... });\n\n```\n\n_data is the parameter in `push.send(registrationIds, data)`_\n\n- [See wns fileds](https://github.com/tjanczuk/wns)\n\n**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.\n\n## ADM\n\nThe following parameters are used to create an ADM message:\n\n```js\nconst data = Object.assign({}, _data); // _data is the data passed as method parameter\nconst consolidationKey = data.consolidationKey;\nconst expiry = data.expiry;\nconst timeToLive = data.timeToLive;\n\ndelete data.consolidationKey;\ndelete data.expiry;\ndelete data.timeToLive;\n\nconst ADMmesssage = {\n  expiresAfter: expiry - Math.floor(Date.now() / 1000) || timeToLive || 28 * 86400,\n  consolidationKey,\n  data,\n};\n```\n\n_data is the parameter in `push.send(registrationIds, data)`_\n\n- [See node-adm fields](https://github.com/umano/node-adm#usage)\n\n## Web-Push\n\nData can be passed as a simple string payload. If you do not pass a string, the parameter value will be stringified beforehand.\nSettings are directly forwarded to `webPush.sendNotification`.\n\n```js\nconst payload = typeof data === 'string' ? data : JSON.stringify(data);\nwebPush.sendNotification(regId, payload, settings.web);\n```\n\nA working server example implementation can be found at [https://github.com/alex-friedl/webpush-example/blob/master/server/index.js](https://github.com/alex-friedl/webpush-example/blob/master/server/index.js)\n\n## Proxy\n\nThe module supports proxy configuration at two different levels:\n\n### Network Proxy (SDK-level)\n\nTo route Firebase Admin SDK network requests through a corporate proxy, configure HTTP/HTTPS agents:\n\n```javascript\nimport { HttpProxyAgent } from 'http-proxy-agent';\nimport { HttpsProxyAgent } from 'https-proxy-agent';\n\nconst settings = {\n  fcm: {\n    appName: 'myApp',\n    credential: { ... },\n    // Route all Firebase Admin SDK network traffic through proxy\n    httpAgent: new HttpProxyAgent(`http://${env.proxy.host}:${env.proxy.port}`),\n    httpsAgent: new HttpsProxyAgent(`http://${env.proxy.host}:${env.proxy.port}`),\n  },\n};\n```\n\nThis affects how the SDK communicates with Google's servers and applies to all Firebase services.\n\n### Notification Proxy Behavior (Android-level)\n\nTo control how Android devices handle notifications in proxy scenarios, use the `proxy` property in the notification data:\n\n```javascript\nconst data = {\n  title: 'Notification',\n  body: 'Test',\n  proxy: 'allow', // Can be 'allow', 'deny', or 'if_priority_lowered'\n};\n\npush.send(registrationIds, data);\n```\n\nThis is a notification-level setting that tells the Android system whether to deliver the notification when the device is on a proxy network.\n\n### Platform-Specific Proxy\n\nFor APN (Apple Push Notification), configure the proxy at the app settings level:\n\n```javascript\nconst settings = {\n  apn: {\n    token: { ... },\n    proxy: {\n      host: \u003cproxy_address\u003e,\n      port: \u003cproxy_port\u003e\n    }\n  }\n};\n```\n\n## Resources\n\n- [Crossplatform integration example using this library and a React Native app](https://github.com/alex-friedl/crossplatform-push-notifications-example)\n- [Web-Push client/server example](https://github.com/alex-friedl/webpush-example)\n- [Node Push Notify from alexlds](https://github.com/alexlds/node-push-notify)\n\n## LICENSE\n\n```\nThe MIT License (MIT)\n\nCopyright (c) 2016 AppFeel\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n```\n\n_\u003cp style=\"font-size: small;\" align=\"right\"\u003e\u003ca color=\"#232323;\" href=\"http://appfeel.com\"\u003eMade in Barcelona with \u003cspan color=\"#FCB\"\u003e\u003c3\u003c/span\u003e and \u003cspan color=\"#BBCCFF\"\u003eCode\u003c/span\u003e\u003c/a\u003e\u003c/p\u003e_\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fappfeel%2Fnode-pushnotifications","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fappfeel%2Fnode-pushnotifications","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fappfeel%2Fnode-pushnotifications/lists"}