---
title: Session sampling
description: Exclude instrumentations from session sampling
url: https://coralogix.com/docs/user-guides/rum/sdk-installation/flutter/mobile/configuration/session-sampling/
product: ingress
feature: RUM Ingress
feature_id: rum.ingress
feature_identifier: ingress/rum.ingress
last_updated: '2026-11-02'
---

# Session sampling

### Exclude instrumentations from session sampling

`sdkSampler` sets the percentage of sessions (0-100) whose events are reported. A sampled-out session still starts the SDK and keeps sending the `traceparent` header, so its requests still correlate with your backend traces, but its events are not reported. Use `excludeFromSampling` to keep specific instrumentation categories reporting on a sampled-out session. This is useful when you ship `sdkSampler: 0` (or a low rate) for cost control but still want every error and log.

```
import 'package:cx_flutter_plugin/cx_excludable_instrumentation.dart';



var options = CXExporterOptions(

  // ...other options...

  sdkSampler: 0,

  excludeFromSampling: const [

    CXExcludableInstrumentation.errors,

    CXExcludableInstrumentation.logs,

  ],

);
```

Supported categories: `errors`, `logs`, `network`, `userInteractions`, `mobileVitals`, `customSpan`, `customMeasurement`, `navigation` and `lifecycle` (the last two from 0.20.0). The same values are accepted on iOS and Android. Defaults to an empty list, so a sampled-out session reports nothing at all, not even the SDK's own initialization events (from 0.19.1). List at least one category and the session reports that category together with those internal events.

`instrumentations` always wins over `excludeFromSampling`. Listing a category does not turn back on an instrumentation you set to `false`, and the list has no effect on a session that is sampled in.

#### Telling excluded events apart in `beforeSend`

Every event carries `isSessionSampledIn` (read-only). `false` means the event reached export only because its category is listed in `excludeFromSampling` — the session itself was sampled out. Use it in `beforeSend` to apply your own filtering on top of the exclude list, e.g. keep only errors from sampled-out sessions:

```
var options = CXExporterOptions(

  // ...other options...

  sdkSampler: 5,

  excludeFromSampling: const [

    CXExcludableInstrumentation.errors,

    CXExcludableInstrumentation.logs,

  ],

  beforeSend: (event) {

    // Session sampled out: forward only error-severity events, drop the rest.

    if (!event.isSessionSampledIn &&

        event.eventContext?.severity != CxLogSeverity.error) {

      return null;

    }

    return event;

  },

);
```

`event.isSessionSampledIn` is a convenience accessor over `event.sessionContext?.isSessionSampledIn`, and defaults to `true` when the event carries no session context. The flag is also mirrored on `instrumentation_data.otelSpan.attributes` as `cx_rum.session_context.isSessionSampledIn`.

Session identity is read-only in `beforeSend`: `isSessionSampledIn`, `session_id` and `session_creation_date` are restored from the SDK's own values after your callback returns, and clearing `sessionContext` entirely restores it whole. Writing to them has no effect. The user identity fields (`user_id`, `user_name`, `user_email`, `user_metadata`) remain editable, so redacting user data in `beforeSend` works as before.

> **Crash events do not reach `beforeSend`.** On both iOS and Android, crash events are uploaded directly by the native SDK rather than taking the round trip to Dart and back, so a dying process is not racing the extra hop. A `beforeSend` callback therefore never sees them: filtering, redaction, or label edits you apply there do **not** apply to crashes. If you need to keep data out of crash payloads, keep it out of the values you pass to the SDK (`setLabels`, `setUserContext`, `reportError` data) rather than relying on `beforeSend`.

Requires the native SDKs bundled with plugin ≥ 0.11.0 (iOS 2.13.1 / Android 2.19.1). Against older natives the flag is absent and reads as `true`.
