diff --git a/develop-docs/sdk/expected-features/index.mdx b/develop-docs/sdk/expected-features/index.mdx
index 7bc4c7d49b33a..9dd51c7eee3ef 100644
--- a/develop-docs/sdk/expected-features/index.mdx
+++ b/develop-docs/sdk/expected-features/index.mdx
@@ -211,14 +211,11 @@ Write events to disk before attempting to send, so that they can be retried in t
When SDKs receive an `HTTP 2xx` status code response from Sentry, they **MUST** consider it as a successful send.
-If Sentry returns an `HTTP 4xx` or `HTTP 5xx` status code, SDKs:
-
-- **MUST** discard the envelope
-- **MUST** record a [client report](/sdk/telemetry/client-reports) with the discard reason `send_error`, except for an `HTTP 429` response, see below.
+If Sentry returns an `HTTP 4xx` or `HTTP 5xx` status code, SDKs **MUST** discard the envelope and record a [client report](/sdk/telemetry/client-reports/#network-failure-recording) as specified in the client reports spec.
For an [`HTTP 413 Content Too Large`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/413) response, SDKs:
-* **MUST** discard the envelope and record a [client report](/sdk/telemetry/client-reports) with the discard reason `send_error`. Upstream usually records a [client report](/sdk/telemetry/client-reports) for oversized envelopes, but not always. Double-counting is preferable to not counting, so users are aware of all dropped envelopes. Since client reports are not expected to be fully accurate, we accept this tradeoff for now (Jan 7th 2026). In the future, we may add error responses to indicate when SDKs should record a client report.
+* **MUST** discard the envelope and record a [client report](/sdk/telemetry/client-reports/#network-failure-recording).
* **MUST NOT** retry sending the envelope.
* **SHOULD** log an error, informing users that the envelope was discarded due to size limits.
* **MAY** add information from the response body to the logged error. If doing so, SDKs **MUST** be aware that Relay can change or remove information in the response body for an `HTTP 413` at any time without notice.
@@ -226,7 +223,7 @@ For an [`HTTP 413 Content Too Large`](https://developer.mozilla.org/en-US/docs/W
For an [`HTTP 429 Too Many Requests`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429) response, SDKs:
- **MUST** respect the [rate limiting rules](/sdk/expected-features/rate-limiting/), such as correctly parsing the retry-header.
-- **MUST** discard the envelope, but **MUST NOT** record a [client report](/sdk/telemetry/client-reports), because the upstream already does this. Doing this would double-count client reports for discarded envelopes.
+- **MUST** discard the envelope, but **MUST NOT** record a [client report](/sdk/telemetry/client-reports/#network-failure-recording), because the upstream already does this.
- **MUST NOT** retry sending the envelope.
SDKs **MAY** retry sending the envelope when a network error occurs, such as:
@@ -235,7 +232,9 @@ SDKs **MAY** retry sending the envelope when a network error occurs, such as:
* DSN resolution failure
* Connection reset by peer
-When other failures occur, like those caused by processing the file in the SDK itself, SDKs **MUST** discard the envelope and record a [client report](/sdk/telemetry/client-reports) with the discard reason `internal_sdk_error`. Otherwise, the SDK might end up in an endless retry loop.
+When other failures occur, like those caused by processing the file in the SDK itself, SDKs **MUST** discard the envelope and record a [client report](/sdk/telemetry/client-reports/#network-failure-recording) with the discard reason `internal_sdk_error`. Otherwise, the SDK might end up in an endless retry loop.
+
+See the [Client Reports — Network Failure Recording](/sdk/telemetry/client-reports/#network-failure-recording) spec for the full set of client report recording requirements for each HTTP status code.
#### Additional capabilities
diff --git a/develop-docs/sdk/foundations/transport/envelope-items.mdx b/develop-docs/sdk/foundations/transport/envelope-items.mdx
index 3a74d75ac1371..21a672e01b505 100644
--- a/develop-docs/sdk/foundations/transport/envelope-items.mdx
+++ b/develop-docs/sdk/foundations/transport/envelope-items.mdx
@@ -203,26 +203,6 @@ details.
_None_
-### Client Report
-
-Item type `"client_report"` contains a client report payload encoded in JSON.
-
-See the client reports documentation for the payload
-details.
-
-**Constraints:**
-
-- This Item may occur multiple times per Envelope, but please avoid sending more client reports than necessary.
-- This Item can either be included in an Envelope with other Items, or it may be sent by itself.
-
-**Envelope Headers:**
-
-_None_
-
-**Additional Item Headers:**
-
-_None_
-
### Replay Event
Item type `"replay_event"` contains a replay payload encoded in JSON.
diff --git a/develop-docs/sdk/telemetry/client-reports.mdx b/develop-docs/sdk/telemetry/client-reports.mdx
index 45b3e7d745f27..a471f4016733e 100644
--- a/develop-docs/sdk/telemetry/client-reports.mdx
+++ b/develop-docs/sdk/telemetry/client-reports.mdx
@@ -1,46 +1,341 @@
---
title: Client Reports
+spec_id: sdk/telemetry/client-reports
+spec_version: 1.19.0
+spec_status: stable
+spec_depends_on:
+ - id: sdk/foundations/transport/envelopes
+ version: ">=1.0.0"
+spec_changelog:
+ - version: 1.19.0
+ date: 2026-02-06
+ summary: Added network failure recording rules (send_error for 4xx/5xx, no report for 429)
+ - version: 1.18.0
+ date: 2026-01-29
+ summary: Added telemetry processor integration, updated SDK recommendations
+ - version: 1.17.0
+ date: 2026-01-21
+ summary: Added `invalid` discard reason
+ - version: 1.16.0
+ date: 2026-01-14
+ summary: Added `ignored` discard reason
+ - version: 1.15.0
+ date: 2025-01-21
+ summary: Added `buffer_overflow` discard reason
+ - version: 1.14.0
+ date: 2024-09-10
+ summary: Added span outcome tracking (span category for dropped transactions)
+ - version: 1.13.0
+ date: 2023-12-12
+ summary: Added `backpressure` discard reason
+ - version: 1.12.0
+ date: 2023-06-26
+ summary: Added `insufficient_data` discard reason
+ - version: 1.11.0
+ date: 2023-02-09
+ summary: Added `send_error` and `internal_sdk_error` discard reasons
+ - version: 1.10.0
+ date: 2022-06-23
+ summary: Added product context (Scope and Intent)
+ - version: 1.9.0
+ date: 2022-05-06
+ summary: Client reports never rate limited by server
+ - version: 1.8.0
+ date: 2022-04-11
+ summary: Added HTTP status code handling guidance
+ - version: 1.7.0
+ date: 2022-04-06
+ summary: SDK bugs out of scope for client reports
+ - version: 1.6.0
+ date: 2022-04-04
+ summary: event_processor discard for ignored exceptions
+ - version: 1.5.0
+ date: 2022-04-04
+ summary: Added `send_client_reports` configuration option
+ - version: 1.4.0
+ date: 2022-03-28
+ summary: SDK recommendations, legacy events, custom transports sections
+ - version: 1.3.0
+ date: 2022-03-28
+ summary: No double counting — MUST NOT record for HTTP 429
+ - version: 1.2.0
+ date: 2022-03-22
+ summary: Specified data categories for discard reasons
+ - version: 1.1.0
+ date: 2021-12-24
+ summary: Relay outcome types (rate_limited_events, filtered_events, filtered_sampling_events)
+ - version: 1.0.1
+ date: 2021-09-10
+ summary: Fixed field name from discard_reason to reason
+ - version: 1.0.0
+ date: 2021-09-10
+ summary: Initial spec — client report protocol, envelope format, discard reasons
---
-## Scope and Intent
+
-Client reports (not to be confused with [User Feedback](https://docs.sentry.io/product/user-feedback/))
-are a protocol feature that let clients send status reports
-about themselves to Sentry. They are currently mainly used to emit outcomes
-for events that were never sent. Chained relays are also able to emit these
-client reports to inform the next relay in chain about _some_ outcomes.
+
-Due to a bug in Relay, which discards envelopes containing unknown envelope
-items, the minimum required version of Sentry for client reports is
-[21.9.0](https://github.com/getsentry/relay/blob/master/CHANGELOG.md#2190).
+## Overview
-Before client reports were added there were no insights into the full number of events generated within applications instrumented with Sentry SDKs. It was always clear to track the number of events dropped on Sentry server side for any number of reason, but there was a gap in knowing just how many events were never sent from the SDKs at all. Are there patterns in different platforms? Are there problems we are not aware of? If a customer were to call Sentry and ask where there events are, we would have no answer, and no way to find out if there are truly missing events from their SDKs. Client reports removes some of this doubt. That being said we are not looking to perfectly measure every nuance and edge case of events being discarded in SDKs. It is more important to have a best effort and be able to gain insights to our SDKs and their host applications.
+Client reports are a protocol feature that let SDKs send status reports about themselves to Sentry. They are primarily used to emit outcomes for events that were never sent — providing visibility into what is happening on the SDK side that affects the user experience.
-As seen here, we communicate _Accepted_, _filtered_ and _dropped_, and now we can send a new type _discarded_ (not displayed in product yet).
-
+Not to be confused with [User Feedback](https://docs.sentry.io/product/user-feedback/).
-## Basic Operation
+Due to a bug in Relay which discards envelopes containing unknown envelope items, the minimum required Sentry version for client reports is [21.9.0](https://github.com/getsentry/relay/blob/master/CHANGELOG.md#2190).
-Client reports are sent as envelope items to Sentry, typically as separate
-envelopes or with one of the already scheduled envelopes. They should not
-be sent too frequently but not too infrequently either. Their main purpose
-is to bring visibility into what is happening on the SDK side which affects
-the user experience.
+Related specs:
+- [Envelopes](/sdk/foundations/transport/envelopes/) — transport format
+- [Envelope Items](/sdk/foundations/transport/envelope-items/) — envelope item types
+- [Telemetry Processor](/sdk/foundations/processing/telemetry-processor/) — SDK processing architecture
+- [Rate Limiting](/sdk/expected-features/rate-limiting/) — data category definitions
-For instance SDKs might drop events in a few places in the SDK and this loss
-of events can be invisible to a customer. Client reports let an SDK emit
-such event outcomes to provide data about how often this is happening. For
-instance SDKs might drop events if the transports hit their maximum internal
-queue size, because rate limits instruct the SDK to drop events as they are
-over quota etc.
+---
+
+## Concepts
+
+### Outcomes
+
+An **outcome** describes the fate of a telemetry item — whether it was accepted, filtered, rate-limited, or discarded. Client reports cover the **discarded** category: items that were never sent to Sentry.
+
+### Discard Reasons
+
+A **discard reason** is a string that explains why a telemetry item was dropped. Each discarded item is categorized by reason and [data category](/sdk/expected-features/rate-limiting/#definitions).
+
+### Data Categories
+
+Data categories (e.g., `error`, `transaction`, `span`) identify the type of telemetry item that was discarded. These are the same categories used for [rate limits](/sdk/expected-features/rate-limiting/#definitions).
+
+---
+
+## Behavior
+
+
+
+### Core Operation
+
+Client reports are sent as envelope items to Sentry, typically as separate envelopes or with one of the already scheduled envelopes. Their main purpose is to bring visibility into what is happening on the SDK side.
+
+SDKs might drop events in several places — transport queue overflow, rate limit backoff, sampling, `before_send`, event processors — and this loss can be invisible to a customer. Client reports let an SDK emit such event outcomes to provide data about how often this is happening.
+
+The party that drops an envelope item **MUST** record and report it.
+
+SDKs can assume client reports are never rate limited (since 1.9.0). The server minimizes the possibility of client reports getting rate limited, but the SDKs shouldn't worry about this edge case as this feature is best-effort.
+
+Bugs in SDKs are out of scope for client reports and are not tracked using client reports (since 1.7.0).
+
+Client reports do not expect 100 percent correct numbers, and it is acceptable for SDKs to lose a small number of client reports. The expectation is to give users an approximation of specific outcomes.
+
+
+
+### Network Failure Recording
+
+
+
+#### Successful Sends (HTTP 2xx)
+
+When SDKs receive an `HTTP 2xx` status code response from Sentry, they **MUST** consider it a successful send. No client report is recorded.
+
+
+
+
+
+#### Error Responses (HTTP 4xx/5xx)
+
+If Sentry returns an `HTTP 4xx` or `HTTP 5xx` status code, SDKs:
+
+- **MUST** discard the envelope.
+- **MUST** record a client report with the discard reason `send_error`. For `HTTP 429` and `HTTP 413`, follow the dedicated sections [below](#network-429) instead, as they have additional requirements.
+
+
+
+
+
+#### Content Too Large (HTTP 413)
+
+For an [`HTTP 413 Content Too Large`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/413) response, SDKs:
+
+- **MUST** discard the envelope and record a client report with the discard reason `send_error`. Upstream usually records a client report for oversized envelopes, but not always. Double-counting is preferable to not counting, so users are aware of all dropped envelopes. Since client reports are not expected to be fully accurate, we accept this tradeoff for now.
+- **MUST NOT** retry sending the envelope.
+- **SHOULD** log an error, informing users that the envelope was discarded due to size limits.
+- **MAY** add information from the response body to the logged error. If doing so, SDKs **MUST** be aware that Relay can change or remove information in the response body for an `HTTP 413` at any time without notice.
+
+
+
+
+
+#### Rate Limited (HTTP 429)
+
+For an [`HTTP 429 Too Many Requests`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429) response, SDKs:
-Bugs in our SDKs are out of scope for client reports and are not being tracked
-using client reports at the moment.
+- **MUST** respect the [rate limiting rules](/sdk/expected-features/rate-limiting/), such as correctly parsing the retry-header.
+- **MUST** discard the envelope, but **MUST NOT** record a client report, because the upstream already does this. Doing this would double-count client reports for discarded envelopes.
+- **MUST NOT** retry sending the envelope.
-## Envelope Item Payload
+
-A client report is an item in an envelope called `client_report`. It consists
-of a JSON payload that looks roughly like this:
+
+
+#### Processing Failures
+
+When failures occur that are caused by processing in the SDK itself, SDKs **MUST** discard the envelope and record a client report with the discard reason `internal_sdk_error`.
+
+
+
+
+
+#### Transport Errors
+
+SDKs **MAY** retry sending the envelope when a network error occurs (connection timeout, DNS resolution failure, connection reset by peer). No client report is required for retried network errors.
+
+
+
+
+
+### Span Outcomes
+
+When a transaction is dropped, SDKs **MUST** record an additional `span` category entry containing the number of spans inside the transaction plus one. The plus one stems from the fact that Relay extracts an additional span from the transaction. If a transaction contains no spans, SDKs still report one dropped transaction and one dropped span. This also applies to transactions that are not sampled.
+
+If certain spans are dropped in `beforeSendTransaction`, an event processor, etc., SDKs also report those.
+
+
+
+
+
+### Telemetry Processor Integration
+
+SDKs **MAY** keep track of discarded events in the transport. Once SDKs implement the [telemetry processor](/sdk/foundations/processing/telemetry-processor/), they **SHOULD** implement client reports tracking outside the transport, since data can be dropped in multiple places throughout the SDK.
+
+The [telemetry scheduler](/sdk/foundations/processing/telemetry-processor/#telemetry-scheduler) is then responsible for passing aggregated client reports to the transport. The telemetry scheduler still **MUST** adhere to all requirements in this spec.
+
+See the [telemetry processor spec](/sdk/foundations/processing/telemetry-processor/) for the full architecture and recording points.
+
+
+
+
+
+### SDK Recommendations
+
+It is not required, for example:
+
+- to persist the data when an application crashes.
+- to move an envelope item with a client report to the next envelope when the cache for envelopes is full.
+
+SDKs **SHOULD** minimize unnecessary HTTP requests and **MUST NOT** send an envelope for each discarded event. Adjust these recommendations as needed:
+
+1. For low-frequency apps (mobile/web): Attach discarded events to scheduled envelopes. Fewer client reports are acceptable in such cases.
+2. For high-frequency apps (backends): Periodically flush discarded events or attach to scheduled envelopes.
+
+
+
+
+
+### Configuration
+
+SDKs **SHOULD** provide a way to turn sending of client reports on and off. This option is called `send_client_reports` or `sendClientReports`.
+
+
+
+
+
+### Legacy Events
+
+For SDKs still sending legacy events instead of envelopes for backward compatibility with older Sentry servers, the recommendation is to send the client report as a separate envelope or attach it to pending session envelopes.
+
+
+
+
+
+### Custom Transports
+
+There is no expectation that such bookkeeping can work transparently for custom transports. Consequently, it's acceptable if client reports are optional for custom transports.
+
+
+
+---
+
+## Wire Format
+
+### Envelope Item
+
+
+
+Item type `"client_report"` contains a client report payload encoded in JSON.
+
+**Constraints:**
+
+- This Item **MAY** occur multiple times per Envelope, but SDKs **SHOULD** avoid sending more client reports than necessary.
+- This Item can either be included in an Envelope with other Items, or it **MAY** be sent by itself.
+- No envelope headers are required.
+- Size limit: 4 KiB (see [Envelopes — Size Limits](/sdk/foundations/transport/envelopes/)).
+
+
+
+### Payload Structure
+
+
+
+A client report consists of a JSON payload with the following fields:
+
+| Field | Type | Required | Since | Description |
+|-------|------|----------|-------|-------------|
+| `timestamp` | String or Number | **OPTIONAL** | 1.0.0 | The timestamp of when the client report was created. Must be an ISO DateTime string or a UNIX timestamp. If not sent, the server assumes the current UTC timestamp. In the data model, this is called `received`. |
+| `discarded_events` | Array | **REQUIRED** | 1.0.0 | List of outcome objects \{`reason`, `category`, `quantity`\}. |
+
+Each outcome object in `discarded_events` has:
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `reason` | String | **REQUIRED** | A discard reason that defines why events were lost (see [Discard Reasons](#discard-reasons)). |
+| `category` | String | **REQUIRED** | The [data category](/sdk/expected-features/rate-limiting/#definitions) for which the discard reason applies (since 1.2.0). |
+| `quantity` | Number | **REQUIRED** | The number of events which were lost. |
+
+
+
+### Discard Reasons
+
+
+
+The following discard reasons are defined for `discarded_events`:
+
+| Reason | Since | Description |
+|--------|-------|-------------|
+| `queue_overflow` | 1.0.0 | SDK internal queue (e.g., transport queue) overflowed. |
+| `cache_overflow` | 1.0.0 | SDK internal cache (e.g., offline event cache) overflowed. |
+| `ratelimit_backoff` | 1.0.0 | Rate limit instructed the SDK to back off. |
+| `network_error` | 1.0.0 | Network errors, not retried. |
+| `sample_rate` | 1.0.0 | Configured sample rate. |
+| `before_send` | 1.0.0 | Dropped in `before_send`. |
+| `event_processor` | 1.0.0 | Dropped by event processor; may also be used for ignored exceptions/errors (since 1.6.0). |
+| `send_error` | 1.11.0 | Error when sending (e.g., 400 response). |
+| `internal_sdk_error` | 1.11.0 | Internal SDK error (e.g., web worker crash). |
+| `insufficient_data` | 1.12.0 | Lack of data in the event (e.g., not enough samples in a profile). |
+| `backpressure` | 1.13.0 | Downsampling due to system load. |
+| `buffer_overflow` | 1.15.0 | SDK internal buffer (e.g., breadcrumbs buffer) overflowed. |
+| `ignored` | 1.16.0 | Telemetry item was ignored by the SDK (e.g., a span was ignored by `ignore_spans`; can also be used by other deny-list mechanisms). |
+| `invalid` | 1.17.0 | Failed validation (e.g., replay session exceeded maximum allowed length). |
+
+In case a reason needs to be added, it also has to be added to the allowlist in [snuba](https://github.com/getsentry/snuba/blob/master/rust_snuba/src/processors/outcomes.rs#L15).
+
+
+
+### Relay Outcome Types
+
+
+
+The following outcome types are reserved for relay use:
+
+`rate_limited_events`, `filtered_events`, `filtered_sampling_events`
+
+These function like `discarded_events` (same `{reason, category, quantity}` structure) but identify events that were rate limited, filtered, or filtered by dynamic sampling _at a relay_. Client SDKs **MUST NOT** emit these _unless_ they are operating as a relay. The reason codes for these need to match the reason codes that relay would emit directly to Sentry.
+
+
+
+---
+
+## Examples
+
+### Wire Format
```json
{
@@ -60,67 +355,17 @@ of a JSON payload that looks roughly like this:
}
```
-Note that this must be enclosed in an envelope. So the full event looks
-something like this:
+### Full Envelope
```json
{}
{"type":"client_report"}
-{"timestamp":"..."}
+{"timestamp":"2020-02-07T14:16:00Z","discarded_events":[{"reason":"queue_overflow","category":"error","quantity":23}]}
```
-The following fields exist:
-
-`timestamp`
-
-: _String | Number, optional_. The timestamp of when the client report was created. Must be an ISO DateTime string or a UNIX timestamp. If not sent, the server will assume the current UTC timestamp. In the data model, this is called `received`.
-
-`discarded_events`
-
-: _List of outcome objects_ \{`reason`, `category`, `quantity`\}
-
-- `reason`: A string reason that defines why events were lost.
-- `category`: The data category for which the discard reason applies. These are the same data categories used for [rate limits](/sdk/expected-features/rate-limiting/#definitions).
-- `quantity`: The number of events which were lost
-
-The following discard reasons are currently defined for `discarded_events`:
+### Span Outcome Example
-- `queue_overflow`: a SDK internal queue (eg: transport queue) overflowed
-- `cache_overflow`: an SDK internal cache (eg: offline event cache) overflowed
-- `buffer_overflow`: an SDK internal buffer (eg. breadcrumbs buffer) overflowed
-- `ratelimit_backoff`: the SDK dropped events because an earlier rate limit
- instructed the SDK to back off.
-- `network_error`: events were dropped because of network errors and were not retried.
-- `sample_rate`: an event was dropped because of the configured sample rate.
-- `before_send`: an event was dropped in `before_send`
-- `event_processor`: an event was dropped by an event processor; may also be used for ignored exceptions / errors
-- `send_error`: an event was dropped because of an error when sending it (eg: 400 response)
-- `internal_sdk_error`: an event was dropped due to an internal SDK error (eg: web worker crash)
-- `insufficient_data`: an event was dropped due to a lack of data in the event (eg: not enough samples in a profile)
-- `backpressure`: an event was dropped due to downsampling caused by the system being under load
-- `ignored`: a telemetry item was ignored by the SDK (eg: a span was ignored by `ignore_spans`, can also be used by other deny-list mechanisms)
-- `invalid`: an event was dropped because it failed validation (eg: a replay session exceeded the maximum allowed length)
-
-In case a reason needs to be added,
-it also has to be added to the allowlist in [snuba](https://github.com/getsentry/snuba/blob/master/rust_snuba/src/processors/outcomes.rs#L15).
-
-Additionally the following discard reasons are reserved but there is no expectation
-that SDKs send these under normal operation:
-
-`rate_limited_events`, `filtered_events`, `filtered_sampling_events`
-
-: _List of outcome objects_ \{`reason`, `category`, `quantity`\}
-
-These function like `discarded_events` but identify events that were rate limited,
-filtered or filtered by dynamic sampling _at a relay_. Client SDKs must never
-emit these _unless_ they are operating as a relay. The reason codes for these
-need to match the reason codes that relay would emit directly to Sentry.
-
-### Special Case for Span Outcomes
-
-When a transaction is dropped, we record an additional `span` category event containing the number of the spans inside the transaction plus one.
-The plus one stems from the fact that Relay extracts an additional span from the transaction. If a transaction contains no spans, we still want to report one dropped transaction and one dropped span. This also applies to transactions that are not sampled.
-If certain spans are dropped in `beforeSendTransaction`, an event processor etc., we also want to report those.
+When a transaction with 2 spans is dropped due to queue overflow:
```json
{
@@ -133,44 +378,16 @@ If certain spans are dropped in `beforeSendTransaction`, an event processor etc.
{
"reason": "queue_overflow",
"category": "span",
- "quantity": 3 // 2 spans + 1 span (the transaction itself should be counted)
+ "quantity": 3
}
]
}
```
-## SDK Side Recommendations
-
-The client reports feature doesn't expect 100 percent correct numbers, and it is
-acceptable for the SDKs to lose a small number of client reports. The expectation of
-this feature is to give the users an approximation of specific outcomes. Of course,
-the SDKs should ensure not dropping too many reports. It is not required, for example:
+The span quantity is 3 (2 spans + 1 for the transaction itself, since Relay extracts an additional span from the transaction).
-- to persist the data when an application crashes.
-- to move an envelope item with a client report to the next envelope when the cache for envelopes is full.
-
-SDKs **SHOULD** minimize unnecessary HTTP requests and **MUST NOT** send an envelope for each discarded event. Adjust these recommendations as needed:
-
-1. For low-frequency apps (mobile/web): Attach discarded events to scheduled envelopes. Fewer client reports are acceptable in such cases.
-2. For high-frequency apps (backends): Periodically flush discarded events or attach to scheduled envelopes.
-
-SDKs **MAY** keep track of discarded events in the transport. Once SDKs implement the [telemetry processor](/sdk/foundations/processing/telemetry-processor/), they **SHOULD** implement client reports tracking outside the transport, since data can be dropped in multiple places throughout the SDK. The [telemetry scheduler](/sdk/foundations/processing/telemetry-processor/#telemetry-scheduler) is then responsible for passing aggregated client reports to the transport. The telemetry scheduler still **MUST** adhere to the requirements above.
-
-The party that drops an envelope item **MUST** record and report it. SDKs can assume client reports are never rate limited. The server is minimizing the possibility of client reports getting rate limited, but the SDKs shouldn't worry about this edge case as this feature is best-effort.
-
-For details on which HTTP status codes require a client report and which discard reasons to use, see [Dealing with Network Failures](/sdk/expected-features/#dealing-with-network-failures).
-
-### Configuration
-
-SDKs should provide a way to turn sending of client reports on and off. This option is called `send_client_reports` or `sendClientReports` on SDKs that have already implemented it.
-
-### Legacy Events
-
-For SDKs still sending legacy events instead of envelopes for backward compatibility with
-older Sentry servers, the recommendation is to send the client report as a separate
-envelope or attach it to pending session envelopes.
+---
-### Custom Transports
+## Changelog
-There is no expectation that such bookkeeping can work transparently for custom transports.
-Consequently, it's acceptable if client reports are optional for custom transports.
+