---
title: "Sessions"
description: "Release health tracking via session lifecycle updates and crash-free rate computation."
url: https://develop.sentry.dev/sdk/telemetry/sessions/
---

# Sessions

This document uses key words such as "MUST", "SHOULD", and "MAY" as defined in

<!-- -->

[RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) to indicate requirement levels.

Statusstable

Version`1.7.0`[(changelog)](https://develop.sentry.dev/sdk/telemetry/sessions.md#changelog)

## [Overview](https://develop.sentry.dev/sdk/telemetry/sessions.md#overview)

Sessions allow Sentry to track the health of releases by monitoring when applications start, end, crash, or encounter errors. SDKs send session update events as `session` or `sessions` envelope items. Sentry uses this data to compute crash-free rates, error rates, and session durations per release.

Related specs:

* [Envelopes](https://develop.sentry.dev/sdk/foundations/transport/envelopes.md) — transport format
* [Envelope Items](https://develop.sentry.dev/sdk/foundations/transport/envelope-items.md) — `session` and `sessions` item type constraints

***

## [Concepts](https://develop.sentry.dev/sdk/telemetry/sessions.md#concepts)

### [Session Modes](https://develop.sentry.dev/sdk/telemetry/sessions.md#session-modes)

SDKs operate in one of two session modes:

* **User-mode** *(application-mode)* — A single session spans the full application run. Typical for mobile apps, desktop apps, CLI tools, and browser sessions. Session duration is meaningful.
* **Server-mode** *(request-mode)* — Each HTTP request or RPC call is a separate session. High volume, short-lived. Duration is typically not useful. Sessions **SHOULD** be pre-aggregated before sending.

### [Session Lifecycle](https://develop.sentry.dev/sdk/telemetry/sessions.md#session-lifecycle)

A session progresses through these states:

```bash
[init] → ok → exited | unhandled | crashed | abnormal
```

* `ok` — session is in progress and healthy
* `exited` — session terminated normally (duration is tracked)
* `unhandled` — session terminated with an unhandled error
* `crashed` — session terminated in a crash (process terminated)
* `abnormal` — session fate is unknown (e.g., power loss, force kill)

### [Server Model](https://develop.sentry.dev/sdk/telemetry/sessions.md#server-model)

Sentry's session system uses hourly buckets of pre-materialized data. Session updates are immediately materialized into the correct bucket on arrival. This means the protocol is **additive only** — the client **MUST** store the entire session state and send it with each update.

***

## [Behavior](https://develop.sentry.dev/sdk/telemetry/sessions.md#behavior)

### [Session Lifecycle](https://develop.sentry.dev/sdk/telemetry/sessions.md#session-lifecycle-1)

Stablespecified since

<!-- -->

1.0.0

Sessions are entirely client-driven. The client determines when a session starts, ends, or transitions to an unhealthy state.

* Sessions are updated through session change events that hold the **entire** session state. The most recent event holds the authoritative state.
* The initial session event **MUST** have `init` set to `true`. This lets the server skip deduplication. Internally, `seq` is set to `0` when `init` is `true`.
* Sessions can only be updated for 5 days. After that, a session without a second event is permanently marked as good.
* A session does not have to be started in order to crash — just reporting a crash is sufficient.

### [Attribute Immutability](https://develop.sentry.dev/sdk/telemetry/sessions.md#attribute-immutability)

Stablespecified since

<!-- -->

1.0.0

SDKs **MUST NOT** change session attributes (`did`, `started`, or any `attrs` fields) in subsequent updates. Only `status`, `duration`, and `errors` **MAY** change. If a user is not known at session start, the session start **SHOULD** be delayed or the session restarted once the user is known.

### [Terminal Session States](https://develop.sentry.dev/sdk/telemetry/sessions.md#terminal-session-states)

Stablespecified since

<!-- -->

1.0.0

Once a session reaches a terminal state, the SDK **MUST NOT** send further updates. Terminal states are: `exited`, `crashed`, `abnormal`, and (since 1.6.0) `unhandled`.

SDKs **SHOULD** distinguish between terminal states:

* **`exited`**: The session ended cleanly. Only `exited` sessions have their duration averaged. A session **MAY** exit even if errors occurred.

* **`unhandled`** (since 1.6.0): An unhandled error occurred but the process did not terminate. Use when:

  * An unhandled error occurred with a natural session end (e.g., end of HTTP request).
  * The application did not handle an error, but the language or framework prevented termination.

* **`crashed`**: The application process terminated. Use when:

  * A complete crash occurred (crash to desktop, process termination).
  * A user feedback dialog is surfaced. After this, the SDK **MUST** start a new session.

* **`abnormal`**: The session fate is unknown. SDKs **SHOULD** prefer `exited` or `crashed` when possible. Use when the application did not shut down correctly (e.g., power loss, `kill -9`, task manager). Abnormal session ends are normally recorded on application restart.

### [Error Counting](https://develop.sentry.dev/sdk/telemetry/sessions.md#error-counting)

Stablespecified since

<!-- -->

1.0.0

SDKs **MUST** maintain a running `errors` counter that is incremented when errors occur during the session. The counter **MUST** also be incremented when a session goes to `crashed` (the crash itself is always an error). Ingest forces `errors` to 1 if not set or 0.

A session that is `ok` with `errors > 0` is considered "errored." All `crashed` and `abnormal` sessions are also considered errored but are subtracted from the final errored count.

(since 1.7.0) Only events from `captureException`, `captureError`, or `captureEvent` **MUST** increment the `errors` counter, and only when their level is `error` or higher. Events from `captureMessage` **MUST NOT** affect the session error count regardless of level.

| Method                              | Level     | Increments `errors` |
| ----------------------------------- | --------- | ------------------- |
| `captureException` / `captureError` | `fatal`   | Yes                 |
| `captureException` / `captureError` | `error`   | Yes                 |
| `captureException` / `captureError` | `warning` | No                  |
| `captureEvent`                      | `fatal`   | Yes                 |
| `captureEvent`                      | `error`   | Yes                 |
| `captureEvent`                      | `warning` | No                  |
| `captureMessage`                    | `fatal`   | No                  |
| `captureMessage`                    | `error`   | No                  |
| `captureMessage`                    | `warning` | No                  |

### [Session Modes](https://develop.sentry.dev/sdk/telemetry/sessions.md#session-modes-1)

Stablespecified since

<!-- -->

1.1.0

SDKs **SHOULD** default to the session mode most appropriate for the language ecosystem:

**User-mode** *(application-mode)*:

* Typically a single session from application start to quit.
* (since 1.3.1) On mobile, sessions **MAY** end when the app is backgrounded for over 30 seconds.
* Sessions span multiple hubs/threads.
* Session duration is meaningful (typically minutes).

**Server-mode** *(request-mode)*:

* One session per HTTP request or RPC call.
* High volume — sessions **SHOULD** be pre-aggregated.
* Sessions are attached to a single hub/concurrency unit.
* Timing information is typically not useful.

When using user-mode, a single session **SHOULD** start at application initialization and persist through the runtime. When using server-mode, no application-wide session **SHOULD** be started — sessions are started/ended per request by integrations.

(since 1.3.0) If an SDK can detect that an application is better served by session aggregates, it **MUST NOT** report an application-wide session. The application-wide session may still be created during initialization but **MUST** be aborted and never sent to Sentry.

### [Pre-aggregation](https://develop.sentry.dev/sdk/telemetry/sessions.md#pre-aggregation)

Stablespecified since

<!-- -->

1.2.0

Server-mode SDKs **SHOULD** pre-aggregate closed sessions before sending to Sentry. When a session closes and has not been sent upstream (its `init` flag would be `true`), it is eligible for aggregation:

1. Round the `started` timestamp down to the minute.
2. Aggregate into the bucket identified by the rounded timestamp and `did`.
3. Increment the count for the session's terminal status. Use `errored` for sessions with `exited` status and non-zero `errors` count.

(since 1.3.0) SDKs **SHOULD** use a periodic session flusher (every 60 seconds) that sends the aggregated `sessions` envelope item. When a client is closed or flushed, the session flusher **MUST** also be flushed before the transport is closed.

### [Session Update Filtering](https://develop.sentry.dev/sdk/telemetry/sessions.md#session-update-filtering)

Stablespecified since

<!-- -->

1.4.0

When events are dropped by filtering mechanisms (sample rate, rate limiting, `beforeSend`, event processors, or ignored exception types), the session update behavior depends on the drop reason:

* Events dropped due to **sampling** or **rate limiting** **SHOULD** still update the session — the event was dropped to save quota but represents something the developer cares about.
* Events dropped for **other reasons** (beforeSend, event processors, ignored types) **SHOULD NOT** update the session — the developer chose to ignore them.

(since 1.4.1) Rate limited events **SHOULD** update the session despite being dropped.

If the event has been dropped but the session was updated, the session update **SHOULD** be sent to the server without the event in case the session changed from healthy to errored or from any state to crashed (for user-attended sessions).

**Filter order** (Python SDK as reference):

1. Check for ignored exception types (`ignore_errors`)
2. Apply scoped event processors
3. Apply global event processors
4. Apply `beforeSend`
5. Update the session if the event made it this far
6. Apply sampling rate

### [Session Updates and Sending](https://develop.sentry.dev/sdk/telemetry/sessions.md#session-updates-and-sending)

Stablespecified since

<!-- -->

1.1.0

SDKs **SHOULD** automatically update the current session whenever data is captured (at the same point where `apply_to_scope` is called) to increment the `errors` count or update the session based on the distinct ID.

SDKs **SHOULD** aim to minimize the number of envelopes sent upstream.

Server-mode SDKs **SHOULD** use the periodic session flusher with pre-aggregation. User-mode SDKs **MAY** send session updates alongside captured events in the same envelope. The final session update **MAY** be batched.

The `init` flag **MUST** be set correctly for the first transmission of the session. Session metadata **MUST** be immutable after the initial transmission.

SDKs **SHOULD** send session updates in the same envelope as crash events when transitioning to `crashed`. This ensures both arrive together over unreliable networks.

***

## [Wire Format](https://develop.sentry.dev/sdk/telemetry/sessions.md#wire-format)

### [Session Update Payload](https://develop.sentry.dev/sdk/telemetry/sessions.md#session-update-payload)

Stablespecified since

<!-- -->

1.0.0

A session update is sent as a `session` envelope item containing a JSON object. Multiple `session` envelope items **MAY** appear in a single envelope. Ingestion may limit the maximum number of items per envelope.

| Field                | Type    | Required     | Since | Description                                                                                                            |
| -------------------- | ------- | ------------ | ----- | ---------------------------------------------------------------------------------------------------------------------- |
| `sid`                | String  | **OPTIONAL** | 1.0.0 | Session ID (UUID, client-generated). **MAY** be skipped if initial state is `exited`.                                  |
| `did`                | String  | **OPTIONAL** | 1.0.0 | Distinct ID (device or user ID). Automatically hashed before storage.                                                  |
| `seq`                | Number  | **OPTIONAL** | 1.0.0 | Logical clock. Defaults to current UNIX timestamp in milliseconds. Forced to `0` when `init` is `true`.                |
| `timestamp`          | String  | **OPTIONAL** | 1.0.0 | ISO DateTime of when the update occurred. Defaults to current UTC time. Called `received` in the data model.           |
| `started`            | String  | **REQUIRED** | 1.0.0 | ISO DateTime of when the session started.                                                                              |
| `init`               | Boolean | **OPTIONAL** | 1.0.0 | `true` for the first event of the session. Default: `false`.                                                           |
| `duration`           | Number  | **OPTIONAL** | 1.0.0 | Session duration in seconds (float). Inactive time **MAY** be subtracted.                                              |
| `status`             | String  | **OPTIONAL** | 1.0.0 | Session status. Default: `ok`. One of: `ok`, `exited`, `crashed`, `abnormal`, or (since 1.6.0) `unhandled`.            |
| `errors`             | Number  | **OPTIONAL** | 1.0.0 | Running error count. Default: `0`. **MUST** be incremented on crash.                                                   |
| `abnormal_mechanism` | String  | **OPTIONAL** | 1.5.0 | Mechanism that caused `abnormal` status (e.g., ANR detection). Default: `none`.                                        |
| `attrs`              | Object  | **REQUIRED** | 1.0.0 | Session attributes. See [Session Attributes](https://develop.sentry.dev/sdk/telemetry/sessions.md#session-attributes). |

#### [Session Attributes](https://develop.sentry.dev/sdk/telemetry/sessions.md#session-attributes)

| Field         | Type   | Required     | Since | Description                                                           |
| ------------- | ------ | ------------ | ----- | --------------------------------------------------------------------- |
| `release`     | String | **REQUIRED** | 1.0.0 | Release version (suggested format: `my-project-name@1.0.0`).          |
| `environment` | String | **OPTIONAL** | 1.0.0 | Environment name.                                                     |
| `ip_address`  | String | **OPTIONAL** | 1.0.0 | User IP address for filtering. Not persisted. Auto-filled if not set. |
| `user_agent`  | String | **OPTIONAL** | 1.0.0 | User agent string for filtering. Not persisted.                       |

### [Session Aggregates Payload](https://develop.sentry.dev/sdk/telemetry/sessions.md#session-aggregates-payload)

Stablespecified since

<!-- -->

1.2.0

For server-mode sessions, SDKs **SHOULD** send aggregated session counts as a `sessions` envelope item. Multiple `sessions` envelope items **MAY** appear in a single envelope. Ingestion may limit the maximum number of items per envelope.

| Field        | Type   | Required     | Since | Description                                              |
| ------------ | ------ | ------------ | ----- | -------------------------------------------------------- |
| `aggregates` | Array  | **REQUIRED** | 1.2.0 | Array of aggregate groups. See below.                    |
| `attrs`      | Object | **REQUIRED** | 1.2.0 | Session attributes (same as individual session `attrs`). |

#### [Aggregate Group Fields](https://develop.sentry.dev/sdk/telemetry/sessions.md#aggregate-group-fields)

| Field       | Type   | Required     | Since | Description                                                |
| ----------- | ------ | ------------ | ----- | ---------------------------------------------------------- |
| `started`   | String | **REQUIRED** | 1.2.0 | Timestamp rounded down to the minute. ISO DateTime.        |
| `did`       | String | **OPTIONAL** | 1.2.0 | Distinct user ID for this group.                           |
| `exited`    | Number | **OPTIONAL** | 1.2.0 | Sessions with `exited` status and zero errors.             |
| `abnormal`  | Number | **OPTIONAL** | 1.2.0 | Sessions with `abnormal` status.                           |
| `unhandled` | Number | **OPTIONAL** | 1.6.0 | Sessions with `unhandled` status.                          |
| `crashed`   | Number | **OPTIONAL** | 1.2.0 | Sessions with `crashed` status.                            |
| `errored`   | Number | **OPTIONAL** | 1.2.0 | Sessions with `exited` status and non-zero `errors` count. |

***

## [Public API](https://develop.sentry.dev/sdk/telemetry/sessions.md#public-api)

### [Start Session](https://develop.sentry.dev/sdk/telemetry/sessions.md#start-session)

Stablespecified since

<!-- -->

1.1.0

SDKs **MUST** expose a function to start a session:

```bash
startSession() -> void
```

Stores a session on the current scope and starts tracking it. This implicitly ends any existing session.

(since 1.3.0) Sessions **SHOULD** be enabled by default for the global hub/client initialized by `Sentry.init()`, and disabled by default for manually created clients.

Naming **SHOULD** follow the SDK's language conventions:

* `Sentry.startSession()` (JavaScript)
* `Hub.start_session()` (Python)

### [End Session](https://develop.sentry.dev/sdk/telemetry/sessions.md#end-session)

Stablespecified since

<!-- -->

1.1.0

SDKs **MUST** expose a function to end a session:

```bash
endSession() -> void
```

Ends the session, setting an appropriate `status` and `duration`, and enqueues it for sending to Sentry. SDKs **MUST NOT** send further updates for an ended session.

Naming **SHOULD** follow the SDK's language conventions:

* `Sentry.endSession()` (JavaScript)
* `Hub.end_session()` (Python)

### [Auto Session Tracking](https://develop.sentry.dev/sdk/telemetry/sessions.md#auto-session-tracking)

Stablespecified since

<!-- -->

1.1.0

SDKs **SHOULD** accept an `autoSessionTracking` configuration option (boolean, default varies by SDK).

When enabled, the SDK automatically starts and ends sessions based on the session mode. SDKs **MAY** also expose `startAutoSessionTracking()` / `stopAutoSessionTracking()` for runtime control.

Naming **SHOULD** follow the SDK's language conventions:

* `autoSessionTracking` (JavaScript)
* `auto_session_tracking` (Python)

***

## [Examples](https://develop.sentry.dev/sdk/telemetry/sessions.md#examples)

### [Session Update](https://develop.sentry.dev/sdk/telemetry/sessions.md#session-update)

```json
{
  "sid": "7c7b6585-f901-4351-bf8d-02711b721929",
  "did": "optional distinct user id",
  "init": true,
  "started": "2020-02-07T14:16:00Z",
  "duration": 60,
  "status": "exited",
  "attrs": {
    "release": "my-project-name@1.0.0",
    "environment": "production"
  }
}
```

### [Session Aggregates](https://develop.sentry.dev/sdk/telemetry/sessions.md#session-aggregates)

```json
{
  "aggregates": [
    {
      "started": "2020-02-07T14:16:00Z",
      "exited": 123
    },
    {
      "started": "2020-02-07T14:16:00Z",
      "did": "optional distinct user id",
      "exited": 12,
      "errored": 3
    }
  ],
  "attrs": {
    "release": "my-project-name@1.0.0",
    "environment": "development"
  }
}
```

### [Full Envelope](https://develop.sentry.dev/sdk/telemetry/sessions.md#full-envelope)

#### [Single Session](https://develop.sentry.dev/sdk/telemetry/sessions.md#single-session)

```bash
{}
{"type":"session"}
{"sid":"7c7b6585-f901-4351-bf8d-02711b721929","init":true,"started":"2020-02-07T14:16:00Z","status":"ok","attrs":{"release":"my-project-name@1.0.0"}}
```

#### [Aggregated Sessions](https://develop.sentry.dev/sdk/telemetry/sessions.md#aggregated-sessions)

```bash
{}
{"type":"sessions"}
{"aggregates":[{"started":"2020-02-07T14:16:00Z","exited":123}],"attrs":{"release":"my-project-name@1.0.0"}}
```

***

## [Changelog](https://develop.sentry.dev/sdk/telemetry/sessions.md#changelog)

| Version | Date       | Summary                                                                       |
| ------- | ---------- | ----------------------------------------------------------------------------- |
| `1.7.0` | 2025-10-16 | Added error level impact rules for session error counting                     |
| `1.6.0` | 2025-09-30 | Added unhandled session status                                                |
| `1.5.1` | 2025-07-16 | Clarified session envelope wording                                            |
| `1.5.0` | 2023-05-08 | Added abnormal\_mechanism field to session payload                            |
| `1.4.1` | 2022-11-14 | Clarified rate limited events should update sessions                          |
| `1.4.0` | 2022-04-26 | Added session update filtering requirements for dropped events                |
| `1.3.1` | 2021-06-02 | Added mobile session background timeout note                                  |
| `1.3.0` | 2021-05-17 | Added SDK implementation guidelines (individual sessions, session aggregates) |
| `1.2.1` | 2021-01-13 | Updated release format to match suggested pattern                             |
| `1.2.0` | 2020-12-02 | Added session aggregates payload                                              |
| `1.1.1` | 2020-09-02 | Clarified session modes and improved documentation                            |
| `1.1.0` | 2020-08-28 | Added SDK considerations (session modes, exposed API, update recommendations) |
| `1.0.0` | 2020-05-25 | Initial spec — session update payload, basic operation, server model          |
