Client
The SDK component responsible for event creation, integration management, and transport dispatch.
The Client is the SDK component responsible for building Sentry events from captured data and dispatching them to the Transport. It is configured once during Sentry.init() and manages the integration lifecycle.
The Client is stateless with respect to contextual data — it receives the Scope at capture time and merges scope data into the event. The Client does hold configuration (options) and owns its transport and integrations.
In the Hub & Scope model, the Client was bound to a Hub. In the current Scopes model, the Client is resolved via the scope chain.
Related specs:
- Configuration — client options, environment variables, debug mode, sampling
- Integrations — integration interface, lifecycle, and defaults
- Hooks — lifecycle hooks, before_send, before_breadcrumb
- Errors — error capture, exception interface, wire format
- Scopes — scope chain and client resolution
- Transport — envelope delivery
- Envelopes — wire format
- Attributes — attribute type system
Stateless: The Client does not hold contextual data (tags, breadcrumbs, user). All contextual data comes from scopes, which are passed to the Client at capture time.
Transport delegation: The Client builds the event; the Transport sends it. The Client MUST NOT implement network I/O directly — it delegates to its Transport (or TelemetryProcessor, if present).
NoOpClient: A Client that performs no operations. Present on the global scope before
Sentry.init()is called, ensuring thatgetClient()never returnsnull.Disabled SDK: The SDK is considered disabled when the Client has no transport, or when no DSN is configured. In this state, event processors,
configure_scopecallbacks, and breadcrumb recording SHOULD NOT be invoked.
Sentry.init(options) MUST create a Client, configure its transport, and set up integrations. The Client is then set on the global scope, replacing the NoOpClient.
Before Sentry.init() is called, a NoOpClient MUST be present on the global scope. (since 2.0.0)
SDKs MUST accept an empty DSN as valid configuration. If initialized with an empty or missing DSN, the SDK MUST NOT send any data over the network. Depending on the platform, the SDK MAY reduce its runtime footprint to a minimum.
Calling Sentry.init() multiple times is permitted for testing. Behavior in production beyond application startup is undefined.
The Client is considered active when it has a configured transport. When active, the Client processes captured events through the event pipeline.
| Method | Description |
|---|---|
close(timeout) | Flush the transport queue for up to timeout seconds. The Client SHOULD be disabled or disposed after close returns. |
flush(timeout) | Flush the transport queue for up to timeout seconds. The Client remains usable. |
Both methods MUST block for at most timeout seconds. If the transport includes a TelemetryProcessor, flushing MUST first forward all buffered items to the transport, then flush the transport itself.
A Client MUST always be available — getClient() MUST NOT return null.
Client resolution walks the scope chain:
- Check the current scope
- Check the isolation scope
- Check the global scope
- Fall back to NoOpClient (should not happen if
init()was called)
Users MAY bind a different Client to any scope via scope.setClient(client).
See Scopes: Client Resolution for details.
When captureEvent, captureException, or captureMessage is called, the Client processes the event through the following pipeline. The event MAY be discarded at any stage, stopping further processing.
- Disabled check: If the SDK is disabled (no transport / no DSN), discard immediately.
- Scope application and event processors: Obtain the current, isolation, and global scopes, then apply in this order:
- Merge scope data onto the event in the defined order. Scope data MUST be merged before event processors run, so processors observe the fully populated event.
- Invoke event processors — scoped first, then global, each in registration order. Any processor returning
nulldiscards the event (client report reason:event_processor). - Discard events matching
ignoreErrors(client report reason:event_processor). SDKs MAY implement this as an event processor, in which case it runs as part of the previous step.
before_sendhook: Invoke the user-configured callback. Returningnulldiscards the event (client report reason:before_send). This hook MUST only apply to error events. For transactions, usebefore_send_transaction. For logs, usebefore_send_log. See Hooks for details.- Session update: SDKs that implement Sessions MUST update the current session by incrementing its
errorscount or setting the appropriate status. SDKs without session support skip this step. - Sampling: Apply the configured
sample_rate. Events MAY be randomly discarded. When discarded, the Client MUST record a client report with discard reasonsample_rate. - Transport: Pass the event to the transport (or TelemetryProcessor). The transport MAY discard due to missing DSN, full queue, or rate limiting.
Ignored exception types, event processors, and before_send are developer-controlled filters: an event they discard MUST NOT update the session, because the developer chose to ignore it. Sampling and the transport discard events to save quota, so they MUST NOT prevent the session update — a sampled-out event still counts toward release health. This is the only reason sampling runs after before_send.
SDKs without session support MAY instead apply sampling immediately after the disabled check. With no session to update, where sampling runs does not affect release health, and sampling early skips event processors and before_send for events that will never be sent. The sample_rate client report is REQUIRED either way.
| Method | Description |
|---|---|
Client(options) / Client.from_config(options) | Construct a Client with the given options. |
| Method | Description |
|---|---|
capture_event(event, scope) | Merge event with scope data, run through event pipeline, dispatch to transport. |
capture_exception(exception, scope) | Convert exception to event, then capture. |
capture_message(message, level, scope) | Convert message to event, then capture. |
| Method | Description |
|---|---|
close(timeout) | Flush and disable. |
flush(timeout) | Flush without disabling. |
See Configuration for the full set of client options, environment variables, and sampling behavior.
| Version | Date | Summary |
|---|---|---|
3.0.0 | 2026-08-03 | Breaking — Sampling runs after before_send and the session update for SDKs that support sessions; added ignored exception types and session update steps |
2.2.0 | 2025-02-24 | Restructured into sub-specs for integrations, hooks, and configuration |
2.1.0 | 2024-09-23 | Added integration lifecycle (setupOnce, setup, afterAllSetup, preprocessEvent, processEvent) |
2.0.0 | 2024-02-14 | Breaking — Client decoupled from Hub; resolved via scope chain; NoOpClient before init |
1.1.0 | 2022-11-17 | Added session lifecycle (start_session, end_session) |
1.0.0 | 2020-05-04 | Initial spec — stateless event creator with capture_event, close, flush, transport delegation |
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").