---
title: "Custom Instrumentation"
description: "Learn how to capture performance data on any action in your app."
url: https://docs.sentry.io/platforms/apple/guides/ios/tracing/instrumentation/custom-instrumentation/
---

# Custom Instrumentation | Sentry for iOS

To capture transactions and spans customized to your organization's needs, you must first [set up tracing.](https://docs.sentry.io/platforms/apple/guides/ios/tracing.md)

To instrument certain regions of your code, you can create transactions to capture them.

```swift
import Sentry;

// Transaction can be started by providing the name and the operation
let transaction = SentrySDK.startTransaction(
  name: "transaction-name",
  operation: "transaction-operation"
)

// Transactions can have child spans, and those spans can have child spans as well.
let span = transaction.startChild(operation: "child-operation")

// ...
// Perform your operations
// ...

span.finish(); // Remember that only finished spans will be sent with the transaction
transaction.finish(); // Finishing the transaction will send it to Sentry
```

For example, if you want to create a transaction for a user interaction in your application:

```swift
// Let's say this method is called in a background thread when a user clicks on the checkout button of your shop
func performCheckout()
{
  // This will create a new Transaction for you
  let transaction = SentrySDK.startTransaction(
      name: "checkout",
      operation: "perform-checkout"
  )

  // Validate the cart
  let validationSpan = transaction.startChild(
      operation: "validation",
      description: "validating shopping cart"
  )

  validateShoppingCart() //Some long process, maybe a sync http request.

  validationSpan.finish()

  // Process the order
  let processSpan = transaction.startChild(
      operation: "process",
      description: "processing shopping cart"
  )

  processShoppingCart() //Another time consuming process.

  processSpan.finish();

  transaction.finish();
}
```

This example will send a transaction named `checkout` to Sentry. The transaction will contain a `validation` span that measures how long `validateShoppingCart()` took and a `process` span that measures `processShoppingCart()`. Finally, the call to `transaction.finish()` will finish the transaction and send it to Sentry.

## [Create Transaction Bound to The Current Scope](https://docs.sentry.io/platforms/apple/guides/ios/tracing/instrumentation/custom-instrumentation.md#create-transaction-bound-to-the-current-scope)

Our SDK can bind a transaction to the scope making it accessible to every method running within this scope by calling `SentrySDK#startTransaction` method with `bindToScope` parameter to `true`.

`bindToScope` additionally ensures that your new transaction replaces any one that may be already started. This is useful if you want custom instrumentation to co-exist with auto-instrumented transactions.

In cases where you want to attach Spans to an already ongoing Transaction you can use `SentrySDK.span`. This method will return a `SpanProtocol` in case there is a running Transaction or a `Span` in case there is already a running Span, otherwise it returns `nil`.

```swift
import Sentry

let transaction = SentrySDK.startTransaction(
    name: "processOrderBatch",
    operation: "task",
    bindToScope: true
)
processOrderBatch()
transaction.finish()

func processOrderBatch() {
    var span = SentrySDK.span

    if span == nil {
        span = SentrySDK.startTransaction(name: "processOrderBatch", operation: "task")
    }

    var innerSpan = span.startChild(operation: "subtask")
    // omitted code
    innerSpan.finish()
}
```

## [Connect Errors with Spans](https://docs.sentry.io/platforms/apple/guides/ios/tracing/instrumentation/custom-instrumentation.md#connect-errors-with-spans)

Sentry errors can be linked to transactions and spans. Errors that are sent to Sentry while the transaction or span **bound to the scope** method is running, will be linked automatically:

```swift
import Sentry

let transaction = SentrySDK.startTransaction(name: "Transaction Name", operation: "operation", bindToScope: true)

do {
  try processItem()
  transaction.finish()
} catch {
  SentrySDK.capture(error: error)
  transaction.finish(status: .internalError)
}
```

## [Improving Data on Transactions and Spans](https://docs.sentry.io/platforms/apple/guides/ios/tracing/instrumentation/custom-instrumentation.md#improving-data-on-transactions-and-spans)

### [Adding Data Attributes to Transactions](https://docs.sentry.io/platforms/apple/guides/ios/tracing/instrumentation/custom-instrumentation.md#adding-data-attributes-to-transactions)

You can add data attributes to your transactions. This data is visible in the trace explorer in Sentry. Data attributes can be of type `String`, `Number` or `Boolean`, as well as (non-mixed) arrays of these types:

```swift
let transaction = SentrySDK.startTransaction(name: "processOrderBatch", operation: "task")
transaction.setData(value: "value1", key: "my-data-attribute-1")
transaction.setData(value: 42, key: "my-data-attribute-2")
transaction.setData(value: true, key: "my-data-attribute-3")

transaction.setData(value: ["value1", "value2", "value3"], key: "my-data-attribute-4")
transaction.setData(value: [42, 43, 44], key: "my-data-attribute-5")
transaction.setData(value: [true, false, true], key: "my-data-attribute-6")
```

### [Adding Data Attributes to Spans](https://docs.sentry.io/platforms/apple/guides/ios/tracing/instrumentation/custom-instrumentation.md#adding-data-attributes-to-spans)

You can add data attributes to your spans. This data is visible in the trace explorer in Sentry. Data attributes can be of type `String`, `Number` or `Boolean`, as well as (non-mixed) arrays of these types:

```swift
let span = parent.startChild(operation: "operation")
span.setData(value: "value1", key: "my-data-attribute-1")
span.setData(value: 42, key: "my-data-attribute-2")
span.setData(value: true, key: "my-data-attribute-3")

span.setData(value: ["value1", "value2", "value3"], key: "my-data-attribute-4")
span.setData(value: [42, 43, 44], key: "my-data-attribute-5")
span.setData(value: [true, false, true], key: "my-data-attribute-6")
```
