# Scopes and Hubs

## SDKs will typically automatically manage the scopes for you in the framework integrations. Learn what a scope is and how you can use it to your advantage.

When an event is captured and sent to Sentry, SDKs will merge that event data with extra information from the current scope. SDKs will typically automatically manage the scopes for you in the framework integrations and you don't need to think about them. However, you should know what a scope is and how you can use it for your advantage.

## [What's a Scope, What's a Hub](#whats-a-scope-whats-a-hub)

You can think of the hub as the central point that our SDKs use to route an event to Sentry. When you call `init()` a hub is created and a client and a blank scope are created on it. That hub is then associated with the current thread and will internally hold a stack of scopes.

The scope will hold useful information that should be sent along with the event. For instance [contexts](../context/) or [breadcrumbs](../breadcrumbs/) are stored on the scope. When a scope is pushed, it inherits all data from the parent scope and when it pops all modifications are reverted.

The default SDK integrations will push and pop scopes intelligently. For instance web framework integrations will create and destroy scopes around your routes or controllers.

## [How the Scope and Hub Work](#how-the-scope-and-hub-work)

As you start using an SDK, a scope and hub are automatically created for you out of the box. It's unlikely that you'll interact with the hub directly unless you're writing an integration or you want to create or destroy scopes. Scopes, on the other hand are more user facing. You can call `ConfigureScope` at any point in time to modify data stored on the scope. This is useful for doing things like [modifying the context](../context/).

Read on if you're curious to know how thread locality works for scope data. In .NET, there are two modes for managing ambient data (which is data that's available in different parts of an application and doesn't need to be passed explicitly through method arguments): a disabled global mode and an enabled global mode. Usually, Sentry will automatically choose the most appropriate mode for your application type. However, this can be overridden by setting [`SentryOptions.IsGlobalModeEnabled`](../../configuration/options/#is-global-mode-enabled) manually.

If global mode is disabled (appropriate for most server-based applications), the ambient scope data will be stored as an `AsyncLocal` and will flow with the execution context. Stephen Toub's blog post on [ExecutionContext vs SynchronizationContext](https://devblogs.microsoft.com/pfxteam/executioncontext-vs-synchronizationcontext/) explains that concept in more detail.

If global mode is enabled (appropriate for desktop applications), ambient scope data will be stored as a Singleton and available globally. This means you can set context (such as the user logged into the application) once and it will be sent with all events, regardless of whether the event was captured on the UI thread or a background thread.

When you call a global function such as `CaptureEvent` internally Sentry discovers the current hub and asks it to capture an event. Internally the hub will then merge the event with the topmost scope's data.

## [Configuring the Scope](#configuring-the-scope)

The most useful operation when working with scopes is the `ConfigureScope` function. It can be used to reconfigure the current scope.

You can, for instance, add custom tags or inform Sentry about the currently authenticated user.

```powershell
Edit-SentryScope {
    $_.SetTag("my-tag", "my value")
    $_.User.Id = '42'
    $_.User.Email = 'john.doe@example.com'
}
```

You can also apply this configuration when unsetting a user at logout:

```powershell
Edit-SentryScope {
    $_.User = $null
}
```

To learn what useful information can be associated with scopes see [the context documentation](../context/).

## [Local Scopes](#local-scopes)

We also support pushing and configuring a scope within a single call. This is typically called `WithScope`, `PushScope` or implemented as a function parameter on the capture methods, depending on the SDK. It's very helpful if you only want to send data for one specific event.

### [Using Scope Callback Parameter](#using-scope-callback-parameter)

In the following example we use the scope callback parameter that is available for all `capture` methods to attach a `level` and a `tag` to only one specific error:

```powershell
try {
    throw "my error"
} catch {
    # will be tagged with my-tag="my value"
    $_ | Out-Sentry -EditScope {
        $_.SetTag("my-tag", "my value")
        $_.Level = [Sentry.SentryLevel]::Warning
    }
}

try {
    throw "my other error"
} catch {
    # will not be tagged with my-tag
    $_ | Out-Sentry
}
```

Before the callback is invoked the SDK creates a clone of the current scope, and the changes made will stay isolated within the callback function. This allows you to more easily isolate pieces of context information to specific locations in your code or even call `clear` to briefly remove all context information.

##### Important

Any exceptions that occur within the callback function for configuring a local scope will not be caught, and all errors that occur will be silently ignored and **not** reported.
