---
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[](https://develop.sentry.dev/sdk/getting-started/standards/spec-lifecycle.md "Learn about spec statuses")

Version`2.9.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)

Multiple metrics can share the same timestamp in certain cases. This happens when the runtime freezes timer APIs during synchronous execution (notably Cloudflare Workers freeze `Date.now()` and `performance.now()`), or when the caller supplies the same [user-provided timestamp](https://develop.sentry.dev/sdk/telemetry/metrics.md#metrics-module) for a batch of metrics. SDKs **MUST** attach a `sentry.timestamp.sequence` integer attribute to every metric to allow deterministic ordering within a single SDK instance.

Candidatespecified since 2.6.0

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

* Be a 64-bit signed integer (`Int64`).
* Start at `0` when the SDK initializes.
* Increment by `1` for each metric that is captured.
* Never reset during the SDK's lifetime. The counter **MUST** increment continuously across all metrics regardless of their timestamps.
* Reset to `0` only when the SDK is re-initialized, or when the counter reaches the maximum `Int64` value (`2^63 - 1`). Overflow to `0` is acceptable because the probability of reaching this limit within a single SDK lifetime is negligible.

The sequence provides deterministic ordering within a single SDK instance. It does not guarantee ordering across independent processes or workers, which have separate counters.

### [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_user_agent": "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 **SHOULD** include `version` and `ingest_settings` properties to instruct Relay to infer IP address and user agent from the incoming request. See the [Ingest Settings](https://develop.sentry.dev/sdk/foundations/transport/envelope-items.md#ingest-settings) spec for the full definition, field reference, and behavior.

### [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 or String | **REQUIRED** | 2.0.0 | Timestamp indicating when the metric was recorded. Relay accepts a numeric Unix timestamp in seconds (epoch time) or an RFC 3339 string.                                                                                             |
| `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.
  * `timestamp` **Timestamp, optional** — indicates when the metric was recorded (since 2.9.0). SDKs **SHOULD** accept the language's native date/time type (e.g. `Date` in JavaScript/Swift, `datetime` in Python, `Instant` in Java, `DateTimeInterface` in PHP). When provided, the SDK **MUST** convert the value and use it as the `timestamp` field in the [metric payload](https://develop.sentry.dev/sdk/telemetry/metrics.md#metric-payload). Relay accepts both a numeric Unix timestamp in seconds (epoch time) and an RFC 3339 string, so SDKs **MAY** use either format. When not provided, the SDK **MUST** default to the current time at the moment the metric is captured. If no native date/time type exists, SDKs **MUST** accept a numeric Unix timestamp in seconds (epoch time) as a fallback instead.

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 with an explicit timestamp
const recordedAt = new Date("2024-05-18T16:00:00Z");
Sentry.metrics.distribution("page.load_time", 245.7, {
  unit: "millisecond",
  timestamp: recordedAt,
  attributes: {
    page: "/dashboard",
    browser: "chrome",
  },
});
```

*Other available variations of the above snippet: python, php, java, swift*

### [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": 2, "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": 3, "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": 4, "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.9.0` | 2026-05-18 | Added optional \`timestamp\` parameter to metrics public API. Changed \`sentry.timestamp.sequence\` to a continuously incrementing Int64 that never resets on timestamp change. |
| `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)                                                                                                                      |
