---
title: "Filtering"
description: "Learn more about how to configure your SDK to filter events reported to Sentry."
url: https://docs.sentry.io/platforms/native/guides/crashpad/configuration/filtering/
---

# Filtering | Sentry for Google Crashpad

When you add Sentry to your app, you get a lot of valuable information about errors and performance. And lots of information is good -- as long as it's the right information, at a reasonable volume.

The Sentry SDKs have several configuration options to help you filter out events.

We also offer [Inbound Filters](https://docs.sentry.io/concepts/data-management/filtering.md) to filter events in sentry.io. We recommend filtering at the client level though, because it removes the overhead of sending events you don't actually want. Learn more about the [fields available in an event](https://develop.sentry.dev/sdk/foundations/transport/event-payloads/).

## [Filtering Error Events](https://docs.sentry.io/platforms/native/guides/crashpad/configuration/filtering.md#filtering-error-events)

Configure your SDK to filter error events by using the `before_send` callback method and configuring, enabling, or disabling integrations.

### [Using `before_send`](https://docs.sentry.io/platforms/native/guides/crashpad/configuration/filtering.md#using-before-send)

All Sentry SDKs support the `before_send` callback method. Because it's called immediately before the event is sent to the server, this is your last chance to decide not to send data or to edit it. `before_send` receives the event object as a parameter, which you can use to either modify the event’s data or drop it completely by returning `null`, based on custom logic and the data available on the event.

```c
#include <sentry.h>

sentry_value_t strip_sensitive_data(sentry_value_t event, void *hint, void *user_data) {
    (void)hint; // unlike in other SDKs, `hint` currently contains no data.
    // to get more crash context into a callback, use the `on_crash` hook instead.

    if (strcmp(sentry_value_as_string(sentry_value_get_by_key(event, "level")), "info") == 0) {
        // remove the user data from "info" level events
        sentry_value_remove_by_key(event, "user");
        // make our mark on the event
        sentry_value_t tags = sentry_value_get_by_key(event, "tags");
        if (!sentry_value_is_null(tags)) {
            sentry_value_set_by_key(tags, "info", sentry_value_new_string((char*) user_data));
        }
    }

    // return the modified event, or discard it by freeing it and returning `null`
    //       sentry_value_decref(event);
    //       return sentry_value_new_null();
    return event;
}

int main(void) {
  sentry_options_t *options = sentry_options_new();
  sentry_options_set_before_send(options, strip_sensitive_data, "anonymized");
  sentry_init(options);

  /* ... */
}
```

The callback is executed in the same thread as the call to `sentry_capture_event`. Work performed by the function may thus block the executing thread. For this reason, consider avoiding heavy work in `before_send`.

#### [Using `on_crash`](https://docs.sentry.io/platforms/native/guides/crashpad/configuration/filtering.md#using-on_crash)

The `before_send` callback implementation in `sentry-native` makes it hard to distinguish between normal events and crashes. For this reason, we introduced another callback, `on_crash`, which - at this point - only exists in `sentry_native`:

```c
#include <sentry.h>

static sentry_value_t
on_crash_callback(
    const sentry_ucontext_t *uctx, // provides the user-space context of the crash
    sentry_value_t event,          // used the same way as in `before_send`; mostly empty for minidump-generating backends (crashpad, breakpad)
    void *user_data                // user-data that you can provide at configuration time
)
{
    // Enrich an event before the crash is sent to sentry's backend infrastructure
    sentry_value_t tags = sentry_value_get_by_key(event, "tags");
    if (!sentry_value_is_null(tags)) {
        sentry_value_set_by_key(tags, "crash_hook", sentry_value_new_string("invoked"));
    }
    /* ... */

    // tell the backend to retain the event (+ dump)
    // or to discard it, you could free the event and return a `null`:
    //       sentry_value_decref(event);
    //       return sentry_value_new_null();
    return event;
}

int main(void) {
  sentry_options_t *options = sentry_options_new();
  sentry_options_set_on_crash(options, on_crash_callback, NULL);
  sentry_init(options);

  /* ... */
}
```

The `on_crash` callback replaces `before_send` as a callback for crash events only. They can be defined simultaneously, where the SDK prevents `before_send` from being invoked for crash events. This allows for better differentiation between crashes and other events and gradual migration from existing `before_send` implementations:

* If you have a `before_send` implementation and do not define an `on_crash` callback `before_send` will receive both normal and crash events as before
* If you only want to pre-process normal events with `before_send`, then you can define an "empty" `on_crash` callback that returns the passed-in event and does nothing else.
* If you are not interested in pre-processing normal events but only want to act on crashes, then only define an `on_crash` callback with the option to filter (available for all backends) or enrich (only for `inproc`) the crash event.

##### Not Supported in Crashpad on macOS

The Crashpad backend on macOS doesn't currently support notifying the crashing process and thus can't correctly terminate sessions or call the registered `before_send` or `on_crash` hooks. It will also lose any events queued for sending at the time of the crash.

##### Limitations in Crashpad on Windows for Fast-fail Crashes

The Crashpad backend on Windows supports fast-fail crashes, which bypass SEH (Structured Exception Handling) primarily for security reasons. `sentry-native` registers a WER (Windows Error Reporting) module, which signals the `crashpad_handler` to send a minidump when a fast-fail crash occurs. However, since this process bypasses SEH, the application local exception handler is no longer invoked, which also means that for these kinds of crashes, `before_send` and `on_crash` will not be invoked before sending the minidump and thus have no effect.

Note also that breadcrumbs can be filtered, as discussed in [our Breadcrumbs documentation](https://docs.sentry.io/product/error-monitoring/breadcrumbs.md).

## [Filtering Transaction Events](https://docs.sentry.io/platforms/native/guides/crashpad/configuration/filtering.md#filtering-transaction-events)

To prevent certain transactions from being reported to Sentry, use the `traces_sampler` or `before_send_transaction` configuration option, which allows you to provide a function to evaluate the current transaction and drop it if it's not one you want.

### [Using `traces_sampler`](https://docs.sentry.io/platforms/native/guides/crashpad/configuration/filtering.md#using-traces-sampler)

The `traces_sampler` and `traces_sample_rate` config options are mutually exclusive. If you define a `traces_sampler` to filter out certain transactions, you must also handle the case of non-filtered transactions by returning the rate at which you'd like them sampled.

In its simplest form, used just for filtering the transaction, it looks like this:

```c
static double
traces_sampler_callback(const sentry_transaction_context_t *transaction_ctx,
    sentry_value_t custom_sampling_ctx, const int *parent_sampled, void *user_data)
{
    // check if there was a parent sampling decision
    if (parent_sampled != NULL) {
        return *parent_sampled; // Inherit parent's sampling decision
    }
    // a sampling decision can be made on the transaction context name and operation
    if (strcmp(sentry_transaction_context_get_name(transaction_ctx),
        "little.teapot") == 0) {
        if (strcmp(sentry_transaction_context_get_operation(transaction_ctx),
            "Short and stout here is my handle and here is my spout") == 0) {
            // use the custom_sampling_ctx as a key-value dictionary
            if (sentry_value_as_int32(
                sentry_value_get_by_key(custom_sampling_ctx, "b")) == 42) {
                return 1;
            }
        }
    }
    return 0;
}

sentry_options_t *options = sentry_options_new();
sentry_options_set_traces_sampler(options, traces_sampler_callback);
sentry_init(options);
```

It also allows you to sample different transactions at different rates.

If the transaction currently being processed has a parent transaction (from an upstream service calling this service), the parent (upstream) sampling decision will always be included in the `parent_sampled` parameter, so that your `traces_sampler` can choose whether and when to inherit that decision. In most cases, inheritance is the right choice, to avoid breaking distributed traces. A broken trace will not include all your services. See [Inheriting the parent sampling decision](https://docs.sentry.io/platforms/native/guides/crashpad/configuration/sampling.md#inheritance) to learn more.

Learn more about [configuring the sample rate](https://docs.sentry.io/platforms/native/guides/crashpad/configuration/sampling.md).

### [Using `before_send_transaction`](https://docs.sentry.io/platforms/native/guides/crashpad/configuration/filtering.md#using-before-send-transaction)

When discarding a transaction in a `before_send_transaction` callback, one must call `sentry_value_decref(tx)` and return a `sentry_value_new_null()`.

```c

static sentry_value_t
before_transaction_callback(sentry_value_t tx, void *user_data)
{
    (void)user_data;
      // throw out any transaction while a tag is active
    if (!sentry_value_is_null(sentry_value_get_by_key(tx, "tags"))) {
        sentry_value_decref(tx);
        return sentry_value_new_null();
    }
    // replace the transaction name with a custom one otherwise
    sentry_value_set_by_key(
        tx, "transaction", sentry_value_new_string("little.coffeepot"));
    return tx;
}

sentry_options_t *options = sentry_options_new();
sentry_options_set_before_transaction(options, before_transaction_callback, NULL);
sentry_init(options);
```
