---
title: Integrations
---
# Integrations

Explore multiple ways the Capture SDK can be integrated with system APIs (iOS or Android) and popular third-party libraries.

## Log Forwarding

Integrate Capture SDK with one of the supported 3rd party logging libraries.The SDK provides several small side libraries that facilitate the forwarding of your existing logs to the SDK with just a few lines of code.

### Timber (Android)

Forward all logs emitted with the use of [Timber](https://github.com/JakeWharton/timber){:target="_blank"} logging library to the Capture SDK.

#### Installation

Add the following line to the dependencies in your `build.gradle` file:

=== "Gradle (Kotlin)"

    ```kotlin
    dependencies {
      implementation("io.bitdrift:capture-timber:<version>")
    }
    ```

=== "Gradle (Groovy)"

    ```groovy
    dependencies {
      implementation 'io.bitdrift:capture-timber:<version>'
    }
    ```

#### Usage

=== "Kotlin"

    ```kotlin
    import io.bitdrift.capture.timber.CaptureTree
    import timber.log.Timber
    // ...
    Timber.plant(CaptureTree())
    ```

=== "Java"

    ```java
    import io.bitdrift.capture.timber.CaptureTree;
    import timber.log.Timber;
    // ...
    Timber.plant(new CaptureTree());
    ```

### CocoaLumberjack (iOS)

Forward all logs emitted with the use of [CocoaLumberjack](https://github.com/CocoaLumberjack/CocoaLumberjack){:target="_blank"} logging library to the Capture SDK.

#### Installation

=== "Swift Package Manager"

    ```swift
    .package(url: "https://github.com/bitdriftlabs/capture-ios.git", from: "<version>")
    ```

    Next, add the `CaptureCocoaLumberjack` package product to your Xcode target.

=== "CocoaPods"

    ```ruby
    pod "CaptureCocoaLumberjack"
    ```

#### Usage

```swift
import CaptureCocoaLumberjack
import CocoaLumberjackSwift
// ...

Logger
  .start(
    withAPIKey: "<your-api-key>",
    sessionStrategy: .fixed()
  )?
  .enableIntegrations([.cocoaLumberjack()])
```

### SwiftyBeaver (iOS)

Forward all logs emitted with the use of [SwiftyBeaver](https://github.com/SwiftyBeaver/SwiftyBeaver){:target="_blank"} logging library to the Capture SDK.

#### Installation

=== "Swift Package Manager"

    ```swift
    .package(url: "https://github.com/bitdriftlabs/capture-ios.git", from: "<version>")
    ```

    Next, add the `CaptureSwiftyBeaver` package product to your Xcode target.

=== "CocoaPods"

    ```ruby
    pod 'BitdriftSwiftyBeaver'
    ```

#### Usage

```swift
import CaptureSwiftyBeaver
import SwiftyBeaver
// ...

Logger
  .start(
    withAPIKey: "<your-api-key>",
    sessionStrategy: .fixed()
  )?
  .enableIntegrations([.swiftyBeaver()])
```

## Linking Sessions

Developers will want to navigate from a third party view to the bitdrift Capture Timeline view to better understand what happened surrounding a crash/bug/etc. To accomplish this users can embed a link to the Capture Timeline view from the reported event using [the Logger's session url getter](features/session-management.md#retrieving-session-url).

!!! info ""
    In order for the sessions to be captured there should be at least one running Workflow triggering the `Record Session` action. The examples below assume the existence of a Workflow that matches on a log line as shown here:

    ![Workflows Menu](../assets/images/sdk-integrations-linking-sessions.png "Workflows Menu")

    Read more about how to capture sessions in Workflows [here](../product/workflows/actions.md#record-session).

!!! note
    In order to increase the chances that the error is reported in the same session, it is recommended that you use `ActivityBased` as your `SessionStrategy` when starting SDK. This is due to the libraries reporting errors on the next app launch after a crash. Read more about Capture SDK's Session Management [here](features/session-management.md).

### Bugsnag

=== "Android (Kotlin)"

    ```kotlin
    Bugsnag.start(this, Configuration.load(this).apply {
      addOnSend(OnSendCallback { event ->
        // Attach a bitdrift session link to each error report
        event.addMetadata(
          "<tab_name>", // the "section" which is displayed as a tab in the Bugsnag dashboard
          "bitdrift_capture_session",
          Logger.sessionUrl ?: "none"
        )
        // Send a log to bitdrift in order to trigger a Workflow with this log line
        Logger.logError { "App Error Reported" }
        // Return `true` to report this error
        true
      })
    })
    ```

=== "Android (Java)"

    ```java
    Configuration config = Configuration.load(this);
    config.addOnSend(new OnSendCallback() {
      @Override
      public boolean onSend(Event event) {
        // Attach a bitdrift session link to each error report
        event.addMetadata(
          "<tab_name>", // the "section" which is displayed as a tab in the Bugsnag dashboard
          "bitdrift_capture_session",
          Logger.getSessionUrl() != null ? Logger.getSessionUrl() : "none";
        );
        // Send a log to bitdrift in order to trigger a Workflow with this log line
        Logger.logError(() -> "App Error Reported");
        // Return `true` to report this error
        return true;
      }
    });
    Bugsnag.start(this, config);
    ```

=== "iOS (Swift)"

    ```swift
    let config = BugsnagConfiguration.loadConfig()
    config.addOnSendError { (event) -> Bool in
      // Attach a bitdrift session link to each error report
      event.addMetadata(
        Logger.sessionURL ?? "none",
        key: "bitdrift_capture_session",
        section: "<tab_name>" // the "section" which is displayed as a tab in the Bugsnag dashboard
      )
      // Send a log to bitdrift in order to trigger a Workflow with this log line
      Logger.logError("App Error Reported")
      // Return `true` to report this error
      return true
    }
    Bugsnag.start(with: config)
    ```

### Crashlytics

=== "Android (Kotlin)"

    ```kotlin
    // On app launch
    // Attach a bitdrift session link to each error report
    FirebaseCrashlytics.getInstance().setCustomKey(
      "bitdrift_capture_session",
      Logger.sessionUrl ?: "none"
    )
    if (FirebaseCrashlytics.getInstance().didCrashOnPreviousExecution()) {
      // Send a log to bitdrift in order to trigger a Workflow with this log line
      Logger.logError { "App Error Reported" }
    }

    ```

=== "Android (Java)"

    ```java
    // On app launch
    // Attach a bitdrift session link to each error report
    FirebaseCrashlytics.getInstance().setCustomKey(
      "bitdrift_capture_session",
      Logger.getSessionUrl() != null ? Logger.getSessionUrl() : "none";
    );
    if (FirebaseCrashlytics.getInstance().didCrashOnPreviousExecution()) {
      // Send a log to bitdrift in order to trigger a Workflow with this log line
      Logger.logError(() -> "App Error Reported");
    }
    ```

=== "iOS (Swift)"

    ```swift
    // On app launch
    // Attach a bitdrift session link to each error report
    Crashlytics.crashlytics().setCustomValue(
      Logger.sessionURL ?? "none",
      forKey: "bitdrift_capture_session"
    )
    if (Crashlytics.crashlytics().didCrashDuringPreviousExecution) {
      // Send a log to bitdrift in order to trigger a Workflow with this log line
      Logger.logError("App Error Reported")
    }
    ```

### Instabug

=== "Android (Kotlin)"

    ```kotlin
    Instabug.onReportSubmitHandler { report ->
      // Attach a bitdrift session link to each error report
      report.setUserAttribute(
        "bitdrift_capture_session",
        Logger.sessionUrl ?: "none"
      )
      // Send a log to bitdrift in order to trigger a Workflow with this log line
      Logger.logError { "App Error Reported" }
    }
    ```

=== "Android (Java)"

    ```java
    Instabug.onReportSubmitHandler(new Report.OnReportCreatedListener() {
      @Override
      public void onReportCreated(Report report) {
        // Attach a bitdrift session link to each error report
        report.setUserAttribute(
          "bitdrift_capture_session",
          Logger.getSessionUrl() != null ? Logger.getSessionUrl() : "none";
        );
        // Send a log to bitdrift in order to trigger a Workflow with this log line
        Logger.logError(() -> "App Error Reported");
      }
    });
    ```

=== "iOS"

    ```swift
    Instabug.willSendReportHandler = { report in
      // Attach a bitdrift session link to each error report
      report.setUserAttribute(
        Logger.sessionURL ?? "none",
        withKey: "bitdrift_capture_session"
      )
      // Send a log to bitdrift in order to trigger a Workflow with this log line
      Logger.logError("App Error Reported")
      return report
    }
    ```

### Sentry

=== "Android (Kotlin)"

    ```kotlin
    SentryAndroid.init(this) { options ->
      options.beforeSend = BeforeSendCallback { event, hint ->
        // Send a log to bitdrift in order to trigger a Workflow with this log line
        Logger.logError { "App Error Reported" }
        // Return event to report this error
        event
      }
    }
    Sentry.configureScope { scope ->
      // Attach a bitdrift session link to each error report
      scope.setContexts("bitdrift_capture_session", Logger.sessionUrl ?: "none")
    }
    ```

=== "Android (Java)"

    ```java
    SentryAndroid.init(this, options -> {
      options.setBeforeSend((event, hint) -> {
        // Send a log to bitdrift in order to trigger a Workflow with this log line
        Logger.logError(() -> "App Error Reported");
        // Return event to report this error
        return event;
      });
    });
    // Attach a bitdrift session link to each error report
    Sentry.configureScope(scope -> {
      scope.setContexts("bitdrift_capture_session", Logger.getSessionUrl() != null ? Logger.getSessionUrl() : "none");
    });
    ```

=== "iOS (Swift)"

    ```swift
    SentrySDK.start { options in
        options.beforeSend = { event in
            // Send a log to bitdrift in order to trigger a Workflow with this log line
            Logger.logError("App Error Reported")
            // Return event to report this error
            return event
        }
    }
    // Attach a bitdrift session link to each error report
    SentrySDK.configureScope { scope in
        scope.setContext(value: [
            "url": "Logger.sessionURL ?? "none"",
        ], key: "bitdrift_capture_session")
    }
    ```

## Networking

To automatically capture logs for application HTTP network traffic, Capture provides [`OkHttp`](https://square.github.io/okhttp/){:target="_blank"} integration on Android and [`URLSession`](https://developer.apple.com/documentation/foundation/urlsession){:target="_blank"} integration on iOS.

!!! note ""
    - Refer to the [Product Guides > Networking Insights](../product/instant-insights/categories.md#network) section to learn on how the product can surface visualizations of this data.
    - Refer to the [SDK > HTTP Traffic Logs](../sdk/features/http-traffic-logs.md) section to learn more about how the format the Capture SDK uses to emit these logs.

!!! info
    The app can add the `x-capture-path-template` HTTP header to its requests to control the *path template* used to emit Capture HTTP traffic logs. The SDK uses the value of this header as a path template for the requests on which it is present.

### OkHttp (Android)

If you're using [`OkHttp`](https://square.github.io/okhttp/){:target="_blank"} to perform your network calls the Capture SDK can instrument all aspects of every network request and response.

#### Auto-Instrumentation via Gradle Plugin

The Capture Android Gradle plugin will automatically instrument all your network requests by adding the `CaptureOkHttpEventListener` to all of your `OkHttpClient` instances through bytecode manipulation.

!!! info
    The following requires the usage of the **Capture Gradle Plugin**, learn how to configure it in [Android Quickstart Guide](./quickstart.md#gradle-plugin).

<img alt="Capture SDK Support" src="https://img.shields.io/badge/Android-0.22.3-006C9C">

Automatic OkHttp instrumentation is disabled by default, and must be enabled via custom DSL at the bottom of your `build.gradle` file:

=== "Gradle (Kotlin)"

    ```kotlin
    bitdrift {
        instrumentation {
            automaticOkHttpInstrumentation = true
        }
    }
    ```

=== "Gradle (Groovy)"

    ```groovy
    bitdrift {
        instrumentation {
            automaticOkHttpInstrumentation = true
        }
    }
    ```

#### Manual Instrumentation

The Capture OkHttp integration can also be manually enabled with one line of code using Capture's instance of `okhttp3.EventListener.Factory`.

=== "Android (Kotlin)"

    ```kotlin
    import io.bitdrift.capture.network.okhttp.CaptureOkHttpEventListenerFactory
    import okhttp3.OkHttpClient

    val client = OkHttpClient.Builder()
      .eventListenerFactory(CaptureOkHttpEventListenerFactory())
      .build()
    ```

=== "Android (Java)"

    ```java
    import io.bitdrift.capture.network.okhttp.CaptureOkHttpEventListenerFactory;
    import okhttp3.OkHttpClient;

    OkHttpClient client = new OkHttpClient.Builder()
      .eventListenerFactory(new CaptureOkHttpEventListenerFactory())
      .build();
    ```

Capture's event listener factory can be combined with an existing instance of `okhttp3.EventListener.Factory` or `okhttp3.EventListener`.

=== "Android (Kotlin)"

    ```kotlin
    // Combining `CaptureOkHttpEventListenerFactory` with an existing instance of `EventListener.Factory`.
    val client = OkHttpClient.Builder()
      .eventListenerFactory(CaptureOkHttpEventListenerFactory(existingEventListenerFactory))
      .build()

    // Combining `CaptureOkHttpEventListenerFactory` with an existing instance of `EventListener`.
    val client = OkHttpClient.Builder()
      .eventListenerFactory(CaptureOkHttpEventListenerFactory(existingEventListener))
      .build()
    ```

=== "Android (Java)"

    ```java
    // Combining `CaptureOkHttpEventListenerFactory` with an existing instance of `EventListener.Factory`.
    OkHttpClient client = new OkHttpClient.Builder()
      .eventListenerFactory(new CaptureOkHttpEventListenerFactory(existingEventListenerFactory))
      .build();

    // Combining `CaptureOkHttpEventListenerFactory` with an existing instance of `EventListener`.
    OkHttpClient client = new OkHttpClient.Builder()
      .eventListenerFactory(new CaptureOkHttpEventListenerFactory(existingEventListener))
      .build();
    ```

#### Using with Retrofit

When using [`Retrofit`](https://square.github.io/retrofit/){:target="_blank"}, you can use `RetrofitUrlPathProvider` to automatically extract endpoint URL paths from Retrofit service annotations:

=== "Android (Kotlin)"

    ```kotlin
    import io.bitdrift.capture.network.okhttp.CaptureOkHttpEventListenerFactory
    import io.bitdrift.capture.network.okhttp.RetrofitUrlPathProvider
    import okhttp3.OkHttpClient
    import retrofit2.Retrofit
    import retrofit2.converter.gson.GsonConverterFactory

    private val okHttpClient: OkHttpClient =
        OkHttpClient
            .Builder()
            .eventListenerFactory(
                CaptureOkHttpEventListenerFactory(
                    requestFieldProvider = RetrofitUrlPathProvider(),
                ),
            )
            .build()

    private val retrofitService = Retrofit.Builder()
        .baseUrl("https://binaryjazz.us")
        .client(okHttpClient)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(BinaryJazzRetrofitService::class.java)
    ```
!!! warning
    If you don't use `Retrofit` you might need to add the following lines to your `proguard-rules.pro` file to avoid the `Missing classes detected while running R8` error when assembling release builds:
    ```
    -dontwarn retrofit2.Invocation
    -dontwarn retrofit2.http.**
    ```

#### Apollo GraphQL

If you use [apollo for GraphQL v4](https://github.com/apollographql/apollo-kotlin) you can add extra instrumentation to those calls by using the `io.bitdrift.capture-apollo` dependency.

!!! note
    For v3 and lower, the OkHttp networking integration described above will do a best-effort to automatically extract the graphql operation name from the `X-APOLLO-OPERATION-NAME` HTTP header provided by apollo. There's no need to use this interceptor in that case.

##### Installation

Next, add the following line to the dependencies in your `build.gradle` file:

=== "Gradle (Kotlin)"

    ```kotlin
    dependencies {
      implementation("io.bitdrift:capture-apollo:<version>")
    }
    ```

=== "Gradle (Groovy)"

    ```groovy
    dependencies {
      implementation 'io.bitdrift:capture-apollo:<version>'
    }
    ```

##### Usage

It is required that you are already instrumenting your OkHttp networking requests with the `CaptureOkHttpEventListener` as described [above](#okhttp-android).

=== "Android (Kotlin)"

    ```kotlin
    import com.apollographql.apollo.ApolloClient
    import com.apollographql.apollo.network.okHttpClient
    import io.bitdrift.capture.apollo.CaptureApolloInterceptor
    import io.bitdrift.capture.network.okhttp.CaptureOkHttpEventListenerFactory
    import okhttp3.OkHttpClient

    val client = OkHttpClient.Builder()
      // you can skip this if you're using the gradle capture-plugin
      .eventListenerFactory(CaptureOkHttpEventListenerFactory())
      .build()

    val apolloClient = ApolloClient.Builder()
      .okHttpClient(okHttpClient)
      .addInterceptor(CaptureApolloInterceptor())
      .build()
    ```

=== "Android (Java)"

    ```java
    import com.apollographql.apollo.ApolloClient;
    import com.apollographql.apollo.network.okHttpClient;
    import io.bitdrift.capture.apollo.CaptureApolloInterceptor;
    import io.bitdrift.capture.network.okhttp.CaptureOkHttpEventListenerFactory;
    import okhttp3.OkHttpClient;

    OkHttpClient client = new OkHttpClient.Builder()
      // you can skip this if you're using the gradle capture-plugin
      .eventListenerFactory(new CaptureOkHttpEventListenerFactory())
      .build();

    ApolloClient apolloClient = new ApolloClient.Builder()
      .httpEngine(new DefaultHttpEngine(okHttpClient))
      .addInterceptor(new CaptureApolloInterceptor())
      .build();
    ```

### WebView (Android)

<img alt="Capture SDK Support" src="https://img.shields.io/badge/Android-0.22.3-006C9C">

!!! example "Experimental Feature"
    WebView integration is currently **experimental** and available as an **early access** feature. The API and functionality may change in future releases.

The Capture SDK can automatically instrument Android [`WebView`](https://developer.android.com/reference/android/webkit/WebView){:target="_blank"} instances to capture console logs and other web activity occurring within WebViews in your application.

#### Auto-Instrumentation via Gradle Plugin

The Capture Android Gradle plugin will automatically instrument all your `WebView` instances through bytecode manipulation, injecting monitoring capabilities when `loadUrl()` is called.

!!! info
    The following requires the usage of the **Capture Gradle Plugin** version **0.22.3** or later. Learn how to configure it in [Android Quickstart Guide](./quickstart.md#gradle-plugin).

Automatic WebView instrumentation is disabled by default and must be enabled via custom DSL at the bottom of your `build.gradle` file:

=== "Gradle (Kotlin)"

    ```kotlin
    bitdrift {
        instrumentation {
            automaticWebViewInstrumentation = true
        }
    }
    ```

=== "Gradle (Groovy)"

    ```groovy
    bitdrift {
        instrumentation {
            automaticWebViewInstrumentation = true
        }
    }
    ```

#### Configuration

To enable WebView monitoring, provide a non-null `WebViewConfiguration` to the `Configuration` object when starting the Capture SDK:

=== "Android (Kotlin)"

    ```kotlin
    import io.bitdrift.capture.Capture.Logger
    import io.bitdrift.capture.providers.session.SessionStrategy
    import io.bitdrift.capture.webview.WebViewConfiguration

    Logger.start(
      apiKey = "<your-api-key>",
      sessionStrategy = SessionStrategy.Fixed,
      configuration = Configuration(
        webViewConfiguration = WebViewConfiguration()
      )
    )
    ```

The default `WebViewConfiguration` object provides the bare minimum settings for WebView monitoring. Additional monitoring capabilities can be enabled by customizing the configuration object.

##### Configuration Options

The `WebViewConfiguration` class supports the following options to control what data is captured from WebViews:

| Option | Description | Default |
|--------|-------------|---------|
| `capturePageViews` | Capture page view tracking events when users navigate to new pages | `false` |
| `captureNetworkRequests` | Capture network requests made from the WebView (similar to OkHttp integration) | `false` |
| `captureNavigationEvents` | Capture navigation events (page loads, redirects, etc.) | `false` |
| `captureWebVitals` | Capture [Core Web Vitals](https://web.dev/articles/vitals){:target="_blank"} metrics ([LCP](https://web.dev/articles/lcp){:target="_blank"}, [FCP](https://web.dev/articles/fcp){:target="_blank"}, [CLS](https://web.dev/articles/cls){:target="_blank"}, [INP](https://web.dev/articles/inp){:target="_blank"}, [TTFB](https://web.dev/articles/ttfb){:target="_blank"}) | `false` |
| `captureLongTasks` | Capture [long tasks](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceLongTaskTiming){:target="_blank"} that block the main thread | `false` |
| `captureConsoleLogs` | Capture JavaScript [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console){:target="_blank"} messages (log/warn/error) | `false` |
| `captureUserInteractions` | Capture user interactions such as clicks and [rage clicks](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent){:target="_blank"} | `false` |
| `captureErrors` | Capture JavaScript errors, [promise rejections](https://developer.mozilla.org/en-US/docs/Web/API/Window/unhandledrejection_event){:target="_blank"}, and [resource load errors](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/error_event){:target="_blank"} | `false` |

**Example with custom configuration:**

=== "Android (Kotlin)"

    ```kotlin
    import io.bitdrift.capture.Capture.Logger
    import io.bitdrift.capture.providers.session.SessionStrategy
    import io.bitdrift.capture.webview.WebViewConfiguration

    Logger.start(
      apiKey = "<your-api-key>",
      sessionStrategy = SessionStrategy.Fixed,
      configuration = Configuration(
        webViewConfiguration = WebViewConfiguration(
          capturePageViews = true,
          captureWebVitals = true,
          captureConsoleLogs = true,
          captureErrors = true
        )
      )
    )
    ```

#### Dependencies

If your application does not already use the [`androidx.webkit:webkit`](https://developer.android.com/jetpack/androidx/releases/webkit){:target="_blank"} dependency, you will need to add it manually to your `build.gradle` file:

=== "Gradle (Kotlin)"

    ```kotlin
    dependencies {
      implementation("androidx.webkit:webkit:1.15.0")
    }
    ```

=== "Gradle (Groovy)"

    ```groovy
    dependencies {
      implementation 'androidx.webkit:webkit:1.15.0'
    }
    ```

#### Logging from WebView JavaScript

Web pages loaded in instrumented WebViews can send logs directly to the Capture SDK using the `window.bitdrift` JavaScript interface that is automatically injected by the SDK.

The interface provides a `log` method that accepts the following parameters:

- `logLevel` ([`LogLevel`](https://github.com/bitdriftlabs/capture-sdk/blob/main/platform/webview/src/types.ts#L42){:target="_blank"}): The log level - one of `"trace"`, `"debug"`, `"info"`, `"warning"`, or `"error"`
- `message` (string): The log message
- `fields` ([`SerializableLogFields`](https://github.com/bitdriftlabs/capture-sdk/blob/main/platform/webview/src/types.ts#L19){:target="_blank"}, optional): A key-value object containing additional fields to attach to the log

**Example:**

```javascript
// Simple log
window.bitdrift.log("info", "User clicked checkout button");

// Log with additional fields
window.bitdrift.log("error", "Payment failed", {
  errorCode: "PAYMENT_DECLINED",
  amount: 49.99,
  currency: "USD"
});

// Log with multiple fields
window.bitdrift.log("debug", "Form validation", {
  formId: "checkout-form",
  validFields: 8,
  invalidFields: 2,
  userId: "user_12345"
});
```

!!! note
    The `window.bitdrift` interface is injected only when the WebView is instrumented by the Capture SDK. To prevent errors in standard browsers or un-instrumented WebViews, ensure you check that the interface is defined before accessing it.

### URLSession (iOS)

Capture [`URLSession`](https://developer.apple.com/documentation/foundation/urlsession){:target="_blank"} integration can be enabled with just one line of code. It's recommended that the logger is started and integrations are enabled as early in the application lifecycle as possible. If the integration is started after the app has created or accessed instances of `URLSession`, it may result in the SDK not emitting logs for `URLSessionTask`s started with those sessions.

=== "iOS (Swift)"

    ```swift
    Logger
      .start(
        withAPIKey: "<your-api-key>",
        sessionStrategy: .fixed()
      )?
      .enableIntegrations([.urlSession()])
    ```

The above integration method uses swizzling to provide a seamless integration experience. The alternate integration method is swizzling-free and works in cases where the logger is configured and the integration is enabled after the `URLSession` instances are created or accessed.

=== "iOS (Swift)"

    ```swift
    Logger
      .start(
        withAPIKey: "<your-api-key>",
        sessionStrategy: .fixed()
      )?
      .enableIntegrations([.urlSession()], disableSwizzling: true)

    let session = URLSession(
      instrumentedSessionWithConfiguration: .default,
      delegate: nil,
      delegateQueue: nil
    )
    ```

#### Apollo GraphQL

If you use [apollo for GraphQL](https://github.com/apollographql/apollo-ios) the URLSession networking integration described above will do a best-effort to automatically extract the graphql operation name from the `X-APOLLO-OPERATION-NAME` HTTP header provided by apollo.
