BugWatch — Browser & Mobile

Client-side ingest. Browser uses a short-lived x-bugwatch-session token (never the secret key). Mobile uses a client-signed x-bugwatch-token (HMAC on device).

POST/api/v1/bugwatch/ingest/browser

Browser ingest – error event

Ingest events from browser / SPA applications.

Authentication: x-bugwatch-session — a short-lived token minted by your backend via POST /api/v1/bugwatch/browser-session. Run "Mint browser session token" first; the test script saves it as {{sessionToken}} automatically.

The secret key never reaches the browser. The session token is ingest-only, scoped to one project+environment, and honours the project's allowedOrigins allow-list.

Request

  • Header: x-bugwatch-session: {{sessionToken}}
  • Content-Type: application/json or application/x-ndjson
  • Max body: 2 MB
  • CORS: allowed from any origin in the project's allowedOrigins (empty = allow all)

Success — 202 Accepted

{ "ingested": 1, "skipped": 0, "deduped": 0 }

Common errors

  • 401 — invalid or expired session token
  • 403 — origin not in allowedOrigins (origin_not_allowed)
  • 404 — project not found or inactive

Headers

x-bugwatch-session

Request body

application/json
{
  "level": 50,
  "time": {{nowMs}},
  "message": "Uncaught TypeError in browser",
  "release": "1.0.0",
  "environment": "production",
  "tags": { "browser": "Chrome", "page": "/checkout" },
  "user": { "id": "usr_browser_001", "ip": "203.0.113.42" },
  "exception": {
    "type": "TypeError",
    "value": "Cannot read properties of null (reading 'getAttribute')",
    "stacktrace": {
      "frames": [
        { "filename": "https://app.example.com/static/js/main.chunk.js", "function": "handleClick", "lineno": 112, "colno": 45 }
      ]
    }
  }
}

Responses

202 – Browser event ingested

{
  "ingested": 1,
  "skipped": 0,
  "deduped": 0
}
boltTry it
env
POSThttps://api.newinstance.cloud/api/v1/bugwatch/ingest/browser

Headers

x-bugwatch-session

Request body

Code samples

curl -X POST 'https://api.newinstance.cloud/api/v1/bugwatch/ingest/browser' \
  -H 'Content-Type: application/json' \
  --data-raw '{
  "level": 50,
  "time": {{nowMs}},
  "message": "Uncaught TypeError in browser",
  "release": "1.0.0",
  "environment": "production",
  "tags": { "browser": "Chrome", "page": "/checkout" },
  "user": { "id": "usr_browser_001", "ip": "203.0.113.42" },
  "exception": {
    "type": "TypeError",
    "value": "Cannot read properties of null (reading '\''getAttribute'\'')",
    "stacktrace": {
      "frames": [
        { "filename": "https://app.example.com/static/js/main.chunk.js", "function": "handleClick", "lineno": 112, "colno": 45 }
      ]
    }
  }
}'
POST/api/v1/bugwatch/ingest/mobile

Mobile ingest – iOS native crash

Ingest events from native mobile apps (iOS, Android, Flutter, React Native).

Authentication: x-bugwatch-token — a client-signed token built on device by the SDK. The app embeds a per-project mobileAppSecret (HKDF-derived), signs each request locally, and sends only the signed token. The secret is never transmitted.

The pre-request script on this request reproduces the exact token the SDK builds using CryptoJS. Set projectId, environment, and mobileAppSecret in your environment before running.

Token format: base64url(claims).base64url(HMAC-SHA256(claims, appSecret))

Claims (deterministic key order, no spaces):

{"pid":"<projectId>","env":"<env>","iat":<nowSec>,"exp":<nowSec+300>,"nonce":"<16 hex chars>"}

Request

  • Header: x-bugwatch-token: {{mobileToken}} (auto-built by pre-request script)
  • Content-Type: application/json or application/x-ndjson
  • Max body: 2 MB
  • Rate limit: 12,000 events / 60 seconds per project

Success — 202 Accepted

{ "ingested": 1, "skipped": 0, "deduped": 0 }

Common errors

  • 401 — invalid/expired/malformed token
  • 429 — rate limited

Event model (what each SDK puts on the wire)

One merged event per request (eventId, time, level required). The four native SDKs share this endpoint:

  • Native crashes (iOS, Android NDK) carry payloadVersion: 2 with top-level binaryImages + nativeStacktrace (iOS) / nativeFrames (Android) — raw instruction_addr values the worker symbolicates against the uploaded dSYM / ELF by UUID / build-id.
  • JVM / Dart / JS exceptions (Android, Flutter, React Native) and handled errors carry exception.stacktrace as an array of { filename, function, lineno, colno, in_app } frames — de-obfuscated server-side via the uploaded R8 mapping / dart-symbols / source map.
  • All SDKs also emit ANR / app-hang, message, and release-health session events through this same endpoint.

See the per-platform examples in this folder — iOS native crash, Android JVM, Android NDK, Flutter, React Native — and the matching upload in Source Maps & Symbols.

Headers

x-bugwatch-token

Request body

application/json
{
  "eventId": "bw_e_{{$guid}}",
  "time": {{nowMs}},
  "level": 60,
  "message": "Fatal: EXC_BAD_ACCESS (SIGSEGV)",
  "platform": "ios",
  "release": "1.0.0",
  "environment": "production",
  "sdk": {
    "name": "bugwatch-ios",
    "version": "0.1.1"
  },
  "device": {
    "model": "iPhone15,2",
    "family": "iPhone",
    "osName": "iOS",
    "osVersion": "17.4.1",
    "bundleId": "com.example.MyApp",
    "appVersion": "1.4.2",
    "appBuild": "318"
  },
  "exception": {
    "type": "EXC_BAD_ACCESS",
    "value": "Attempted to dereference a null pointer",
    "stacktrace": null
  },
  "binaryImages": [
    {
      "name": "MyApp",
      "debug_id": "550e8400-e29b-41d4-a716-446655440001",
      "arch": "arm64",
      "image_addr": "0x100008000",
      "image_size": 65536,
      "is_main_image": true
    },
    {
      "name": "Foundation",
      "debug_id": "7c8f1a22-9b33-4d55-8e21-0a1b2c3d4e5f",
      "arch": "arm64",
      "image_addr": "0x1db000000",
      "image_size": 2097152
    }
  ],
  "nativeStacktrace": [
    {
      "frame_index": 0,
      "instruction_addr": "0x100008234",
      "image_addr": "0x100008000",
      "image_name": "MyApp",
      "in_app": true
    },
    {
      "frame_index": 1,
      "instruction_addr": "0x1db123456",
      "image_addr": "0x1db000000",
      "image_name": "Foundation"
    }
  ],
  "crashedThreadId": 0,
  "payloadVersion": 2,
  "tags": {
    "device": "iPhone 15 Pro"
  },
  "user": {
    "id": "usr_ios_001"
  }
}

Responses

202 – Mobile event ingested

{
  "ingested": 1,
  "skipped": 0,
  "deduped": 0
}
boltTry it
env
POSThttps://api.newinstance.cloud/api/v1/bugwatch/ingest/mobile

Headers

x-bugwatch-token

Request body

Code samples

curl -X POST 'https://api.newinstance.cloud/api/v1/bugwatch/ingest/mobile' \
  -H 'Content-Type: application/json' \
  --data-raw '{
  "eventId": "bw_e_{{$guid}}",
  "time": {{nowMs}},
  "level": 60,
  "message": "Fatal: EXC_BAD_ACCESS (SIGSEGV)",
  "platform": "ios",
  "release": "1.0.0",
  "environment": "production",
  "sdk": {
    "name": "bugwatch-ios",
    "version": "0.1.1"
  },
  "device": {
    "model": "iPhone15,2",
    "family": "iPhone",
    "osName": "iOS",
    "osVersion": "17.4.1",
    "bundleId": "com.example.MyApp",
    "appVersion": "1.4.2",
    "appBuild": "318"
  },
  "exception": {
    "type": "EXC_BAD_ACCESS",
    "value": "Attempted to dereference a null pointer",
    "stacktrace": null
  },
  "binaryImages": [
    {
      "name": "MyApp",
      "debug_id": "550e8400-e29b-41d4-a716-446655440001",
      "arch": "arm64",
      "image_addr": "0x100008000",
      "image_size": 65536,
      "is_main_image": true
    },
    {
      "name": "Foundation",
      "debug_id": "7c8f1a22-9b33-4d55-8e21-0a1b2c3d4e5f",
      "arch": "arm64",
      "image_addr": "0x1db000000",
      "image_size": 2097152
    }
  ],
  "nativeStacktrace": [
    {
      "frame_index": 0,
      "instruction_addr": "0x100008234",
      "image_addr": "0x100008000",
      "image_name": "MyApp",
      "in_app": true
    },
    {
      "frame_index": 1,
      "instruction_addr": "0x1db123456",
      "image_addr": "0x1db000000",
      "image_name": "Foundation"
    }
  ],
  "crashedThreadId": 0,
  "payloadVersion": 2,
  "tags": {
    "device": "iPhone 15 Pro"
  },
  "user": {
    "id": "usr_ios_001"
  }
}'