---
title: "Metrics"
description: "Counter, gauge, and distribution metrics sent as batched trace_metric envelope items."
url: https://develop.sentry.dev/sdk/telemetry/metrics/
---

# Metrics

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`2.8.0`[(changelog)](https://develop.sentry.dev/sdk/telemetry/metrics.md#changelog)

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

This spec defines the format used by Sentry to ingest metrics, as well as the SDK API and behavior that create and send metrics to Sentry. Metrics are sent as `trace_metric` envelope items containing JSON-encoded payloads.

##### Note

The envelope item type is named `trace_metric` for internal usage to avoid naming collisions with other metric systems within Sentry's infrastructure. From an SDK perspective, these are simply referred to as "metrics".

Related specs:

* [Envelopes](https://develop.sentry.dev/sdk/foundations/transport/envelopes.md) — transport format
* [Attributes](https://develop.sentry.dev/sdk/foundations/state-management/scopes/attributes.md) — attribute types and structure
* [Tracing without Performance](https://develop.sentry.dev/sdk/foundations/trace-propagation.md#default-propagation) — required before adding metrics support
* [Telemetry Processor](https://develop.sentry.dev/sdk/foundations/processing/telemetry-processor.md) — buffer data forwarding scenarios

***

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

### [Metric Types](https://develop.sentry.dev/sdk/telemetry/metrics.md#metric-types)

A metric has a `type` that determines how its values are interpreted:

* **Counter** — tracks the number of times an event occurs. Only increases. Useful for requests, errors, or any countable event.
* **Gauge** — tracks a value that can arbitrarily increase or decrease over time, such as memory usage, queue depth, or connection pool size.
* **Distribution** — tracks the statistical distribution of a set of values. Useful for understanding percentiles, averages, and other statistical properties of measurements like response times or file sizes.

### [Attributes](https://develop.sentry.dev/sdk/telemetry/metrics.md#attributes)

Metrics carry typed key-value pairs called **attributes** for dimensional filtering and grouping. Each attribute declares its type (`string`, `boolean`, `integer`, `double`). See [Attributes](https://develop.sentry.dev/sdk/foundations/state-management/scopes/attributes.md) for the full type specification.

### [Batching](https://develop.sentry.dev/sdk/telemetry/metrics.md#batching)

Multiple metrics are batched into a single `trace_metric` envelope item for efficient transport. SDKs buffer metrics locally and flush them periodically or when size thresholds are reached.

***

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

##### Note

An SDK **SHOULD** implement [Tracing without Performance](https://develop.sentry.dev/sdk/foundations/trace-propagation.md#default-propagation) before adding support for metrics. This is required to ensure that metrics are associated with traces and that the correct trace context is sent to Sentry.

### [Processing Pipeline](https://develop.sentry.dev/sdk/telemetry/metrics.md#processing-pipeline)

Stablespecified since

<!-- -->

2.0.0

Metric processing **MUST** follow this order:

1. Capture metric via [Public APIs](https://develop.sentry.dev/sdk/telemetry/metrics.md#metrics-module) (e.g. `Sentry.metrics.count`).
2. Check if metrics are disabled as per `enableMetrics`/`enable_metrics` configuration — if so, skip the rest of the steps.
3. Pass the metric to Hub/Scope via a generic method (e.g., `captureMetric(metric)`).
4. Pass the metric to the Client via a generic method (e.g., `captureMetric(metric)`).
5. Process captured metric (attach default attributes as per [Default Attributes](https://develop.sentry.dev/sdk/telemetry/metrics.md#default-attributes)).
6. Run `beforeSendMetric`/`before_send_metric` to filter or modify the metric.
7. Add metric to buffer/batch processor as detailed in [Buffering](https://develop.sentry.dev/sdk/telemetry/metrics.md#buffering).
8. At time of flushing buffer, send array of metrics to Sentry via `trace_metric` envelope, apply rate limiting as per [Data Category and Rate Limiting](https://develop.sentry.dev/sdk/telemetry/metrics.md#data-category-and-rate-limiting).

### [Default Attributes](https://develop.sentry.dev/sdk/telemetry/metrics.md#default-attributes)

Stablespecified since

<!-- -->

2.0.0

SDKs **MUST** attach the following attributes to every metric by default:

1. `sentry.environment` — the environment set in the SDK, if defined.
2. `sentry.release` — the release set in the SDK, if defined.
3. `sentry.sdk.name` — the name of the SDK that sent the metric.
4. `sentry.sdk.version` — the version of the SDK that sent the metric.

SDKs **SHOULD** minimize the number of default attributes. Metrics cardinality can explode quickly with too many attributes. New default attributes **SHOULD** only be added after significant feedback from users and discussion internally with the SDK and ingest teams.

### [User Attributes](https://develop.sentry.dev/sdk/telemetry/metrics.md#user-attributes)

Stablespecified since

<!-- -->

2.0.0

SDKs **MAY** attach user information as attributes, guarded by `sendDefaultPii` ([unless manually set by user](https://develop.sentry.dev/sdk/foundations/data-scrubbing.md#sensitive-data), since 2.5.0):

1. `user.id` — the user ID. Maps to `id` in the [User](https://develop.sentry.dev/sdk/foundations/transport/event-payloads/user.md) payload.
2. `user.name` — the username. Maps to `username` in the [User](https://develop.sentry.dev/sdk/foundations/transport/event-payloads/user.md) payload.
3. `user.email` — the email address. Maps to `email` in the [User](https://develop.sentry.dev/sdk/foundations/transport/event-payloads/user.md) payload.

### [Browser Attributes (Relay)](https://develop.sentry.dev/sdk/telemetry/metrics.md#browser-attributes-relay)

Stablespecified since

<!-- -->

2.0.0

By default, Relay parses the user agent attached to an incoming metric envelope to extract `browser` and `os` information. These attributes are attached by Relay, but client-side SDKs **MAY** attach them if they do not forward a user agent when sending metrics to Sentry.

1. `browser.name` — display name of the browser application. Maps to `name` in the [Browser Context](https://develop.sentry.dev/sdk/foundations/transport/event-payloads/contexts.md#browser-context).
2. `browser.version` — version string of the browser. Maps to `version` in the [Browser Context](https://develop.sentry.dev/sdk/foundations/transport/event-payloads/contexts.md#browser-context).

### [Backend SDK Attributes](https://develop.sentry.dev/sdk/telemetry/metrics.md#backend-sdk-attributes)

Stablespecified since

<!-- -->

2.1.0

Backend SDKs (Node.js, Python, PHP, etc.) **SHOULD** attach the following attribute:

1. `server.address` — the address of the server that sent the metric. Equivalent to [`server_name`](https://develop.sentry.dev/sdk/foundations/transport/event-payloads.md#optional-attributes) attached to errors and transactions.

### [Buffering](https://develop.sentry.dev/sdk/telemetry/metrics.md#buffering)

Stablespecified since

<!-- -->

2.0.0

SDKs **MUST** buffer metrics before sending them (since 2.2.0, tightened from SHOULD). SDKs **SHOULD** flush the buffer when specific conditions are met. For initial implementation, a simple strategy is fine, for example: flushing if the buffer length exceeds 100 items or if 5 seconds have passed.

To prevent data loss, the buffer **SHOULD** forward metrics to the transport in the scenarios outlined in the [telemetry buffer data forwarding scenarios](https://develop.sentry.dev/sdk/foundations/processing/telemetry-processor.md#data-forwarding-scenarios) (since 2.2.0).

Furthermore:

* The aggregation window **SHOULD** be time and size based.
* SDKs **SHOULD** implement safeguards to prevent excessive memory usage from metric buffering.

### [Tracing Association](https://develop.sentry.dev/sdk/telemetry/metrics.md#tracing-association)

Stablespecified since

<!-- -->

2.0.0

Metrics **SHOULD** be associated with traces if possible. If a metric is recorded during an active span, the SDK **SHOULD** set the `span_id` property of the metric to the span ID of the span that was active when the metric was collected.

The `trace_id` field is **REQUIRED** on every metric payload and **MUST** be taken from the current propagation context.

### [Replay Association](https://develop.sentry.dev/sdk/telemetry/metrics.md#replay-association)

Stablespecified since

<!-- -->

2.3.0

Whenever possible, metrics **SHOULD** be linked to replays. If a metric is recorded while an active, sampled replay is in progress, the SDK **SHOULD** attach:

1. `sentry.replay_id` — the ID of the replay that was active when the metric was collected. This **MUST NOT** be set if there was no active replay.
2. `sentry._internal.replay_is_buffering` — indicates that the metric is associated with a replay that is currently buffering. This ensures correct handling of scenarios where a `replay_id` is present but the corresponding replay was never actually sent.

### [Metric Ordering](https://develop.sentry.dev/sdk/telemetry/metrics.md#metric-ordering)

Some runtimes (notably Cloudflare Workers) freeze timer APIs (`Date.now()`, `performance.now()`) during synchronous execution, causing multiple metrics to share identical timestamps. SDKs that target runtimes where timestamps may be frozen or lack sub-millisecond precision **MUST** attach a `sentry.timestamp.sequence` integer attribute to every metric. SDKs that only target runtimes with reliable sub-millisecond timestamps **MAY** omit it.

Candidatespecified since

<!-- -->

2.6.0

When sent, the sequence integer **MUST**:

* Start at `0` when the SDK initializes.

* Increment by `1` for each metric that is captured.

* Reset to `0` when:

  * The SDK is re-initialized.
  * The current metric's integer millisecond differs from the previous metric's integer millisecond (i.e., `floor(timestamp_seconds * 1000)` changes).

The sequence provides deterministic ordering within a single SDK instance. It does not guarantee ordering across independent processes or workers, which have separate counters. The reset behavior ensures the sequence only increments for consecutive metrics that share the same timestamp.

### [Data Category and Rate Limiting](https://develop.sentry.dev/sdk/telemetry/metrics.md#data-category-and-rate-limiting)

### [Data Category and Rate Limiting](https://develop.sentry.dev/sdk/telemetry/metrics.md#data-category-and-rate-limiting-1)

Stablespecified since

<!-- -->

2.0.0

The data category for metrics is `trace_metric`. Rate limiting applies as usual. SDKs **SHOULD** track client outcomes to monitor how often metrics are dropped. If the SDK receives a rate limit, it **MUST NOT** send any trace metrics until the limit expires (based on the communicated end timestamp).

### [Debug Logging](https://develop.sentry.dev/sdk/telemetry/metrics.md#debug-logging)

Stablespecified since

<!-- -->

2.0.0

If `debug` is set to `true` in SDK init, calls to the Sentry metrics API **SHOULD** also print to the console with appropriate details. This will help debugging metrics setups.

### [Auto-Emitted Metrics](https://develop.sentry.dev/sdk/telemetry/metrics.md#auto-emitted-metrics)

Candidatespecified since

<!-- -->

2.7.0

Metrics emitted via the [public API](https://develop.sentry.dev/sdk/telemetry/metrics.md#metrics-module) are opt-out. The `enableMetrics`/`enable_metrics` option **MUST** act as a general kill switch for all metrics sent to Sentry — when set to `false`, no metrics **MUST** be sent, regardless of whether they originate from the public API, auto-emitting integrations, or third-party bindings.

However, metrics that are **automatically emitted by integrations or libraries** without an explicit user call follow different rules because they can generate unexpected volume and cost.

**Integrations that auto-emit metrics** — An SDK integration that automatically captures metrics (e.g., recording HTTP request durations, database query counts, or runtime resource usage) **MUST** be opt-in. The integration **MUST NOT** emit any metrics unless the user explicitly enables it. The opt-in mechanism **MAY** be a dedicated integration-level option or requiring the user to explicitly add the integration.

**Third-party metrics bindings** — An SDK feature that binds to an external library's metrics API and mirrors those metrics as Sentry metrics in the background (e.g., syncing from a framework's built-in metrics or an OpenTelemetry metrics pipeline) **MUST** also be opt-in. Users **MUST** explicitly enable the binding before any metrics are forwarded to Sentry.

These rules exist because auto-emitted metrics can cause a high volume of telemetry that directly impacts a user's quota. Unlike spans or errors — where users have prior intuition about volume — silently emitting metrics on their behalf could lead to unexpected costs. Requiring opt-in ensures users remain in control of their metrics volume.

***

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

### [`trace_metric` Envelope Item](https://develop.sentry.dev/sdk/telemetry/metrics.md#trace_metric-envelope-item)

Stablespecified since

<!-- -->

2.0.0

The `trace_metric` envelope item payload is a JSON object that **MUST** include an `items` array of metric entries, allowing multiple metrics per envelope item. The payload **MAY** also include top-level `version` and `ingest_settings` fields as specified in the next section. See the [Examples](https://develop.sentry.dev/sdk/telemetry/metrics.md#full-trace_metric-envelope) section for a complete envelope.

An envelope **MUST** contain at most one `trace_metric` envelope item — all metrics for a flush are batched into a single item's `items` array. Metrics from different traces **MAY** be mixed into the same `trace_metric` item, but if they are, the envelope **MUST NOT** include a DSC (dynamic sampling context) header.

**Item Headers:**

| Field          | Type   | Required     | Description                                                                   |
| -------------- | ------ | ------------ | ----------------------------------------------------------------------------- |
| `type`         | String | **REQUIRED** | **MUST** be `"trace_metric"`.                                                 |
| `item_count`   | Number | **REQUIRED** | Number of metric items in the `items` array. **MUST** match the actual count. |
| `content_type` | String | **REQUIRED** | **MUST** be `"application/vnd.sentry.items.trace-metric+json"`.               |

```json
{
	"type": "trace_metric",
	"item_count": 10,
	"content_type": "application/vnd.sentry.items.trace-metric+json"
}
{
	"version": 2,
	"ingest_settings": {
		"infer_ip": "auto",
		"infer_useragent": "auto"
	},
	"items": [{..metric..}, {..metric..}, {..metric..}]
}
```

### [`version` and `ingest_settings` properties](https://develop.sentry.dev/sdk/telemetry/metrics.md#version-and-ingest_settings-properties)

Candidatespecified since

<!-- -->

2.8.0

The `trace_metric` envelope item `ingest_settings` property is an optional JSON object that contains ingestion settings for Relay, for example, to infer certain data from the incoming request.

| Field             | Type   | Required     | Description                                                                                        |
| ----------------- | ------ | ------------ | -------------------------------------------------------------------------------------------------- |
| `infer_ip`        | String | **OPTIONAL** | The setting to infer the IP address from the incoming request. One of `auto` or `never` (default). |
| `infer_useragent` | String | **OPTIONAL** | The setting to infer the user agent from the incoming request. One of `auto` or `never` (default). |

SDKs like Browser or React Native **MAY** set these to `"auto"` to instruct Relay to infer the IP address or user agent from the incoming request and put it onto the metric as an attribute.

For ingestion settings to take effect, the SDK **MUST** also set the `version` property to `2` (`number`) or higher. If `version` is omitted, Relay treats the payload as version `1` and doesn't apply `ingest_settings`.

### [Metric Payload](https://develop.sentry.dev/sdk/telemetry/metrics.md#metric-payload)

Stablespecified since

<!-- -->

2.0.0

Each metric in the `items` array is a JSON object with the following fields:

```json
{
  "timestamp": 1544719860.0,
  "trace_id": "5b8efff798038103d269b633813fc60c",
  "span_id": "b0e6f15b45c36b12",
  "name": "api.response_time",
  "value": 125.5,
  "unit": "millisecond",
  "type": "distribution",
  "attributes": {
    "endpoint": { "value": "api/users", "type": "string" },
    "method": { "value": "GET", "type": "string" },
    "status_code": { "value": 200, "type": "integer" }
  }
}
```

| Field        | Type   | Required     | Since | Description                                                                                                                                                                                                                          |
| ------------ | ------ | ------------ | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `timestamp`  | Number | **REQUIRED** | 2.0.0 | Timestamp in seconds (epoch time) indicating when the metric was recorded.                                                                                                                                                           |
| `type`       | String | **REQUIRED** | 2.0.0 | The type of metric. One of `counter`, `gauge`, `distribution`.                                                                                                                                                                       |
| `name`       | String | **REQUIRED** | 2.0.0 | The name of the metric. **SHOULD** follow a hierarchical naming convention using dots as separators (e.g., `api.response_time`, `db.query.duration`).                                                                                |
| `value`      | Number | **REQUIRED** | 2.0.0 | The numeric value. For `counter`: the count to increment by (default 1). For `gauge`: the current value. For `distribution`: a single measured value. Integers **MUST** be 64-bit signed; doubles **MUST** be 64-bit floating point. |
| `trace_id`   | String | **REQUIRED** | 2.0.0 | 16 random bytes encoded as a hex string (32 characters). Taken from the current propagation context.                                                                                                                                 |
| `span_id`    | String | **OPTIONAL** | 2.3.0 | 8 random bytes encoded as a hex string (16 characters). The span ID of the span that was active when the metric was emitted.                                                                                                         |
| `unit`       | String | **OPTIONAL** | 2.0.0 | The unit of measurement for the metric value.                                                                                                                                                                                        |
| `attributes` | Object | **OPTIONAL** | 2.0.0 | Typed key-value pairs. See [Attributes](https://develop.sentry.dev/sdk/foundations/state-management/scopes/attributes.md) for supported types and structure.                                                                         |

***

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

### [Initialization Options](https://develop.sentry.dev/sdk/telemetry/metrics.md#initialization-options)

Stablespecified since

<!-- -->

2.0.0

SDKs **MUST** expose the following configuration options:

* `enableMetrics`/`enable_metrics` — a boolean flag to control if metric envelopes will be generated and sent to Sentry. If `false`, the SDK **MUST NOT** send metrics. Defaults to `true`.

* `beforeSendMetric`/`before_send_metric` — an **OPTIONAL** function that takes a metric object and returns a metric object. Called before sending the metric to Sentry. Can be used to modify the metric or prevent it from being sent (by returning `null`/`None`).

While metrics functionality is in an experimental state, SDKs **SHOULD** put these options in an experimental namespace to avoid breaking changes:

```bash
Sentry.init({
  // stable
  enableMetrics: true,

  // experimental
  _experiments: { enableMetrics: true },
})
```

### [Metrics Module](https://develop.sentry.dev/sdk/telemetry/metrics.md#metrics-module)

Stablespecified since

<!-- -->

2.0.0

SDKs **MUST** expose metrics methods in a `metrics` module or namespace. At minimum, the SDK **MUST** implement the following methods:

* `Sentry.metrics.count(name, value, options)` — increment a counter
* `Sentry.metrics.gauge(name, value, options)` — set a gauge value
* `Sentry.metrics.distribution(name, value, options)` — add a distribution value

**Parameters:**

* `name` **String, required** — the name of the metric.

* `value` **Number, required** — the value of the metric.

* `options` **Object, optional** — containing:

  * `unit` **String, optional** — the unit of measurement (only used for `distribution` and `gauge`). SDKs **MUST NOT** restrict what can be sent in (e.g. by using an enum) but **SHOULD** offer constants or similar that help customers send in [units we support](https://develop.sentry.dev/sdk/foundations/state-management/scopes/attributes.md#units) (since 2.4.0).
  * `attributes` **Object, optional** — a dictionary of attributes (key-value pairs with type information).
  * `scope` **Scope, optional** — the scope to capture the metric with.

The Hub/Scope and Client **MUST** exclusively provide a generic method for capturing metrics (e.g., `captureMetric(metric)`). They **MUST NOT** replicate the static `Sentry.metrics.X` API methods to avoid increasing our API surface. Users utilizing multiple Hub/Scope or Clients will need to rely on the generic method for capturing metrics.

### [Threading and Concurrency Considerations](https://develop.sentry.dev/sdk/telemetry/metrics.md#threading-and-concurrency-considerations)

The threading and concurrency considerations for metrics are the same as for logs. See the [Threading and Concurrency Considerations section in the Logs documentation](https://develop.sentry.dev/sdk/telemetry/logs.md#threading-and-concurrency-considerations) for more information.

***

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

### [Counter metric](https://develop.sentry.dev/sdk/telemetry/metrics.md#counter-metric)

```json
{
  "name": "api.requests",
  "value": 1,
  "type": "counter",
  "attributes": {
    "endpoint": { "value": "/api/users", "type": "string" },
    "method": { "value": "POST", "type": "string" }
  }
}
```

### [Gauge metric](https://develop.sentry.dev/sdk/telemetry/metrics.md#gauge-metric)

```json
{
  "name": "db.connection_pool.active",
  "value": 42,
  "unit": "connection",
  "type": "gauge",
  "attributes": {
    "pool_name": { "value": "main_db", "type": "string" },
    "max_size": { "value": 100, "type": "integer" },
    "database": { "value": "postgres", "type": "string" }
  }
}
```

### [Distribution metric](https://develop.sentry.dev/sdk/telemetry/metrics.md#distribution-metric)

```json
{
  "name": "page.load_time",
  "value": 245.7,
  "unit": "millisecond",
  "type": "distribution",
  "attributes": {
    "page": { "value": "/dashboard", "type": "string" },
    "browser": { "value": "chrome", "type": "string" }
  }
}
```

### [SDK API usage](https://develop.sentry.dev/sdk/telemetry/metrics.md#sdk-api-usage)

```javascript
// Increment a counter
Sentry.metrics.count("button.clicks", 1, {
  attributes: {
    button_id: "submit",
    page: "checkout",
  },
});

// Set a gauge value
Sentry.metrics.gauge("db.connection_pool.active", 42, {
  unit: "connection",
  attributes: {
    pool_name: "main_db",
    database: "postgres",
  },
});

// Record a distribution
Sentry.metrics.distribution("page.load_time", 245.7, {
  unit: "millisecond",
  attributes: {
    page: "/dashboard",
    browser: "chrome",
  },
});
```

### [Default attributes example](https://develop.sentry.dev/sdk/telemetry/metrics.md#default-attributes-example)

```json
{
  "attributes": {
    "sentry.environment": { "value": "production", "type": "string" },
    "sentry.release": { "value": "1.0.0", "type": "string" },
    "sentry.sdk.name": {
      "value": "sentry.javascript.browser",
      "type": "string"
    },
    "sentry.sdk.version": { "value": "10.17.0", "type": "string" },
    "sentry.replay_id": {
      "value": "36b75d9fa11f45459412a96c41bdf691",
      "type": "string"
    }
  }
}
```

### [User attributes example](https://develop.sentry.dev/sdk/telemetry/metrics.md#user-attributes-example)

```json
{
  "attributes": {
    "user.id": { "value": "123", "type": "string" },
    "user.name": { "value": "john.doe", "type": "string" },
    "user.email": { "value": "john.doe@example.com", "type": "string" }
  }
}
```

### [Full `trace_metric` envelope](https://develop.sentry.dev/sdk/telemetry/metrics.md#full-trace_metric-envelope)

```json
{ "sdk": { "name": "sentry.javascript.browser", "version": "10.17.0" } }
{
  "type": "trace_metric",
  "item_count": 5,
  "content_type": "application/vnd.sentry.items.trace-metric+json"
}
{
  "items": [
    {
      "timestamp": 1746456149.019,
      "trace_id": "624f66e93a04469f9992c7e9f1485056",
      "span_id": "b0e6f15b45c36b12",
      "name": "api.requests",
      "value": 1,
      "type": "counter",
      "attributes": {
        "endpoint": { "value": "/api/users", "type": "string" },
        "method": { "value": "POST", "type": "string" },
        "status_code": { "value": 201, "type": "integer" },
        "sentry.sdk.name": { "value": "sentry.javascript.browser", "type": "string" },
        "sentry.sdk.version": { "value": "10.17.0", "type": "string" },
        "sentry.environment": { "value": "production", "type": "string" },
        "sentry.release": { "value": "1.0.0", "type": "string" },
        "sentry.timestamp.sequence": { "value": 0, "type": "integer" }
      }
    },
    {
      "timestamp": 1746456149.019,
      "trace_id": "624f66e93a04469f9992c7e9f1485056",
      "span_id": "b0e6f15b45c36b12",
      "name": "api.response_time",
      "value": 125.5,
      "unit": "millisecond",
      "type": "distribution",
      "attributes": {
        "endpoint": { "value": "/api/users", "type": "string" },
        "method": { "value": "POST", "type": "string" },
        "sentry.sdk.name": { "value": "sentry.javascript.browser", "type": "string" },
        "sentry.sdk.version": { "value": "10.17.0", "type": "string" },
        "sentry.timestamp.sequence": { "value": 1, "type": "integer" }
      }
    },
    {
      "timestamp": 1746456149.02,
      "trace_id": "624f66e93a04469f9992c7e9f1485056",
      "span_id": "b0e6f15b45c36b12",
      "name": "cache.hit_rate",
      "value": 0.95,
      "unit": "ratio",
      "type": "gauge",
      "attributes": {
        "cache_name": { "value": "user_sessions", "type": "string" },
        "region": { "value": "us-west-1", "type": "string" },
        "sentry.sdk.name": { "value": "sentry.javascript.browser", "type": "string" },
        "sentry.sdk.version": { "value": "10.17.0", "type": "string" },
        "sentry.timestamp.sequence": { "value": 0, "type": "integer" }
      }
    },
    {
      "timestamp": 1746456149.02,
      "trace_id": "624f66e93a04469f9992c7e9f1485056",
      "span_id": "b0e6f15b45c36b12",
      "name": "database.query.duration",
      "value": 42.3,
      "unit": "millisecond",
      "type": "distribution",
      "attributes": {
        "query_type": { "value": "SELECT", "type": "string" },
        "table": { "value": "users", "type": "string" },
        "sentry.sdk.name": { "value": "sentry.javascript.browser", "type": "string" },
        "sentry.sdk.version": { "value": "10.17.0", "type": "string" },
        "sentry.origin": { "value": "auto.db.graphql", "type": "string" },
        "sentry.timestamp.sequence": { "value": 1, "type": "integer" }
      }
    },
    {
      "timestamp": 1746456149.021,
      "trace_id": "624f66e93a04469f9992c7e9f1485056",
      "span_id": "b0e6f15b45c36b12",
      "name": "active.users",
      "value": 12345,
      "type": "gauge",
      "attributes": {
        "cohort": { "value": "beta", "type": "string" },
        "sentry.sdk.name": { "value": "sentry.javascript.browser", "type": "string" },
        "sentry.sdk.version": { "value": "10.17.0", "type": "string" },
        "sentry.replay_id": { "value": "36b75d9fa11f45459412a96c41bdf691", "type": "string" },
        "sentry.timestamp.sequence": { "value": 0, "type": "integer" }
      }
    }
  ]
}
```

### [Related Resources](https://develop.sentry.dev/sdk/telemetry/metrics.md#related-resources)

* [Experimental JS SDK PR #17883 - Metrics API Implementation](https://github.com/getsentry/sentry-javascript/pull/17883/files)
* [Experimental Python SDK PR #4898 - Metrics API Implementation](https://github.com/getsentry/sentry-python/pull/4898)
* [Batch Processor Specification](https://develop.sentry.dev/sdk/foundations/processing/batch-processor.md)

***

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

| Version | Date       | Summary                                                                                                     |
| ------- | ---------- | ----------------------------------------------------------------------------------------------------------- |
| `2.8.0` | 2026-04-07 | Added \`ingest\_settings\` and \`version\` to trace\_metric envelope item                                   |
| `2.7.0` | 2026-03-10 | Auto-emitted metrics and third-party metrics bindings MUST be opt-in                                        |
| `2.6.0` | 2026-03-04 | Add sentry.timestamp.sequence attribute for deterministic metric ordering                                   |
| `2.5.0` | 2026-02-12 | Clarified sendDefaultPii gating for user attributes — allowed when user manually sets data                  |
| `2.4.1` | 2026-01-19 | Fixed example — replaced unsupported set type with gauge                                                    |
| `2.4.0` | 2026-01-14 | SDKs MUST NOT restrict unit values, SHOULD offer constants for supported units                              |
| `2.3.1` | 2026-01-09 | Fixed Swift API examples (syntax correction)                                                                |
| `2.3.0` | 2025-12-15 | Added span\_id field, added replay association (sentry.replay\_id, sentry.\_internal.replay\_is\_buffering) |
| `2.2.0` | 2025-11-19 | Tightened buffering from SHOULD to MUST, added telemetry buffer forwarding scenarios                        |
| `2.1.0` | 2025-11-17 | Added backend SDK default attributes (server.address)                                                       |
| `2.0.0` | 2025-11-13 | Breaking — new trace\_metric JSON envelope format, attribute system replacing tags                          |
| `1.0.0` | 2023-12-07 | Initial metrics spec (statsd-based format, now superseded)                                                  |
