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.

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 or 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.

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.

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.

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.

Using SentrySDK:configureScope lets you set context data globally, which will be attached to all future events.

Copied
import Sentry

SentrySDK.configureScope { scope in
    scope.setTag(value: "my-tag", key: "my value")
    let user = User()
    user.email = "john.doe@example.com"
    scope.setUser(user)
}

Setting an instance of Scope is helpful when you want to completely control what should be attached to the event.

Copied
import Sentry

let exception = NSException(name: NSExceptionName("My Custom exception"), reason: "User clicked the button", userInfo: nil)
let scope = Scope()
scope.setLevel(.fatal)
// By explicitly just passing the scope, only the data in this scope object will be added to the event
// The global scope (calls to configureScope) will be ignored
// Only do this if you have mastered this SDK, otherwise, you risk losing useful info
// If you just want to mutate what's in the scope use the callback, see: captureError
SentrySDK.capture(exception: exception, scope: scope)

To maintain global state, but mutate context data for one capture call, use the Scope callback:

Copied
import Sentry

let userInfo = [NSLocalizedDescriptionKey : "Object does not exist"]
let error = NSError(domain: "YourErrorDomain", code: 0, userInfo: userInfo)
SentrySDK.capture(error: error) { (scope) in
    // Changes in here will only be captured for this event
    // The scope in this callback is a clone of the current scope
    // It contains all data but mutations only influence the event being sent
    scope.setTag(value: "value", key: "myTag")
}

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

Copied
import Sentry

SentrySDK.setUser(nil)

To learn what useful information can be associated with scopes see the context documentation.

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.

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:

Copied
import Sentry

SentrySDK.capture(error: error) { scope in
    scope.setLevel(.warning)
    // will be tagged with my-tag="my value"
    scope.setTag(value: "my value", key: "my-tag")
}

// will not be tagged with my-tag
SentrySDK.capture(error: error)

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.

Help improve this content
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").