> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stackshift.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# Observe

> Crash reporting, error tracking, and release health for your production app, with alerts by email and webhook.

<Tip>
  **Live.** This area is documented as current, user-reliable behavior.
</Tip>

## Goal

Send sessions and crashes from your app, triage grouped issues, and set up health alerts.

## Prerequisites

* A mobile app created in StackShift
* mobile\_observe is enabled on the plan

## Workflow

<Steps>
  <Step>
    Report a session\_start event when your app launches and crash or error events when something breaks.
  </Step>

  <Step>
    Open the Observe tab to see crash-free rates, grouped issues, and per-version health.
  </Step>

  <Step>
    Resolve or ignore issues as you fix them; a resolved issue that comes back is flagged as returned.
  </Step>

  <Step>
    Add alert rules so a crash-free drop or a new issue notifies you by email or webhook.
  </Step>
</Steps>

## Sending events

The quickest start is an SDK: @stackshift-cloud/observe-react-native for React Native and Expo, or stackshift\_observe for Flutter — one init call wires sessions and crash handlers. Underneath they send batches of up to 50 events to this public endpoint. No API key is needed; the app key in the URL is your app slug. IP addresses are hashed and payloads are limited to the fields shown here.

```bash theme={null}
curl -X POST https://api.stackshift.dev/observe/<app-slug>/events \\
  -H 'Content-Type: application/json' \\
  -d '{
    "events": [
      { "kind": "session_start", "platform": "android", "app_version": "1.4.0", "install_id": "<hashed-device-id>" },
      { "kind": "crash", "platform": "android", "app_version": "1.4.0", "install_id": "<hashed-device-id>",
        "exception_type": "NullPointerException", "message": "boom",
        "frames": [ { "module": "com.acme.app.Checkout", "function": "pay", "line": 42, "in_app": true } ] }
    ]
  }'
```

## Event kinds

* session\_start — one per app launch; powers sessions, installs, and crash-free rates. Include update\_group when running an over-the-air update.
* crash — a fatal error with exception type, message, and stack frames.
* error — a handled, non-fatal error with the same shape as a crash.
* anr — the app stopped responding (Android).

## How grouping works

Crashes and errors are grouped into issues by exception type and the top in-app stack frame, so the same bug reported from thousands of devices shows as one issue. Messages and line numbers are ignored for grouping because they change between builds.

## Alerts

* New issue appears and resolved issue returns fire the moment the event arrives.
* Crash-free below a threshold and error volume spike are checked against a rolling window.
* Each rule has a cooldown so a bad hour does not flood your inbox.
* Delivery is by email to the app owner and the observe.alert webhook event.

## Readable Android crashes (symbolication)

Release Android builds obfuscate class and method names. Upload the R8/proguard mapping file for each version and Observe rewrites incoming stack frames to the original names before grouping. Cloud builds upload their mapping automatically; from CI, PUT the file to /api/v1/public/mobile/ci/observe/symbols?platform=android\&version\_code=42 with a ci:ingest token. iOS native symbolication (dSYM) is not supported yet.

## Data retention

Raw events are kept for 30 days by default; hourly health rollups and issues are kept indefinitely. No personal data is stored: IPs are hashed on arrival and install identifiers should already be hashed by your app.

## Expected result

<Check>
  Production crashes appear grouped by cause within minutes, and health regressions page you instead of your users.
</Check>

## Common failures

<Warning>
  * Events are rejected: the app key in the URL must be your app slug, and each event needs kind, platform, app\_version, and install\_id.
  * Everything counts as one install: send a stable, hashed install identifier, not a fresh random value per launch.
  * Crash-free rate looks wrong: it is computed from session\_start events, so report sessions as well as crashes.
</Warning>
