Documentation menu

SaaS Pro Max SDKs

Four packages under the @saaspro scope. Everything talks to one endpoint, POST https://saaspro.dev/api/v1/ingest, using the same event envelope.

Package Runs in Install
@saaspro/browser Browsers npm i @saaspro/browser
@saaspro/react React 18+ / Next.js npm i @saaspro/react
@saaspro/react-native React Native / Expo npm i @saaspro/react-native
@saaspro/node Node ≥ 20, Bun, Deno npm i @saaspro/node
@saaspro/shared Anywhere npm i @saaspro/shared

No build step at all? Use the script tag.

Which one do I need?

  • A website or web app@saaspro/browser, or @saaspro/react if you use React. Add @saaspro/node for server-side events and error reporting.
  • An API, worker or CLI@saaspro/node.
  • User management from the console → implement the connector with @saaspro/node.

Recipes

Keys

Create keys in the console under App → Settings → Keys. Both forms carry the environment they belong to.

Form Example Can do
Public spm_pub_prod_xxxxxxxx Send events, evaluate flags. Safe in a browser bundle.
Secret spm_sec_prod_xxxxxxxx Everything above, plus server-sent context.ip and context.userAgent. Server only.

A public key sending context.ip or context.userAgent has those fields dropped at ingest; the server reads the real request values instead.

The event envelope

Every SDK posts the same body:

{
  "key": "spm_pub_prod_xxxxxxxx",
  "sentAt": "2026-09-03T10:00:00.000Z",
  "sdk": { "name": "@saaspro/browser", "version": "0.1.0" },
  "events": [
    {
      "id": "4a1f…",
      "type": "track",
      "timestamp": "2026-09-03T09:59:59.120Z",
      "anonymousId": "6b2e…",
      "distinctId": "user_123",
      "sessionId": "9c4d…",
      "name": "signup completed",
      "properties": { "plan": "pro" },
      "value": 49,
      "currency": "EUR",
      "context": { "url": "https://example.com/pricing", "path": "/pricing" }
    }
  ]
}

The browser SDK puts the key in the body (which keeps every request a CORS simple request and matches what sendBeacon sends); the Node SDK sends Authorization: Bearer <key> instead.

Event types: page, track, identify, alias, error, metric, vital, session.

Limits: 1–100 events per envelope; event names ≤ 120 characters matching ^[\w $.:/-]+$; properties / traits / extra ≤ 16 KB serialized; ≤ 100 breadcrumbs; ≤ 32 KB of stack text; ≤ 20 metric label keys.

Names the SDKs produce themselves: $pageview, $pageleave, $click, $outbound, $form_submit, $web_vital, $session_end, $error, $identify, $alias.

Verifying an integration

  1. Open App → Analytics → Live in the console.
  2. Load a page in your app.
  3. A visitor appears within a couple of seconds.

If nothing arrives: check the key's environment, check the browser network tab for a 202 from /api/v1/ingest, and turn on debug: true to see every queued event in the console.