{
  "data": {
    "similar": [
      {
        "grade": "BB",
        "json": "https://www.anchorterminal.com/tools/ably.json",
        "name": "Ably",
        "score": 75,
        "shared": [
          "notify.push"
        ],
        "slug": "ably"
      },
      {
        "grade": "BB",
        "json": "https://www.anchorterminal.com/tools/customer-io.json",
        "name": "Customer.io",
        "score": 74.5,
        "shared": [
          "notify.push"
        ],
        "slug": "customer-io"
      },
      {
        "grade": "BB",
        "json": "https://www.anchorterminal.com/tools/amazon-sns.json",
        "name": "Amazon SNS",
        "score": 72.8,
        "shared": [
          "notify.push"
        ],
        "slug": "amazon-sns"
      },
      {
        "grade": "BB",
        "json": "https://www.anchorterminal.com/tools/suprsend.json",
        "name": "SuprSend",
        "score": 72.6,
        "shared": [
          "notify.push"
        ],
        "slug": "suprsend"
      },
      {
        "grade": "BB",
        "json": "https://www.anchorterminal.com/tools/courier.json",
        "name": "Courier",
        "score": 70.5,
        "shared": [
          "notify.push"
        ],
        "slug": "courier"
      },
      {
        "grade": "B",
        "json": "https://www.anchorterminal.com/tools/firebase-cloud-messaging.json",
        "name": "Firebase Cloud Messaging",
        "score": 69.8,
        "shared": [
          "notify.push"
        ],
        "slug": "firebase-cloud-messaging"
      }
    ],
    "tool": {
      "slug": "expo-push-notifications",
      "name": "Expo Push Notifications",
      "vendor": "Expo",
      "vendorUrl": "https://expo.dev",
      "kind": "http-api",
      "category": "notifications",
      "summary": "Hosted push service from Expo that takes one HTTPS request and relays it to Apple's APNs and Google's FCM for apps built with Expo. It issues push tickets and receipts, and sending is free.",
      "url": "https://www.anchorterminal.com/tools/expo-push-notifications",
      "markdownUrl": "https://www.anchorterminal.com/tools/expo-push-notifications.md",
      "slimMarkdownUrl": "https://www.anchorterminal.com/tools/expo-push-notifications.min.md",
      "jsonUrl": "https://www.anchorterminal.com/api/v1/tools/expo-push-notifications.json",
      "repo": "https://github.com/expo/expo-server-sdk-node",
      "license": "Proprietary service under Expo's terms of service. The Node.js server SDK is MIT",
      "transports": [
        "http"
      ],
      "remoteUrl": "https://exp.host/--/api/v2/push/send",
      "packages": [
        {
          "registry": "npm",
          "name": "expo-server-sdk"
        }
      ],
      "auth": "mixed",
      "authNotes": "No credential by default. The docs say the API \"currently does not require any authentication\", and a send needs only an Expo push token. An owner can turn on enhanced push security in the EAS dashboard, after which every call needs `Authorization: Bearer \u003caccess token\u003e` or fails with `UNAUTHORIZED`. Tokens are personal access tokens, which act on everything the person can reach, or robot user tokens limited by role. Both are created and revoked by a person in the dashboard.",
      "pricing": "free",
      "pricingNotes": "Free. The push FAQ says there is no cost for sending through the service, and the pricing page lists no push charge. A send needs an Expo project with APNs and FCM credentials, which a person sets up on an Expo account. The Free plan is $0 a month, Starter $19 and Production $199, and those prices buy builds and updates, not push. Whether signup asks for a card was not stated.",
      "priceSummary": "Free",
      "where": "hosted",
      "x402": {
        "level": "no",
        "evidence": "No x402, MPP or L402 in the push docs, the pricing page or the Node SDK source (checked 2026-10-09).",
        "endpoints": []
      },
      "toolCount": null,
      "popularity": {
        "githubStars": 1037,
        "npmWeekly": 1348515,
        "pypiWeekly": null,
        "asOf": "2026-10-09"
      },
      "docsUrl": "https://docs.expo.dev/push-notifications/sending-notifications/",
      "llmsTxt": "https://docs.expo.dev/llms.txt",
      "capabilities": [
        "notify.push"
      ],
      "tags": [
        "hosted",
        "free",
        "push",
        "no-key",
        "llms-txt",
        "typescript",
        "closed-source",
        "status-page",
        "soc2"
      ],
      "lastRelease": "2026-08-24",
      "graded": true,
      "anchor": {
        "graded": true,
        "score": 58.8,
        "grade": "C",
        "agentReady": false,
        "rank": 571,
        "ranked": true,
        "rankOf": 950,
        "categoryRank": 9,
        "methodology": "0.4",
        "run": "2026-10-01",
        "scores": {
          "ergonomics": 63,
          "maintenance": 74,
          "payments": 40,
          "reliability": 65,
          "schema": 60,
          "security": 48,
          "transparency": 68
        },
        "pending": [
          "performance",
          "tasks"
        ],
        "breakdown": [
          {
            "key": "reliability",
            "name": "Reliability",
            "weight": 16,
            "effectiveWeight": 20,
            "score": 65,
            "points": 13,
            "reason": "Hosted reading. status.expo.dev is a Statuspage site with a Push Notifications Broker component (20). The incident feed reaches back only to 4 August 2026, so 11 July to 3 August went unread. It lists three push incidents, an iOS push partial outage on 4 August lasting 83 minutes, delayed iOS push for an hour on 5 September and an iOS queue backlog on 8 September lasting 4 hours 41 minutes, plus wider API and website incidents on 1 September and 5 October. Read as one major incident (10). Limits are published with numbers, 600 notifications a second per project, 100 messages a request and 1,000 receipt IDs a request (15). The docs tell callers to retry 429 and 5xx with exponential backoff and the Node SDK does so twice on 429. No Retry-After header is documented and there is no idempotency key, while Expo says a notification may be handed on more than once (10 of 15). The docs state the push service has no SLA (0). The API is generally available (10)."
          },
          {
            "key": "performance",
            "name": "Performance",
            "weight": 10,
            "effectiveWeight": 0,
            "pending": true,
            "points": 0,
            "reason": "Pending. Latency is measured per call by our probes, which haven't run yet, so this run doesn't score it. Its weight is shared across the assessed categories until the first probe window closes."
          },
          {
            "key": "schema",
            "name": "Schema \u0026 documentation",
            "weight": 13,
            "effectiveWeight": 16.25,
            "score": 60,
            "points": 9.75,
            "reason": "API reading. No OpenAPI file or other machine-readable description of the push API was found. The Node SDK publishes TypeScript types for messages, tickets and receipts (5 of 25). docs.expo.dev has an `llms.txt` page map and serves every page as Markdown (10). The message table gives each field's platform and its APNs or FCM equivalent, with notes on `ttl`, `priority` and `channelId`, and the page says when to call FCM and APNs directly instead (16 of 20). Fields are typed, with enums for `priority` and `interruptionLevel`, while `data` and the error `details` are free-form objects (10 of 15). curl requests, sample responses, four request error codes and five receipt error codes with fixes (13 of 15). The path carries `v2`, and the docs page shows a modification date of 25 September 2026. No changelog for the push API was found, only the Node SDK's (6 of 15)."
          },
          {
            "key": "ergonomics",
            "name": "Agent ergonomics",
            "weight": 13,
            "effectiveWeight": 16.25,
            "score": 63,
            "points": 10.24,
            "reason": "API reading. Responses are a ticket or receipt per message and nothing else, and one request carries up to 100 messages (22 of 25). Receipts are fetched by ID, up to 1,000 a request, and cleared after 24 hours. There is no call to list sent notifications and no filtering (8 of 20). Request and receipt errors have named codes with a stated fix, and per-message errors come back alongside successes (17 of 20). No idempotency key and no dry run. Retry guidance is written down and Expo says duplicates are possible (6 of 20). Only `to` is required and no credential is needed by default. Expo maintains one SDK, for Node.js, and the other twelve listed are community or Symfony libraries (10 of 15)."
          },
          {
            "key": "security",
            "name": "Security \u0026 auth",
            "weight": 14,
            "effectiveWeight": 17.5,
            "score": 48,
            "points": 8.4,
            "reason": "By default the API takes no credential, and the docs say a leaked push token lets another party send to that device. An owner can require a Bearer access token, either a personal token that acts on every account the person can reach or a robot user's token limited by role, and both can be revoked (12 of 30). Robot users take a role, but no send-only permission or confirmation step was found (6 of 20). Tickets and receipts return only status and error fields, no third-party content (10). Audit logs of administrative actions are for Enterprise subscribers, and there is no per-send log beyond receipts kept 24 hours (5 of 15). A security.txt with a disclosure address and no Expires field, bounties described as usually reserved for flaws as severe as remote code execution, and SOC 2 Type 2 for the Security criterion with the report on request (15 of 20)."
          },
          {
            "key": "payments",
            "name": "Payments \u0026 pricing",
            "weight": 10,
            "effectiveWeight": 12.5,
            "score": 40,
            "points": 5,
            "reason": "No x402, MPP or L402 (0). The push FAQ says sending costs nothing, and the pricing page is public (20). The service is free and the Free plan is $0 a month. Whether signup asks for a card was not stated (15 of 20). The send call needs no key, but a push token exists only after a person has set up an Expo account, a project and APNs and FCM credentials, and the terms bar accounts registered by agents (5 of 20)."
          },
          {
            "key": "tasks",
            "name": "Task success",
            "weight": 10,
            "effectiveWeight": 0,
            "pending": true,
            "points": 0,
            "reason": "Pending. Task success needs the category task suites run through each tool, which haven't run yet, so this run doesn't score it. Its weight is shared across the assessed categories until then. A data provider's data-quality score is published on its listing now and becomes half of this category when it's scored."
          },
          {
            "key": "maintenance",
            "name": "Maintenance \u0026 community",
            "weight": 7,
            "effectiveWeight": 8.75,
            "score": 74,
            "points": 6.48,
            "reason": "Read as a closed service with an official SDK. The Node SDK's latest tag is v7.2.0 on 24 August 2026, 46 days before the check (20 of 30). Three releases in the last 90 days, v7.0.0 on 30 July, v7.1.0 on 8 August and v7.2.0 on 24 August (20). The SDK repository shows 2 open issues and pull requests in total, with a dependency update merged on 29 September. We did not read the issue threads or test support (15 of 25). One current official SDK, for Node.js only (10 of 15). The repository runs a test workflow on every push and pull request with Renovate configured. We did not see the run results (9 of 10)."
          },
          {
            "key": "transparency",
            "name": "Transparency \u0026 trust",
            "weight": 7,
            "effectiveWeight": 8.75,
            "score": 68,
            "points": 5.95,
            "note": "editorial 60, provenance 76",
            "reason": "Closed service under Expo's terms of service, which cover every Expo service without naming push, with an MIT Node SDK (15 of 30). The FAQ says notification content is held only in memory and queues until handed to Apple or Google, the security page says push tokens are stored and the payload deleted after sending, and the privacy policy lists push tokens among data collected. These agree. No retention period for tokens and no public DPA were found (22 of 30). The docs mark `_contentAvailable` as deprecated with no removal date, and no deprecation policy was found (5 of 20). The sub-processor list, updated 15 September 2026, names each company with its country and lists Apple and Google for sending push, and the docs place the push service on Google Cloud in the United States (18 of 20)."
          }
        ],
        "assessment": {
          "date": "2026-10-09",
          "basis": "public evidence",
          "confidence": "medium",
          "notes": {
            "ergonomics": "API reading. Responses are a ticket or receipt per message and nothing else, and one request carries up to 100 messages (22 of 25). Receipts are fetched by ID, up to 1,000 a request, and cleared after 24 hours. There is no call to list sent notifications and no filtering (8 of 20). Request and receipt errors have named codes with a stated fix, and per-message errors come back alongside successes (17 of 20). No idempotency key and no dry run. Retry guidance is written down and Expo says duplicates are possible (6 of 20). Only `to` is required and no credential is needed by default. Expo maintains one SDK, for Node.js, and the other twelve listed are community or Symfony libraries (10 of 15).",
            "maintenance": "Read as a closed service with an official SDK. The Node SDK's latest tag is v7.2.0 on 24 August 2026, 46 days before the check (20 of 30). Three releases in the last 90 days, v7.0.0 on 30 July, v7.1.0 on 8 August and v7.2.0 on 24 August (20). The SDK repository shows 2 open issues and pull requests in total, with a dependency update merged on 29 September. We did not read the issue threads or test support (15 of 25). One current official SDK, for Node.js only (10 of 15). The repository runs a test workflow on every push and pull request with Renovate configured. We did not see the run results (9 of 10).",
            "payments": "No x402, MPP or L402 (0). The push FAQ says sending costs nothing, and the pricing page is public (20). The service is free and the Free plan is $0 a month. Whether signup asks for a card was not stated (15 of 20). The send call needs no key, but a push token exists only after a person has set up an Expo account, a project and APNs and FCM credentials, and the terms bar accounts registered by agents (5 of 20).",
            "reliability": "Hosted reading. status.expo.dev is a Statuspage site with a Push Notifications Broker component (20). The incident feed reaches back only to 4 August 2026, so 11 July to 3 August went unread. It lists three push incidents, an iOS push partial outage on 4 August lasting 83 minutes, delayed iOS push for an hour on 5 September and an iOS queue backlog on 8 September lasting 4 hours 41 minutes, plus wider API and website incidents on 1 September and 5 October. Read as one major incident (10). Limits are published with numbers, 600 notifications a second per project, 100 messages a request and 1,000 receipt IDs a request (15). The docs tell callers to retry 429 and 5xx with exponential backoff and the Node SDK does so twice on 429. No Retry-After header is documented and there is no idempotency key, while Expo says a notification may be handed on more than once (10 of 15). The docs state the push service has no SLA (0). The API is generally available (10).",
            "schema": "API reading. No OpenAPI file or other machine-readable description of the push API was found. The Node SDK publishes TypeScript types for messages, tickets and receipts (5 of 25). docs.expo.dev has an `llms.txt` page map and serves every page as Markdown (10). The message table gives each field's platform and its APNs or FCM equivalent, with notes on `ttl`, `priority` and `channelId`, and the page says when to call FCM and APNs directly instead (16 of 20). Fields are typed, with enums for `priority` and `interruptionLevel`, while `data` and the error `details` are free-form objects (10 of 15). curl requests, sample responses, four request error codes and five receipt error codes with fixes (13 of 15). The path carries `v2`, and the docs page shows a modification date of 25 September 2026. No changelog for the push API was found, only the Node SDK's (6 of 15).",
            "security": "By default the API takes no credential, and the docs say a leaked push token lets another party send to that device. An owner can require a Bearer access token, either a personal token that acts on every account the person can reach or a robot user's token limited by role, and both can be revoked (12 of 30). Robot users take a role, but no send-only permission or confirmation step was found (6 of 20). Tickets and receipts return only status and error fields, no third-party content (10). Audit logs of administrative actions are for Enterprise subscribers, and there is no per-send log beyond receipts kept 24 hours (5 of 15). A security.txt with a disclosure address and no Expires field, bounties described as usually reserved for flaws as severe as remote code execution, and SOC 2 Type 2 for the Security criterion with the report on request (15 of 20).",
            "transparency": "Closed service under Expo's terms of service, which cover every Expo service without naming push, with an MIT Node SDK (15 of 30). The FAQ says notification content is held only in memory and queues until handed to Apple or Google, the security page says push tokens are stored and the payload deleted after sending, and the privacy policy lists push tokens among data collected. These agree. No retention period for tokens and no public DPA were found (22 of 30). The docs mark `_contentAvailable` as deprecated with no removal date, and no deprecation policy was found (5 of 20). The sub-processor list, updated 15 September 2026, names each company with its country and lists Apple and Google for sending push, and the docs place the push service on Google Cloud in the United States (18 of 20)."
          },
          "sources": [
            {
              "what": "sending guide, read as Markdown",
              "url": "https://docs.expo.dev/push-notifications/sending-notifications.md",
              "seen": "2026-10-09"
            },
            {
              "what": "push FAQ, read as Markdown",
              "url": "https://docs.expo.dev/push-notifications/faq.md",
              "seen": "2026-10-09"
            },
            {
              "what": "programmatic access (access tokens and robot users)",
              "url": "https://docs.expo.dev/accounts/programmatic-access.md",
              "seen": "2026-10-09"
            },
            {
              "what": "docs page map",
              "url": "https://docs.expo.dev/llms.txt",
              "seen": "2026-10-09"
            },
            {
              "what": "status page components",
              "url": "https://status.expo.dev/",
              "seen": "2026-10-09"
            },
            {
              "what": "status incident feed",
              "url": "https://status.expo.dev/history.atom",
              "seen": "2026-10-09"
            },
            {
              "what": "pricing",
              "url": "https://expo.dev/pricing",
              "seen": "2026-10-09"
            },
            {
              "what": "terms of service",
              "url": "https://expo.dev/terms",
              "seen": "2026-10-09"
            },
            {
              "what": "privacy policy",
              "url": "https://expo.dev/privacy",
              "seen": "2026-10-09"
            },
            {
              "what": "security and compliance",
              "url": "https://expo.dev/security",
              "seen": "2026-10-09"
            },
            {
              "what": "sub-processor list",
              "url": "https://expo.dev/privacy/subprocessors",
              "seen": "2026-10-09"
            },
            {
              "what": "security.txt",
              "url": "https://expo.dev/.well-known/security.txt",
              "seen": "2026-10-09"
            },
            {
              "what": "product changelog",
              "url": "https://expo.dev/changelog",
              "seen": "2026-10-09"
            },
            {
              "what": "Node SDK source, tags, changelog and workflows (shallow clone, not run)",
              "url": "https://github.com/expo/expo-server-sdk-node",
              "seen": "2026-10-09"
            },
            {
              "what": "npm weekly downloads",
              "url": "https://api.npmjs.org/downloads/point/last-week/expo-server-sdk",
              "seen": "2026-10-09"
            },
            {
              "what": "domain registration (RDAP)",
              "url": "https://pubapi.registry.google/rdap/domain/expo.dev",
              "seen": "2026-10-09"
            }
          ],
          "openQuestions": [
            "unchecked: the status record from 11 July to 3 August 2026, which the incident feed no longer lists",
            "unchecked: the Expo subscription agreement, which expo.dev/robots.txt disallows",
            "unchecked: the Drata trust centre and any DPA behind it",
            "Whether signup for the Free plan asks for a card",
            "Whether 429 responses carry a Retry-After header, which the docs do not say",
            "Whether the 1 September and 5 October 2026 platform incidents affected push sends",
            "The docs give 1,000 receipt IDs a request and the Node SDK chunks at 300. Which limit the server enforces was not tested",
            "Expo's terms bar accounts registered by bots, agents or other automated means, which matters before any probe is run"
          ]
        },
        "negative": 0,
        "verdict": "A free push relay with a small, well documented HTTP API, published limits of 600 notifications a second and written error codes. Sending needs no credential unless the owner turns on access tokens, there is no idempotency key or SLA, and the status page records three iOS push incidents since 4 August 2026.",
        "bestFor": "An agent that must push to an app already built with Expo, at no cost and with one call for both platforms.",
        "strengths": [
          "One POST to `https://exp.host/--/api/v2/push/send` reaches both APNs and FCM, with up to 100 messages a request",
          "Sending is free, per the push FAQ, and the Free plan costs $0 a month",
          "Limits are published. 600 notifications a second per project, 100 messages a request, 1,000 receipt IDs a request",
          "Docs are served as Markdown with an `llms.txt` index, and every message field is mapped to its APNs or FCM equivalent",
          "Expo states notification content is held only in memory and queues until handed to Apple or Google"
        ],
        "weaknesses": [
          "The send API needs no authentication by default, so anyone holding a push token can send to that device until the owner enables access tokens",
          "No idempotency key. Expo says a notification may reach Apple or Google more than once, or not at all",
          "No SLA for the push service, stated in the docs",
          "Three iOS push incidents on the status page since 4 August 2026, one a partial outage of 83 minutes and one a backlog of 4 hours 41 minutes",
          "No OpenAPI file or push API changelog was found, and only the Node.js SDK is maintained by Expo",
          "Expo's terms say accounts registered by bots, agents or other automated means are not permitted. This matters before any probe is run"
        ],
        "agentNotes": [
          "Send an array of up to 100 messages per request, all for one project, and stay under 600 notifications a second",
          "Keep each ticket `id` and POST them to `/--/api/v2/push/getReceipts` about 15 minutes later. Receipts are cleared after 24 hours",
          "Stop sending to a token when a ticket or receipt returns `DeviceNotRegistered`",
          "If the project has enhanced push security on, send `Authorization: Bearer \u003caccess token\u003e` or the call fails with `UNAUTHORIZED`",
          "Retry 429 and 5xx with exponential backoff, and expect an occasional duplicate because there is no idempotency key"
        ],
        "metrics": {
          "kind": "remote",
          "measured": false
        },
        "reviewCount": 0,
        "avgRating": 0,
        "history": [
          {
            "basis": "public evidence",
            "confidence": "medium",
            "grade": "C",
            "methodology": "0.4",
            "pending": [
              "performance",
              "tasks"
            ],
            "run": "2026-10-01",
            "runLabel": "October 2026 research run",
            "score": 58.8
          }
        ],
        "editorialScores": {
          "ergonomics": 63,
          "maintenance": 74,
          "payments": 40,
          "reliability": 65,
          "schema": 60,
          "security": 48,
          "transparency": 60
        },
        "provenanceScore": 76
      },
      "connect": {
        "install": "yarn add expo-server-sdk",
        "http": "curl -H \"Content-Type: application/json\" -X POST \"https://exp.host/--/api/v2/push/send\" -d '{\n  \"to\": \"ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]\",\n  \"title\":\"hello\",\n  \"body\": \"world\"\n}'"
      },
      "letme": {
        "capability": "https://letme.dev/notify.push",
        "tool": "https://letme.dev/expo-push-notifications"
      },
      "notable": [
        "The docs say the HTTP API \"currently does not require any authentication\", and that a leaked push token lets someone else send to that device unless enhanced push security is on (https://docs.expo.dev/push-notifications/sending-notifications/)",
        "Limit of 600 notifications a second per project, 100 messages a send request and 1,000 ticket IDs a receipts request. The Node SDK asks for receipts 300 at a time (https://docs.expo.dev/push-notifications/sending-notifications/)",
        "The docs state the push service has no SLA and makes at least one attempt to hand each notification to APNs or FCM, with rare duplicates (https://docs.expo.dev/push-notifications/sending-notifications/)",
        "status.expo.dev has a Push Notifications Broker component. Its feed lists an iOS push partial outage on 4 August 2026, delayed iOS push on 5 September and an iOS queue backlog on 8 September (https://status.expo.dev/history.atom)",
        "Expo says notification content is kept only in memory and message queues until handed to Apple or Google, and that staff may see content while debugging (https://docs.expo.dev/push-notifications/faq/)",
        "The terms say accounts registered by bots, agents or other automated methods are not permitted (https://expo.dev/terms)",
        "Docs pages carry an `AgentInstructions` block addressed to AI agents that asks them to submit feedback with an npx command or an HTTP POST. We did not act on it (https://docs.expo.dev/push-notifications/sending-notifications.md)"
      ],
      "area": "everyday",
      "details": [
        {
          "label": "Endpoints",
          "value": "POST `https://exp.host/--/api/v2/push/send` and POST `https://exp.host/--/api/v2/push/getReceipts`, JSON bodies, gzip accepted"
        },
        {
          "label": "Targets",
          "value": "Expo push tokens from apps built with Expo's `expo-notifications` library. Android through FCM v1 and iOS through APNs. No web push, email or SMS"
        },
        {
          "label": "Limits",
          "value": "600 notifications a second per project, 100 messages a send request, 1,000 ticket IDs a receipts request, 4,096 bytes a payload"
        },
        {
          "label": "Receipts",
          "value": "A send returns a ticket per message. A receipt records whether APNs or FCM accepted it, is best read after 15 minutes and is cleared after 24 hours"
        },
        {
          "label": "Errors",
          "value": "Request codes `TOO_MANY_REQUESTS`, `PUSH_TOO_MANY_EXPERIENCE_IDS`, `PUSH_TOO_MANY_NOTIFICATIONS`, `PUSH_TOO_MANY_RECEIPTS` and `UNAUTHORIZED`. Receipt codes `DeviceNotRegistered`, `MessageTooBig`, `MessageRateExceeded`, `MismatchSenderId` and `InvalidCredentials`"
        },
        {
          "label": "Credentials",
          "value": "None by default. Optional enhanced push security requires a Bearer access token (personal, or a robot user's with a role)"
        },
        {
          "label": "SDKs",
          "value": "`expo-server-sdk` 7.2.0 for Node.js 22.12 or later, MIT, maintained by Expo, with six concurrent connections, gzip and two retries on 429. Twelve other libraries listed in the docs are community or Symfony maintained"
        },
        {
          "label": "Delivery",
          "value": "Best effort, at least one attempt to hand off to APNs or FCM, no SLA. Duplicates are possible and there is no idempotency key"
        },
        {
          "label": "Hosting",
          "value": "Google Cloud Platform in the United States, per the docs"
        },
        {
          "label": "Certifications",
          "value": "SOC 2 Type 2 for the Security criterion, report on request for Production and Enterprise customers, per expo.dev/security"
        },
        {
          "label": "Status",
          "value": "status.expo.dev on Statuspage with a Push Notifications Broker component"
        }
      ],
      "provenance": {
        "legalEntity": "650 Industries, Inc.",
        "domain": "expo.dev",
        "domainRegistered": "2019-02-22",
        "endpointOnVendorDomain": false,
        "terms": "https://expo.dev/terms",
        "privacy": "https://expo.dev/privacy",
        "statusPage": "https://status.expo.dev",
        "changelog": "https://github.com/expo/expo-server-sdk-node/blob/main/CHANGELOG.md",
        "securityTxt": "valid",
        "checked": "2026-10-09",
        "notes": [
          "The terms (last updated 29 May 2025, effective 30 June 2025) are a contract with 650 Industries, Inc. and cover any product or service Expo makes available. They list EAS Build, Update, Submit, Hosting and Workflows by name and do not name the push service.",
          "The push API answers at exp.host, a second domain. Expo's docs and its Node SDK source name that host.",
          "expo.dev/.well-known/security.txt gives vulnerability-disclosures@expo.dev and a Canonical line and has no Expires field, which RFC 9116 requires.",
          "The privacy policy (last updated 21 October 2025) says Expo may collect end users' push tokens when the push service is used.",
          "expo.dev/robots.txt disallows `/expo-subscription-agreement`, so that agreement was not read.",
          "The registry's RDAP record for expo.dev gives a registration date of 2019-02-22. The changelog link is the Node SDK's, because no changelog for the push API itself was found."
        ],
        "score": 76,
        "checks": [
          {
            "check": "Legal entity named",
            "value": "650 Industries, Inc.",
            "points": 20,
            "max": 20,
            "state": "ok"
          },
          {
            "check": "Domain age",
            "value": "expo.dev, registered 2019-02-22 (7 years)",
            "points": 11,
            "max": 15,
            "state": "part"
          },
          {
            "check": "Endpoint on the vendor's domain",
            "value": "exp.host is not on expo.dev",
            "points": 0,
            "max": 15,
            "state": "no"
          },
          {
            "check": "Terms of service",
            "value": "read, states 7 of the 7 things a reader expects, and has 2 clauses that cost points",
            "points": 6,
            "max": 10,
            "state": "part"
          },
          {
            "check": "Privacy policy",
            "value": "read, states 6 of the 8 things a reader expects",
            "points": 8.5,
            "max": 10,
            "state": "part"
          },
          {
            "check": "Status page",
            "value": "status.expo.dev",
            "points": 10,
            "max": 10,
            "state": "ok"
          },
          {
            "check": "Changelog",
            "value": "published",
            "points": 10,
            "max": 10,
            "state": "ok"
          },
          {
            "check": "security.txt",
            "value": "valid",
            "points": 10,
            "max": 10,
            "state": "ok"
          }
        ],
        "policies": [
          {
            "kind": "terms",
            "url": "https://expo.dev/terms",
            "state": "read",
            "readAt": "2026-10-09",
            "statedDate": "2025-05-29",
            "words": 7916,
            "points": 6,
            "max": 10,
            "expected": [
              {
                "key": "terms.date",
                "label": "Gives the date it was last updated",
                "found": true,
                "quote": "Last updated May 29, 2025, and effective June 30, 2025.",
                "says": "Last updated 2025-05-29"
              },
              {
                "key": "terms.law",
                "label": "Names the governing law or courts",
                "found": true,
                "quote": "These Terms shall be governed by, and construed and interpreted in accordance with, the laws of the State of California (without giving effect to conflict of law principles).",
                "says": "The law of the State of California"
              },
              {
                "key": "terms.liability",
                "label": "States a limit on its liability",
                "found": true,
                "quote": "To the fullest extent permitted by law, in no event shall the Expo Parties’ total liability to you for all damages, losses and causes of action, whether in contract, tort (including negligence) or otherwise exceed the greater of the actual amount you paid for the services (if any) and $100, except to the extent an app…",
                "says": "Capped at $100,"
              },
              {
                "key": "terms.termination",
                "label": "Says how the agreement or account can be ended",
                "found": true,
                "quote": "If you knowingly give false, misleading, or inaccurate information regarding the existence of infringing content, we may suspend your account, and you may face other legal consequences."
              },
              {
                "key": "terms.changes",
                "label": "Says how changes to the terms are announced",
                "found": true,
                "quote": "…mail to the attention of the Legal Department at 624 University Ave, FL1, Palo Alto CA 94301 and by email to legal@expo.dev within 30 days of the date such change became effective, as indicated by the later of (a) the “Last Updated” date of the Terms you seek to reject or (b) the date of our email to you notifying you…",
                "says": "Gives 30 days of notice before a change"
              },
              {
                "key": "terms.use",
                "label": "Lists what users may not do",
                "found": true,
                "quote": "If you do not have authority to or do not agree to all of these Terms, or if you object to the Privacy Policy, you must not access or use the Services."
              },
              {
                "key": "terms.sla",
                "label": "Refers to a service level or uptime commitment",
                "found": true,
                "quote": "You acknowledge and agree that all use of any Beta Feature is at your sole risk, and that warranties, indemnities and SLA terms do not apply."
              }
            ],
            "toKnow": [
              {
                "key": "terms.automated",
                "label": "Restricts automated access",
                "found": true,
                "quote": "Accounts registered by “bots,” “agents,” or other automated methods or means are not permitted.",
                "costsPoints": true
              },
              {
                "key": "terms.nonotice",
                "label": "Says the terms or the service can change without notice",
                "found": true,
                "quote": "Expo reserves the right to permanently or temporarily modify or remove the Services or any portion thereof (including without limitation by changing the user interface of or removing certain features from the Services) from time to time, in Expo’s sole discretion, without notice to you.",
                "costsPoints": true
              },
              {
                "key": "terms.cutoff",
                "label": "Says access can be ended without notice or for any reason",
                "found": true,
                "quote": "Expo may immediately terminate these Terms with you and suspend or terminate your access to the Services for any or no reason at any time without notice, including, without limitation, if you fail to comply with any provision of these Terms, our Acceptable Use Policy, or our Community Guidelines."
              },
              {
                "key": "terms.arbitration",
                "label": "Requires arbitration or waives class actions",
                "found": true,
                "quote": "BY AGREEING TO BINDING ARBITRATION, YOU WAIVE YOUR RIGHT TO LITIGATE DISPUTES THROUGH A COURT AND TO HAVE A JUDGE OR JURY DECIDE YOUR CASE."
              }
            ],
            "notes": [
              {
                "date": "2026-10-08",
                "text": "Total liability is capped at the greater of the amount paid for the services and 100 US dollars.",
                "quote": "in no event shall the Expo Parties’ total liability to you for all damages, losses and causes of action, whether in contract, tort (including negligence) or otherwise exceed the greater of the actual amount you paid for the services (if any) and $100"
              },
              {
                "date": "2026-10-08",
                "text": "A login may be used by one person only, and it may not be shared with any other person or entity.",
                "quote": "You may not share or otherwise permit any other person or entity to access the Services using your username and password."
              },
              {
                "date": "2026-10-08",
                "text": "The customer authorises Expo to use its name or logo in marketing and promotional materials.",
                "quote": "You authorize Expo to use your name or logo to refer to you as a customer of the Services in connection with Expo’s marketing and promotional materials."
              }
            ]
          },
          {
            "kind": "privacy",
            "url": "https://expo.dev/privacy",
            "state": "read",
            "readAt": "2026-10-09",
            "statedDate": "2025-10-21",
            "words": 3283,
            "points": 8.5,
            "max": 10,
            "expected": [
              {
                "key": "privacy.date",
                "label": "Gives the date it was last updated",
                "found": true,
                "quote": "Last updated October 21st 2025",
                "says": "Last updated 2025-10-21"
              },
              {
                "key": "privacy.collected",
                "label": "Says what personal data is collected",
                "found": true,
                "quote": "Expo is committed to protecting the privacy and security of the information we collect and to being transparent about the ways in which we collect and process your information."
              },
              {
                "key": "privacy.retention",
                "label": "Says how long data is kept",
                "found": false
              },
              {
                "key": "privacy.processors",
                "label": "Says who else receives the data",
                "found": true,
                "quote": "For example, if you access any social media or similar services through the Services to login or to share information about your experience on our Services with others, we may collect information from these third-party services."
              },
              {
                "key": "privacy.sale",
                "label": "Says whether personal data is sold or shared for advertising",
                "found": false
              },
              {
                "key": "privacy.rights",
                "label": "Says what rights people have over their data",
                "found": true,
                "quote": "Pursuant to the Data Privacy Framework, EU, UK, and Swiss individuals have the right to obtain our confirmation of whether we maintain personal information relating to you in the United States, and the right to access that data."
              },
              {
                "key": "privacy.contact",
                "label": "Gives a privacy contact",
                "found": true,
                "quote": "EU, UK, and Swiss individuals with Data Privacy Framework inquiries or complaints should first contact us via our contact form."
              },
              {
                "key": "privacy.transfers",
                "label": "Says where data is transferred or stored",
                "found": true,
                "quote": "…confidentiality, and, to the extent required by applicable law, the Company implements measures such as standard contractual clauses or other appropriate legal mechanisms to ensure that any transferred information remains protected and secure.",
                "says": "Relies on standard contractual clauses"
              }
            ],
            "notes": [
              {
                "date": "2026-10-08",
                "text": "Deleting an account removes all past and active work associated with it and cannot be reversed.",
                "quote": "Account deletions include any and all past and active work associated with the account, and are irreversible."
              }
            ]
          }
        ]
      },
      "pageJsonUrl": "https://www.anchorterminal.com/tools/expo-push-notifications.json",
      "live": {
        "slug": "expo-push-notifications",
        "probe": {
          "target": "https://exp.host/--/api/v2/push/send",
          "method": "get",
          "lastAt": "2026-10-10T01:37:51.355353289Z",
          "lastOk": true,
          "lastStatus": 405,
          "lastMs": 143,
          "authRequired": false,
          "uptime24h": 100,
          "uptime30d": 100,
          "p50ms24h": 128,
          "p95ms24h": 192,
          "samples24h": 102,
          "samples30d": 102,
          "days": [
            {
              "date": "2026-10-09",
              "probes": 85,
              "ok": 85
            },
            {
              "date": "2026-10-10",
              "probes": 17,
              "ok": 17
            }
          ]
        },
        "vendorStatus": {
          "page": "https://status.expo.dev",
          "indicator": "none",
          "summary": "All Systems Operational",
          "checkedAt": "2026-10-10T01:33:41.378077992Z"
        },
        "versions": [
          {
            "registry": "github",
            "name": "expo/expo-server-sdk-node",
            "version": "v7.2.0",
            "released": "2026-08-24",
            "seenAt": "2026-10-09T16:52:32.455380467Z"
          },
          {
            "registry": "npm",
            "name": "expo-server-sdk",
            "version": "7.2.0",
            "seenAt": "2026-10-09T16:52:31.59453516Z"
          }
        ],
        "githubStars": 1037,
        "npmWeekly": 1348515,
        "pages": [
          {
            "url": "https://raw.githubusercontent.com/expo/expo-server-sdk-node/main/CHANGELOG.md",
            "kind": "changelog",
            "status": 200,
            "checkedAt": "2026-10-09T18:45:09.224081599Z",
            "changedAt": "0001-01-01T00:00:00Z",
            "fingerprint": "851125e2dd50"
          },
          {
            "url": "https://expo.dev/privacy",
            "kind": "privacy",
            "status": 200,
            "checkedAt": "2026-10-09T18:39:14.02772659Z",
            "changedAt": "0001-01-01T00:00:00Z",
            "fingerprint": "42bd6fab5bc9"
          },
          {
            "url": "https://expo.dev/terms",
            "kind": "terms",
            "status": 200,
            "checkedAt": "2026-10-09T18:39:16.223165435Z",
            "changedAt": "0001-01-01T00:00:00Z",
            "fingerprint": "d061e1a55580"
          }
        ],
        "updatedAt": "2026-10-10T01:37:51.355353289Z"
      }
    },
    "verify": {
      "accepts": "a page on expo.dev or one of its subdomains, or the README of github.com/expo/expo-server-sdk-node",
      "badgeUrl": "https://www.anchorterminal.com/badges/expo-push-notifications.svg",
      "body": {
        "slug": "expo-push-notifications",
        "url": "the page with the badge or the link"
      },
      "docs": "https://www.anchorterminal.com/builders/#verify",
      "effect": "none, it never changes a grade, rank or review",
      "endpoint": "https://www.anchorterminal.com/api/v1/verify",
      "listingUrl": "https://www.anchorterminal.com/tools/expo-push-notifications",
      "mcpTool": "verify_listing",
      "recheck": "weekly; two failed checks in a row and it lapses, a later pass restores it",
      "snippets": {
        "html": "\u003ca href=\"https://www.anchorterminal.com/tools/expo-push-notifications\"\u003e\u003cimg src=\"https://www.anchorterminal.com/badges/expo-push-notifications.svg\" alt=\"Expo Push Notifications on Anchor Terminal\" height=\"20\"\u003e\u003c/a\u003e",
        "markdown": "[![Expo Push Notifications on Anchor Terminal](https://www.anchorterminal.com/badges/expo-push-notifications.svg)](https://www.anchorterminal.com/tools/expo-push-notifications)",
        "link": "\u003ca href=\"https://www.anchorterminal.com/tools/expo-push-notifications\"\u003eExpo Push Notifications on Anchor Terminal\u003c/a\u003e"
      }
    }
  },
  "kind": "anchor.page",
  "links": {
    "api": "https://www.anchorterminal.com/api/v1/index.json",
    "html": "https://www.anchorterminal.com/tools/expo-push-notifications",
    "json": "https://www.anchorterminal.com/tools/expo-push-notifications.json",
    "llms": "https://www.anchorterminal.com/llms.txt",
    "markdown": "https://www.anchorterminal.com/tools/expo-push-notifications.md",
    "slim": "https://www.anchorterminal.com/tools/expo-push-notifications.min.md"
  },
  "markdown": "## Overview\n\n**Grade C · 58.8/100 · rank #571 of 950 · #9 in Notifications · not agent-ready · confidence medium**\n\n\n## Assessment\n\nA free push relay with a small, well documented HTTP API, published limits of 600 notifications a second and written error codes. Sending needs no credential unless the owner turns on access tokens, there is no idempotency key or SLA, and the status page records three iOS push incidents since 4 August 2026.\n\n## Facts\n\n| Field | Value |\n| --- | --- |\n| Vendor | Expo (https://expo.dev) |\n| Kind | HTTP API |\n| Category | Notifications (https://www.anchorterminal.com/categories/notifications) |\n| Transport | HTTP |\n| Endpoint | `https://exp.host/--/api/v2/push/send` |\n| Auth | OAuth or key · No credential by default. The docs say the API \"currently does not require any authentication\", and a send needs only an Expo push token. An owner can turn on enhanced push security in the EAS dashboard, after which every call needs `Authorization: Bearer \u003caccess token\u003e` or fails with `UNAUTHORIZED`. Tokens are personal access tokens, which act on everything the person can reach, or robot user tokens limited by role. Both are created and revoked by a person in the dashboard. |\n| Pricing | Free (Free) · Free. The push FAQ says there is no cost for sending through the service, and the pricing page lists no push charge. A send needs an Expo project with APNs and FCM credentials, which a person sets up on an Expo account. The Free plan is $0 a month, Starter $19 and Production $199, and those prices buy builds and updates, not push. Whether signup asks for a card was not stated. |\n| x402 | No · No x402, MPP or L402 in the push docs, the pricing page or the Node SDK source (checked 2026-10-09). |\n| Licence | Proprietary service under Expo's terms of service. The Node.js server SDK is MIT |\n| Packages | npm: `expo-server-sdk` |\n| Source | https://github.com/expo/expo-server-sdk-node |\n| Docs | https://docs.expo.dev/push-notifications/sending-notifications/ |\n| llms.txt | https://docs.expo.dev/llms.txt |\n| Last release | 2026-08-24 |\n| GitHub stars | 1,037 (as of 2026-10-09) |\n| npm downloads / week | 1,348,515 |\n| Endpoints | POST `https://exp.host/--/api/v2/push/send` and POST `https://exp.host/--/api/v2/push/getReceipts`, JSON bodies, gzip accepted |\n| Targets | Expo push tokens from apps built with Expo's `expo-notifications` library. Android through FCM v1 and iOS through APNs. No web push, email or SMS |\n| Limits | 600 notifications a second per project, 100 messages a send request, 1,000 ticket IDs a receipts request, 4,096 bytes a payload |\n| Receipts | A send returns a ticket per message. A receipt records whether APNs or FCM accepted it, is best read after 15 minutes and is cleared after 24 hours |\n| Errors | Request codes `TOO_MANY_REQUESTS`, `PUSH_TOO_MANY_EXPERIENCE_IDS`, `PUSH_TOO_MANY_NOTIFICATIONS`, `PUSH_TOO_MANY_RECEIPTS` and `UNAUTHORIZED`. Receipt codes `DeviceNotRegistered`, `MessageTooBig`, `MessageRateExceeded`, `MismatchSenderId` and `InvalidCredentials` |\n| Credentials | None by default. Optional enhanced push security requires a Bearer access token (personal, or a robot user's with a role) |\n| SDKs | `expo-server-sdk` 7.2.0 for Node.js 22.12 or later, MIT, maintained by Expo, with six concurrent connections, gzip and two retries on 429. Twelve other libraries listed in the docs are community or Symfony maintained |\n| Delivery | Best effort, at least one attempt to hand off to APNs or FCM, no SLA. Duplicates are possible and there is no idempotency key |\n| Hosting | Google Cloud Platform in the United States, per the docs |\n| Certifications | SOC 2 Type 2 for the Security criterion, report on request for Production and Enterprise customers, per expo.dev/security |\n| Status | status.expo.dev on Statuspage with a Push Notifications Broker component |\n| Capabilities | notify.push |\n| Tags | hosted, free, push, no-key, llms-txt, typescript, closed-source, status-page, soc2 |\n| JSON | https://www.anchorterminal.com/api/v1/tools/expo-push-notifications.json |\n\n## Score breakdown (methodology v0.4, October 2026 research run)\n\nAssessed 2026-10-09 from public evidence against the published checklist (https://www.anchorterminal.com/benchmark/#checklist). Confidence: medium. Performance and Task success pending (no score, not in the total); the total is Σ(score × weight) ÷ 80 over the 7 assessed categories. \"This run\" is each category's share of the 100 points.\n\n| Category | Weight | This run | Score (0–100) | Points |\n| --- | --- | --- | --- | --- |\n| Reliability | 16% | 20 | 65 | 13.0 |\n| Performance | 10% | pending | pending | n/a |\n| Schema \u0026 documentation | 13% | 16.2 | 60 | 9.8 |\n| Agent ergonomics | 13% | 16.2 | 63 | 10.2 |\n| Security \u0026 auth | 14% | 17.5 | 48 | 8.4 |\n| Payments \u0026 pricing | 10% | 12.5 | 40 | 5.0 |\n| Task success | 10% | pending | pending | n/a |\n| Maintenance \u0026 community | 7% | 8.8 | 74 | 6.5 |\n| Transparency \u0026 trust (editorial 60, provenance 76) | 7% | 8.8 | 68 | 6.0 |\n| Negative events | up to −15 | up to −15 | none recorded | 0 |\n| **Total** | | | | **58.8 → C** |\n\n### Why each score\n\n- Reliability 65: Hosted reading. status.expo.dev is a Statuspage site with a Push Notifications Broker component (20). The incident feed reaches back only to 4 August 2026, so 11 July to 3 August went unread. It lists three push incidents, an iOS push partial outage on 4 August lasting 83 minutes, delayed iOS push for an hour on 5 September and an iOS queue backlog on 8 September lasting 4 hours 41 minutes, plus wider API and website incidents on 1 September and 5 October. Read as one major incident (10). Limits are published with numbers, 600 notifications a second per project, 100 messages a request and 1,000 receipt IDs a request (15). The docs tell callers to retry 429 and 5xx with exponential backoff and the Node SDK does so twice on 429. No Retry-After header is documented and there is no idempotency key, while Expo says a notification may be handed on more than once (10 of 15). The docs state the push service has no SLA (0). The API is generally available (10).\n- Performance: Pending. Latency is measured per call by our probes, which haven't run yet, so this run doesn't score it. Its weight is shared across the assessed categories until the first probe window closes.\n- Schema \u0026 documentation 60: API reading. No OpenAPI file or other machine-readable description of the push API was found. The Node SDK publishes TypeScript types for messages, tickets and receipts (5 of 25). docs.expo.dev has an `llms.txt` page map and serves every page as Markdown (10). The message table gives each field's platform and its APNs or FCM equivalent, with notes on `ttl`, `priority` and `channelId`, and the page says when to call FCM and APNs directly instead (16 of 20). Fields are typed, with enums for `priority` and `interruptionLevel`, while `data` and the error `details` are free-form objects (10 of 15). curl requests, sample responses, four request error codes and five receipt error codes with fixes (13 of 15). The path carries `v2`, and the docs page shows a modification date of 25 September 2026. No changelog for the push API was found, only the Node SDK's (6 of 15).\n- Agent ergonomics 63: API reading. Responses are a ticket or receipt per message and nothing else, and one request carries up to 100 messages (22 of 25). Receipts are fetched by ID, up to 1,000 a request, and cleared after 24 hours. There is no call to list sent notifications and no filtering (8 of 20). Request and receipt errors have named codes with a stated fix, and per-message errors come back alongside successes (17 of 20). No idempotency key and no dry run. Retry guidance is written down and Expo says duplicates are possible (6 of 20). Only `to` is required and no credential is needed by default. Expo maintains one SDK, for Node.js, and the other twelve listed are community or Symfony libraries (10 of 15).\n- Security \u0026 auth 48: By default the API takes no credential, and the docs say a leaked push token lets another party send to that device. An owner can require a Bearer access token, either a personal token that acts on every account the person can reach or a robot user's token limited by role, and both can be revoked (12 of 30). Robot users take a role, but no send-only permission or confirmation step was found (6 of 20). Tickets and receipts return only status and error fields, no third-party content (10). Audit logs of administrative actions are for Enterprise subscribers, and there is no per-send log beyond receipts kept 24 hours (5 of 15). A security.txt with a disclosure address and no Expires field, bounties described as usually reserved for flaws as severe as remote code execution, and SOC 2 Type 2 for the Security criterion with the report on request (15 of 20).\n- Payments \u0026 pricing 40: No x402, MPP or L402 (0). The push FAQ says sending costs nothing, and the pricing page is public (20). The service is free and the Free plan is $0 a month. Whether signup asks for a card was not stated (15 of 20). The send call needs no key, but a push token exists only after a person has set up an Expo account, a project and APNs and FCM credentials, and the terms bar accounts registered by agents (5 of 20).\n- Task success: Pending. Task success needs the category task suites run through each tool, which haven't run yet, so this run doesn't score it. Its weight is shared across the assessed categories until then. A data provider's data-quality score is published on its listing now and becomes half of this category when it's scored.\n- Maintenance \u0026 community 74: Read as a closed service with an official SDK. The Node SDK's latest tag is v7.2.0 on 24 August 2026, 46 days before the check (20 of 30). Three releases in the last 90 days, v7.0.0 on 30 July, v7.1.0 on 8 August and v7.2.0 on 24 August (20). The SDK repository shows 2 open issues and pull requests in total, with a dependency update merged on 29 September. We did not read the issue threads or test support (15 of 25). One current official SDK, for Node.js only (10 of 15). The repository runs a test workflow on every push and pull request with Renovate configured. We did not see the run results (9 of 10).\n- Transparency \u0026 trust 68: Closed service under Expo's terms of service, which cover every Expo service without naming push, with an MIT Node SDK (15 of 30). The FAQ says notification content is held only in memory and queues until handed to Apple or Google, the security page says push tokens are stored and the payload deleted after sending, and the privacy policy lists push tokens among data collected. These agree. No retention period for tokens and no public DPA were found (22 of 30). The docs mark `_contentAvailable` as deprecated with no removal date, and no deprecation policy was found (5 of 20). The sub-processor list, updated 15 September 2026, names each company with its country and lists Apple and Google for sending push, and the docs place the push service on Google Cloud in the United States (18 of 20).\n\nFix list for a coding agent, everything this grade says the listing lacks, the biggest gain first (19 items): https://www.anchorterminal.com/fixes/expo-push-notifications.md (JSON https://www.anchorterminal.com/fixes/expo-push-notifications.json)\n\n### What we couldn't check\n\n- unchecked: the status record from 11 July to 3 August 2026, which the incident feed no longer lists\n- unchecked: the Expo subscription agreement, which expo.dev/robots.txt disallows\n- unchecked: the Drata trust centre and any DPA behind it\n- Whether signup for the Free plan asks for a card\n- Whether 429 responses carry a Retry-After header, which the docs do not say\n- Whether the 1 September and 5 October 2026 platform incidents affected push sends\n- The docs give 1,000 receipt IDs a request and the Node SDK chunks at 300. Which limit the server enforces was not tested\n- Expo's terms bar accounts registered by bots, agents or other automated means, which matters before any probe is run\n\n### Sources\n\n- sending guide, read as Markdown: \u003chttps://docs.expo.dev/push-notifications/sending-notifications.md\u003e (seen 2026-10-09)\n- push FAQ, read as Markdown: \u003chttps://docs.expo.dev/push-notifications/faq.md\u003e (seen 2026-10-09)\n- programmatic access (access tokens and robot users): \u003chttps://docs.expo.dev/accounts/programmatic-access.md\u003e (seen 2026-10-09)\n- docs page map: \u003chttps://docs.expo.dev/llms.txt\u003e (seen 2026-10-09)\n- status page components: \u003chttps://status.expo.dev/\u003e (seen 2026-10-09)\n- status incident feed: \u003chttps://status.expo.dev/history.atom\u003e (seen 2026-10-09)\n- pricing: \u003chttps://expo.dev/pricing\u003e (seen 2026-10-09)\n- terms of service: \u003chttps://expo.dev/terms\u003e (seen 2026-10-09)\n- privacy policy: \u003chttps://expo.dev/privacy\u003e (seen 2026-10-09)\n- security and compliance: \u003chttps://expo.dev/security\u003e (seen 2026-10-09)\n- sub-processor list: \u003chttps://expo.dev/privacy/subprocessors\u003e (seen 2026-10-09)\n- security.txt: \u003chttps://expo.dev/.well-known/security.txt\u003e (seen 2026-10-09)\n- product changelog: \u003chttps://expo.dev/changelog\u003e (seen 2026-10-09)\n- Node SDK source, tags, changelog and workflows (shallow clone, not run): \u003chttps://github.com/expo/expo-server-sdk-node\u003e (seen 2026-10-09)\n- npm weekly downloads: \u003chttps://api.npmjs.org/downloads/point/last-week/expo-server-sdk\u003e (seen 2026-10-09)\n- domain registration (RDAP): \u003chttps://pubapi.registry.google/rdap/domain/expo.dev\u003e (seen 2026-10-09)\n\n## Who's behind it (provenance 76/100, checked 2026-10-09)\n\n| Check | Finding | Points |\n| --- | --- | --- |\n| Legal entity named | 650 Industries, Inc. | 20/20 |\n| Domain age | expo.dev, registered 2019-02-22 (7 years) | 11/15 |\n| Endpoint on the vendor's domain | exp.host is not on expo.dev | 0/15 |\n| Terms of service | read, states 7 of the 7 things a reader expects, and has 2 clauses that cost points | 6/10 |\n| Privacy policy | read, states 6 of the 8 things a reader expects | 8.5/10 |\n| Status page | status.expo.dev | 10/10 |\n| Changelog | published | 10/10 |\n| security.txt | valid | 10/10 |\n\nThe terms (last updated 29 May 2025, effective 30 June 2025) are a contract with 650 Industries, Inc. and cover any product or service Expo makes available. They list EAS Build, Update, Submit, Hosting and Workflows by name and do not name the push service.\n\nThe push API answers at exp.host, a second domain. Expo's docs and its Node SDK source name that host.\n\nexpo.dev/.well-known/security.txt gives vulnerability-disclosures@expo.dev and a Canonical line and has no Expires field, which RFC 9116 requires.\n\nThe privacy policy (last updated 21 October 2025) says Expo may collect end users' push tokens when the push service is used.\n\nexpo.dev/robots.txt disallows `/expo-subscription-agreement`, so that agreement was not read.\n\nThe registry's RDAP record for expo.dev gives a registration date of 2019-02-22. The changelog link is the Node SDK's, because no changelog for the push API itself was found.\n\n### Terms and privacy, as read\n\nA reading by a fixed set of rules, each answered with the vendor's own sentence. Not legal advice.\n\n**Terms of service** (https://expo.dev/terms), read 2026-10-09, dated 2025-05-29, states 7 of the 7 things a reader expects.\n\n- To know. Restricts automated access (costs points). \"Accounts registered by “bots,” “agents,” or other automated methods or means are not permitted.\"\n- To know. Says the terms or the service can change without notice (costs points). \"Expo reserves the right to permanently or temporarily modify or remove the Services or any portion thereof (including without limitation by changing the user interface of or removing certain features from the Services) from time to time, in Expo’s sole discretion, without notice to you.\"\n- To know. Says access can be ended without notice or for any reason. \"Expo may immediately terminate these Terms with you and suspend or terminate your access to the Services for any or no reason at any time without notice, including, without limitation, if you fail to comply with any provision of these Terms, our Acceptable Use Policy, or our Community Guidelines.\"\n- To know. Requires arbitration or waives class actions. \"BY AGREEING TO BINDING ARBITRATION, YOU WAIVE YOUR RIGHT TO LITIGATE DISPUTES THROUGH A COURT AND TO HAVE A JUDGE OR JURY DECIDE YOUR CASE.\"\n- Gives the date it was last updated. Last updated 2025-05-29.\n- Names the governing law or courts. The law of the State of California.\n- States a limit on its liability. Capped at $100,.\n- Says how changes to the terms are announced. Gives 30 days of notice before a change.\n- Also in the text (2026-10-08). Total liability is capped at the greater of the amount paid for the services and 100 US dollars. \"in no event shall the Expo Parties’ total liability to you for all damages, losses and causes of action, whether in contract, tort (including negligence) or otherwise exceed the greater of the actual amount you paid for the services (if any) and $100\"\n- Also in the text (2026-10-08). A login may be used by one person only, and it may not be shared with any other person or entity. \"You may not share or otherwise permit any other person or entity to access the Services using your username and password.\"\n- Also in the text (2026-10-08). The customer authorises Expo to use its name or logo in marketing and promotional materials. \"You authorize Expo to use your name or logo to refer to you as a customer of the Services in connection with Expo’s marketing and promotional materials.\"\n\n**Privacy policy** (https://expo.dev/privacy), read 2026-10-09, dated 2025-10-21, states 6 of the 8 things a reader expects.\n\n- Gives the date it was last updated. Last updated 2025-10-21.\n- Not found in the text. Says how long data is kept.\n- Not found in the text. Says whether personal data is sold or shared for advertising.\n- Says where data is transferred or stored. Relies on standard contractual clauses.\n- Also in the text (2026-10-08). Deleting an account removes all past and active work associated with it and cannot be reversed. \"Account deletions include any and all past and active work associated with the account, and are irreversible.\"\n\n## Live (updated 2026-10-10 01:37 UTC)\n\n- Right now: up, HTTP 405, 143 ms, checked 2026-10-10 01:37 UTC (get on `https://exp.host/--/api/v2/push/send`)\n- Uptime 24h 100.0% (102 probes) · 30 days 100.0% (102 probes) · p50 128 ms · p95 192 ms\n- Vendor status page: none, All Systems Operational\n- github `expo/expo-server-sdk-node` v7.2.0, released 2026-08-24\n- npm `expo-server-sdk` 7.2.0\n- Watching changelog \u003chttps://raw.githubusercontent.com/expo/expo-server-sdk-node/main/CHANGELOG.md\u003e\n- Watching privacy \u003chttps://expo.dev/privacy\u003e\n- Watching terms \u003chttps://expo.dev/terms\u003e\n- Always current: https://www.anchorterminal.com/api/v1/live/expo-push-notifications.json\n\n## Probe metrics\n\nNot measured yet. Our benchmark probes haven't run, so there's no availability, latency or error rate from a run and Performance is pending. Live uptime, where we poll the endpoint, is under Live and doesn't change the score.\n\n## Strengths\n\n- One POST to `https://exp.host/--/api/v2/push/send` reaches both APNs and FCM, with up to 100 messages a request\n- Sending is free, per the push FAQ, and the Free plan costs $0 a month\n- Limits are published. 600 notifications a second per project, 100 messages a request, 1,000 receipt IDs a request\n- Docs are served as Markdown with an `llms.txt` index, and every message field is mapped to its APNs or FCM equivalent\n- Expo states notification content is held only in memory and queues until handed to Apple or Google\n\n## Weaknesses\n\n- The send API needs no authentication by default, so anyone holding a push token can send to that device until the owner enables access tokens\n- No idempotency key. Expo says a notification may reach Apple or Google more than once, or not at all\n- No SLA for the push service, stated in the docs\n- Three iOS push incidents on the status page since 4 August 2026, one a partial outage of 83 minutes and one a backlog of 4 hours 41 minutes\n- No OpenAPI file or push API changelog was found, and only the Node.js SDK is maintained by Expo\n- Expo's terms say accounts registered by bots, agents or other automated means are not permitted. This matters before any probe is run\n\n## Before you call it (notes for agents)\n\n1. Send an array of up to 100 messages per request, all for one project, and stay under 600 notifications a second\n2. Keep each ticket `id` and POST them to `/--/api/v2/push/getReceipts` about 15 minutes later. Receipts are cleared after 24 hours\n3. Stop sending to a token when a ticket or receipt returns `DeviceNotRegistered`\n4. If the project has enhanced push security on, send `Authorization: Bearer \u003caccess token\u003e` or the call fails with `UNAUTHORIZED`\n5. Retry 429 and 5xx with exponential backoff, and expect an occasional duplicate because there is no idempotency key\n\n## Connect\n\nInstall:\n\n```bash\nyarn add expo-server-sdk\n```\n\nFirst request:\n\n```bash\ncurl -H \"Content-Type: application/json\" -X POST \"https://exp.host/--/api/v2/push/send\" -d '{\n  \"to\": \"ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]\",\n  \"title\":\"hello\",\n  \"body\": \"world\"\n}'\n```\n\nThrough letme (picks today, calling later): https://letme.dev/expo-push-notifications. letme answers with the pick and how to call it direct; calling through letme (one key, the vendor's own price) comes later. How it works: https://www.anchorterminal.com/letme/index.md\n\n## Similar tools\n\nRanked by shared capabilities, then score. Same-category tools with no shared capability key are listed last.\n\n| Tool | Grade | Score | Rank | Shared capabilities | x402 | Markdown |\n| --- | --- | --- | --- | --- | --- | --- |\n| Ably | BB | 75 | 59 | notify.push | no | https://www.anchorterminal.com/tools/ably.md |\n| Customer.io | BB | 74.5 | 69 | notify.push | no | https://www.anchorterminal.com/tools/customer-io.md |\n| Amazon SNS | BB | 72.8 | 99 | notify.push | no | https://www.anchorterminal.com/tools/amazon-sns.md |\n| SuprSend | BB | 72.6 | 102 | notify.push | no | https://www.anchorterminal.com/tools/suprsend.md |\n| Courier | BB | 70.5 | 151 | notify.push | no | https://www.anchorterminal.com/tools/courier.md |\n| Firebase Cloud Messaging | B | 69.8 | 170 | notify.push | no | https://www.anchorterminal.com/tools/firebase-cloud-messaging.md |\n\n## Panel reviews (0)\n\nReviewed by the Anchor panel (https://www.anchorterminal.com/reviewers/index.md): .\n\nDesk reviews, written from public documentation, pricing, terms, source and status history on 1 October 2026. No calls made. For a desk review, the outcome says whether the reviewer's questions could be answered from public material: success, partial or failure. How reviews work: https://www.anchorterminal.com/reviews/how-it-works.md\n\n## Notable\n\n- The docs say the HTTP API \"currently does not require any authentication\", and that a leaked push token lets someone else send to that device unless enhanced push security is on (source: \u003chttps://docs.expo.dev/push-notifications/sending-notifications/\u003e)\n- Limit of 600 notifications a second per project, 100 messages a send request and 1,000 ticket IDs a receipts request. The Node SDK asks for receipts 300 at a time (source: \u003chttps://docs.expo.dev/push-notifications/sending-notifications/\u003e)\n- The docs state the push service has no SLA and makes at least one attempt to hand each notification to APNs or FCM, with rare duplicates (source: \u003chttps://docs.expo.dev/push-notifications/sending-notifications/\u003e)\n- status.expo.dev has a Push Notifications Broker component. Its feed lists an iOS push partial outage on 4 August 2026, delayed iOS push on 5 September and an iOS queue backlog on 8 September (source: \u003chttps://status.expo.dev/history.atom\u003e)\n- Expo says notification content is kept only in memory and message queues until handed to Apple or Google, and that staff may see content while debugging (source: \u003chttps://docs.expo.dev/push-notifications/faq/\u003e)\n- The terms say accounts registered by bots, agents or other automated methods are not permitted (source: \u003chttps://expo.dev/terms\u003e)\n- Docs pages carry an `AgentInstructions` block addressed to AI agents that asks them to submit feedback with an npx command or an HTTP POST. We did not act on it (source: \u003chttps://docs.expo.dev/push-notifications/sending-notifications.md\u003e)\n\n- #9 of 12 in Best notification APIs for AI agents: https://www.anchorterminal.com/best/notifications/index.md\n- All 66 notifications comparisons: https://www.anchorterminal.com/compare/notifications/index.md\n\n## Compare\n\n- [Amazon SNS vs Expo Push Notifications](https://www.anchorterminal.com/compare/amazon-sns-vs-expo-push-notifications.md): BB 72.8 vs C 58.8\n- [Courier vs Expo Push Notifications](https://www.anchorterminal.com/compare/courier-vs-expo-push-notifications.md): BB 70.5 vs C 58.8\n- [Expo Push Notifications vs Firebase Cloud Messaging](https://www.anchorterminal.com/compare/expo-push-notifications-vs-firebase-cloud-messaging.md): C 58.8 vs B 69.8\n- [Expo Push Notifications vs Knock](https://www.anchorterminal.com/compare/expo-push-notifications-vs-knock.md): C 58.8 vs B 66.5\n- [Expo Push Notifications vs MagicBell](https://www.anchorterminal.com/compare/expo-push-notifications-vs-magicbell.md): C 58.8 vs C 58.8\n- [Expo Push Notifications vs Novu](https://www.anchorterminal.com/compare/expo-push-notifications-vs-novu.md): C 58.8 vs B 64.2\n- [Expo Push Notifications vs ntfy](https://www.anchorterminal.com/compare/expo-push-notifications-vs-ntfy.md): C 58.8 vs C 61.5\n- [Expo Push Notifications vs OneSignal](https://www.anchorterminal.com/compare/expo-push-notifications-vs-onesignal.md): C 58.8 vs B 69.3\n- [Expo Push Notifications vs Pingram](https://www.anchorterminal.com/compare/expo-push-notifications-vs-pingram.md): C 58.8 vs C 57.4\n- [Expo Push Notifications vs Pushover](https://www.anchorterminal.com/compare/expo-push-notifications-vs-pushover.md): C 58.8 vs D 53.1\n- [Expo Push Notifications vs SuprSend](https://www.anchorterminal.com/compare/expo-push-notifications-vs-suprsend.md): C 58.8 vs BB 72.6\n\n## Verify this listing\n\nFor the vendor. The badge or a plain link to this page verifies the listing, from a page on expo.dev or one of its subdomains, or the README of github.com/expo/expo-server-sdk-node. It shows the listing is the vendor's and that the vendor knows it's here, and it never changes a grade, rank or review. The vendor sends the page's address to `POST https://www.anchorterminal.com/api/v1/verify` as `{\"slug\": \"expo-push-notifications\", \"url\": \"…\"}`, or calls the `verify_listing` tool at https://www.anchorterminal.com/mcp. We fetch the page once, then again every week; two failed checks in a row and the verification lapses, and a later pass restores it. What we check: https://www.anchorterminal.com/builders/index.md#verify\n\nHTML badge:\n\n```html\n\u003ca href=\"https://www.anchorterminal.com/tools/expo-push-notifications\"\u003e\u003cimg src=\"https://www.anchorterminal.com/badges/expo-push-notifications.svg\" alt=\"Expo Push Notifications on Anchor Terminal\" height=\"20\"\u003e\u003c/a\u003e\n```\n\nMarkdown badge, for a README:\n\n```markdown\n[![Expo Push Notifications on Anchor Terminal](https://www.anchorterminal.com/badges/expo-push-notifications.svg)](https://www.anchorterminal.com/tools/expo-push-notifications)\n```\n\nPlain link:\n\n```html\n\u003ca href=\"https://www.anchorterminal.com/tools/expo-push-notifications\"\u003eExpo Push Notifications on Anchor Terminal\u003c/a\u003e\n```\n\n## Share this listing\n\nFor the vendor. Sharing assets for social media, two PNGs of 1200 × 630 that say Expo Push Notifications is listed on Anchor Terminal, with the vendor's logo and this page's address and no grade or score.\n\n- Dark: https://www.anchorterminal.com/assets/share/expo-push-notifications-dark.png\n- Light: https://www.anchorterminal.com/assets/share/expo-push-notifications-light.png\n",
  "meta": {
    "attribution": "Anchor Terminal (https://www.anchorterminal.com)",
    "docs": "https://www.anchorterminal.com/docs/",
    "generatedAt": "2026-10-10",
    "license": "CC-BY-4.0",
    "method": "https://www.anchorterminal.com/benchmark/",
    "methodology": "0.4",
    "openapi": "https://www.anchorterminal.com/openapi.json",
    "preview": false,
    "run": "2026-10-01",
    "runLabel": "October 2026 research run"
  },
  "page": {
    "breadcrumbs": [
      {
        "name": "Home",
        "url": "https://www.anchorterminal.com/"
      },
      {
        "name": "Terminal",
        "url": "https://www.anchorterminal.com/tools/"
      },
      {
        "name": "Notifications",
        "url": "https://www.anchorterminal.com/categories/notifications"
      },
      {
        "name": "Expo Push Notifications",
        "url": ""
      }
    ],
    "description": "Hosted push service from Expo that takes one HTTPS request and relays it to Apple's APNs and Google's FCM for apps built with Expo. It issues push tickets and receipts, and sending is free.",
    "facts": [
      "rank #571 of 950",
      "OAuth or key auth",
      "0 desk reviews"
    ],
    "h1": "Expo Push Notifications",
    "image": "https://www.anchorterminal.com/assets/og/tools-expo-push-notifications.png",
    "path": "/tools/expo-push-notifications",
    "published": "2026-10-01",
    "section": "tools",
    "title": "Expo Push Notifications review: pricing, alternatives, grade C",
    "toc": null,
    "updated": "2026-10-10",
    "url": "https://www.anchorterminal.com/tools/expo-push-notifications"
  },
  "tokens": {
    "markdown": 7150,
    "slim": 1480
  },
  "version": 1
}
