# API Reference

## Detour

Main SDK singleton, accessed via `Detour.shared`. All methods are `@MainActor`.

### Link processing methods

#### `processLink(_:)` (synchronous)

```swift
func processLink(_ url: URL) -> DetourResult
```

Converts a URL into a `DetourResult` with parsed route, pathname, params, and link type. Does not resolve short links. Returns an empty result for infrastructure URLs (e.g. Expo dev client URLs).

#### `processLink(_:config:)` (async, URL)

```swift
func processLink(_ url: URL, config: DetourConfig?) async -> DetourResult
```

Processes a URL and optionally resolves short links when `config` is provided. Use this when you receive a URL at runtime (e.g. from `onOpenURL` in SwiftUI or `application(_:open:)` in UIKit).

#### `processLink(_:config:)` (async, String)

```swift
func processLink(_ rawLink: String, config: DetourConfig? = nil) async -> DetourResult
```

Same as the URL variant but accepts a raw link string. Handles both full URLs and plain path strings. When `config` is provided and the URL is a single-segment web path (short link), the SDK resolves it to the full destination URL.

#### `resolveInitialLink(config:launchOptions:completion:)` (UIKit)

```swift
func resolveInitialLink(
    config: DetourConfig,
    launchOptions: [UIApplication.LaunchOptionsKey: Any]?,
    completion: @escaping @Sendable (DetourResult) -> Void
)
```

Resolves the initial link that launched the app in UIKit-based apps. Call from `application(_:didFinishLaunchingWithOptions:)`. Checks in priority order:

1. **Launch URL** from `launchOptions`
2. **Universal Link** from user activities in `launchOptions`
3. **Deferred link** from the Detour API (first install only)

This method is session-guarded, so it processes only once per app session. It also mounts analytics automatically.

#### `resolveInitialLink(config:connectionOptions:completion:)` (SceneDelegate / SwiftUI)

```swift
func resolveInitialLink(
    config: DetourConfig,
    connectionOptions: UIScene.ConnectionOptions,
    completion: @escaping @Sendable (DetourResult) -> Void
)
```

Same as the UIKit variant but uses `UIScene.ConnectionOptions` for scene-based apps. Call from `scene(_:willConnectTo:options:)` or the SwiftUI app lifecycle.

### Analytics methods

#### `mountAnalytics(config:)`

```swift
func mountAnalytics(config: DetourConfig)
```

Mounts the analytics system. Called automatically by `resolveInitialLink`. Only call manually if you use `processLink` without `resolveInitialLink`.

#### `unmountAnalytics()`

```swift
func unmountAnalytics()
```

Unmounts the analytics system and stops listening for events.

### Utility methods

#### `resetSession(allowDeferredRetry:)`

```swift
func resetSession(allowDeferredRetry: Bool = false)
```

Resets the session state so `resolveInitialLink` can run again. When `allowDeferredRetry` is `true`, also resets the first-entrance flag, which is useful for local testing of the deferred link flow.

## DetourConfig

SDK configuration. All properties are immutable and the struct conforms to `Sendable`.

```swift
public struct DetourConfig: Sendable {
    public let apiKey: String
    public let appID: String
    public let shouldUseClipboard: Bool
    public let linkProcessingMode: LinkProcessingMode
}
```

### Initializer

```swift
DetourConfig(
    apiKey: String,
    appID: String,
    shouldUseClipboard: Bool = true,
    linkProcessingMode: LinkProcessingMode = .all
)
```

<PropertyList>
  <Property name="apiKey" type={"String"} required>
    Publishable API key from the Detour Dashboard. Used as a Bearer token for all API calls (deferred link matching, short-link resolution, analytics)
  </Property>
  <Property name="appID" type={"String"} required>
    Unique app identifier from the Detour Dashboard. Used to route API requests to the correct app.
  </Property>
  <Property name="shouldUseClipboard" type={"Bool"} default={"true"}>
    When `true`, the SDK reads the device clipboard and includes it in the probabilistic fingerprint for deferred link matching. May trigger the iOS system paste permission prompt. Set to `false` to skip clipboard access.
  </Property>
  <Property name="linkProcessingMode" type={"LinkProcessingMode"} typeHref="#linkprocessingmode" default={".all"}>
    Controls which link sources the SDK processes. See [LinkProcessingMode](#linkprocessingmode) for details.
  </Property>
</PropertyList>

## DetourResult

Result returned by all link processing methods. Contains a processing flag and an optional parsed link.

```swift
public struct DetourResult: Sendable {
    public let processed: Bool
    public let link: DetourLink?
}
```

<PropertyList>
  <Property name="processed" type={"Bool"}>
    `true` when the SDK has finished processing the link (regardless of whether a link was found)
  </Property>
  <Property name="link" type={"DetourLink?"} typeHref="#detourlink">
    Parsed link data, or `nil` if no link was matched.
  </Property>
</PropertyList>

### Convenience computed properties

<PropertyList>
  <Property name="route" type={"String?"}>
    Shorthand for `link?.route`, the full in-app route including query string.
  </Property>
  <Property name="pathname" type={"String?"}>
    Shorthand for `link?.pathname`, the path without query string.
  </Property>
  <Property name="params" type={"[String: String]"}>
    Shorthand for `link?.params ?? [:]`, the parsed query parameters.
  </Property>
  <Property name="linkType" type={"LinkType?"} typeHref="#linktype">
    Shorthand for `link?.type`, which says how the link arrived.
  </Property>
  <Property name="linkURL" type={"URL?"}>
    Shorthand for `link.flatMap { URL(string: $0.url) }`, the original URL as a `URL` object, `nil` when there is no link.
  </Property>
</PropertyList>

### Factory method

```swift
static func empty() -> DetourResult
```

Returns a result with `processed: true` and `link: nil`. Used internally when no link is matched.

## DetourLink

Parsed link data returned inside a `DetourResult`.

```swift
public struct DetourLink: Sendable {
    public let url: String
    public let route: String
    public let pathname: String
    public let params: [String: String]
    public let type: LinkType
}
```

<PropertyList>
  <Property name="url" type={"String"}>
    Full URL string that was matched or opened.
  </Property>
  <Property name="route" type={"String"}>
    In-app route for navigation, as a path with query string, first path segment (app hash) stripped (e.g. `/promo/123?utm=1`)
  </Property>
  <Property name="pathname" type={"String"}>
    Route path without query string (e.g. `/promo/123`)
  </Property>
  <Property name="params" type={"[String: String]"}>
    Parsed query parameters as key-value pairs.
  </Property>
  <Property name="type" type={"LinkType"} typeHref="#linktype">
    How the link arrived in the app.
  </Property>
</PropertyList>

## LinkProcessingMode

```swift
public enum LinkProcessingMode: String, Sendable {
    case all
    case webOnly = "web-only"
    case deferredOnly = "deferred-only"
}
```

Controls which link sources are processed:

| Value | Behavior |
| --- | --- |
| `.all` (default) | Processes all link sources: deferred links from the Detour API, Universal Links (verified HTTP/HTTPS URLs), and custom scheme deep links |
| `.webOnly` | Same as `.all` but filters out custom scheme links. Only deferred links and Universal Links (HTTP/HTTPS) are processed |
| `.deferredOnly` | Only processes deferred links from the Detour API. Skips Universal Link and scheme link detection in `resolveInitialLink`. Recommended when your app handles runtime links separately |

## LinkType

```swift
public enum LinkType: String, Codable, Sendable {
    case deferred
    case verified
    case scheme
}
```

Describes how the link arrived in the app:

| Value | Meaning |
| --- | --- |
| `.deferred` | The link was obtained from the Detour deferred-link API. This happens when a user who does not have the app installed clicks a Detour link, installs the app, and opens it. The SDK retrieves the original link from the backend on first launch |
| `.verified` | The link arrived as a Universal Link, an HTTP/HTTPS URL that iOS verified belongs to your app via the apple-app-site-association file and delivered directly to it |
| `.scheme` | The link arrived via a custom URL scheme (e.g. `myapp://path`). These are non-HTTP URLs that iOS routes to your app based on the registered scheme |

## DetourAnalytics

Analytics module for logging events to the Detour backend. Accessed via static methods on the `DetourAnalytics` class. Analytics are automatically mounted when calling `resolveInitialLink`. Mount manually only if you use `processLink` without `resolveInitialLink`.

The SDK automatically logs an `app_open` retention event when analytics are first mounted in a session.

### Methods

#### `mount(config:)`

```swift
static func mount(config: DetourConfig)
```

Mounts the analytics system and subscribes to event emissions. Guards against duplicate mounts.

#### `unmount()`

```swift
static func unmount()
```

Unmounts the analytics system and stops listening for events.

#### `logEvent(_:data:)` (DetourEventName)

```swift
static func logEvent(_ eventName: DetourEventName, data: [String: Any]? = nil)
```

Records a user action using a predefined event name. The optional `data` parameter accepts a dictionary of arbitrary metadata.

#### `logEvent(_:data:)` (String)

```swift
static func logEvent(_ eventName: String, data: [String: Any]? = nil)
```

Records a user action using a custom event name string.

#### `logRetention(_:)`

```swift
static func logRetention(_ eventName: String)
```

Records a retention/lifecycle event for user engagement tracking.

## DetourEventName

| Category | Event Name | Raw value |
| :--- | :--- | :--- |
| **General** | `.login` | `login` |
|  | `.search` | `search` |
|  | `.share` | `share` |
|  | `.signUp` | `sign_up` |
|  | `.tutorialBegin` | `tutorial_begin` |
|  | `.tutorialComplete` | `tutorial_complete` |
|  | `.reEngage` | `re_engage` |
|  | `.invite` | `invite` |
|  | `.openedFromPushNotification` | `opened_from_push_notification` |
| **Sales** | `.addPaymentInfo` | `add_payment_info` |
|  | `.addShippingInfo` | `add_shipping_info` |
|  | `.addToCart` | `add_to_cart` |
|  | `.removeFromCart` | `remove_from_cart` |
|  | `.refund` | `refund` |
|  | `.viewItem` | `view_item` |
|  | `.beginCheckout` | `begin_checkout` |
|  | `.purchase` | `purchase` |
|  | `.adImpression` | `ad_impression` |

## Related pages

- [Usage](https://detour.swmansion.com/docs/sdk/ios/sdk-usage)
- [Examples](https://detour.swmansion.com/docs/sdk/ios/examples)
- [Testing & Troubleshooting](https://detour.swmansion.com/docs/sdk/ios/testing)