> ## Documentation Index
> Fetch the complete documentation index at: https://docs.userpilot.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Callbacks

> Configure navigation, analytics, and experience callbacks

Configure how your app handles navigation, analytics events, and experience lifecycle callbacks.

## Navigation Handler

Defines how your app handles deep link routes triggered by Userpilot experiences. Implement this to route users to the appropriate screens or external URLs.

```swift theme={null}
@objc
public protocol UserpilotNavigationDelegate: AnyObject {
    func navigate(to url: URL)
}
```

The Userpilot SDK automatically handles navigation for external links if you haven't implemented `UserpilotNavigationDelegate`. For complete control over link handling, implement `UserpilotNavigationDelegate` to customize behavior for all link types.

**Example Implementation**

```c theme={null}
// in AppDelegate.h
#import <UIKit/UIKit.h>
@import Userpilot;

@interface AppDelegate : UIResponder <UIApplicationDelegate, UserpilotNavigationDelegate>
@end

// in AppDelegate.m
#pragma mark - UserpilotNavigationDelegate

- (void)navigateTo:(NSURL *)url {
    NSLog(@"Userpilot requested navigation to URL: %@", url.absoluteString);

    // Example: open the URL externally in Safari
    if ([[UIApplication sharedApplication] canOpenURL:url]) {
        [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
    }

    // Or handle specific URLs in-app using conditionals
    // e.g., check url.host or pathComponents
}
```

## Analytics Listener

Receives callbacks whenever the SDK tracks an event, screen, or identifies a user. Use this to integrate with another analytics tool or log events for debugging.

```swift theme={null}
@objc
public enum UserpilotAnalytic: Int {
    /// Represents an identify event, typically used to associate a user with a specific ID.
    case identify = 0

    /// Represents a screen tracking event, used to track visits to specific screens.
    case screen = 1

    /// Represents a custom event, used to track specific user interactions or actions.
    case event = 2

    /// Converts the analytic type to its string representation.
    public var rawValueString: String {
        switch self {
        case .identify:
            return "Identify"
        case .screen:
            return "Screen"
        case .event:
            return "Event"
        }
    }
}

/// A protocol that allows observation of analytics events emitted by the Userpilot SDK.
@objc
public protocol UserpilotAnalyticsDelegate: AnyObject {
    /// Notifies the delegate when a Userpilot analytics event is tracked.
    ///
    /// - Parameters:
    ///   - analytic: The type of analytic being tracked. This can be one of:
    ///     - `.identify`: Represents an identify event.
    ///     - `.screen`: Represents a screen tracking event.
    ///     - `.event`: Represents a custom event.
    ///   - value: The primary value associated with the analytic:
    ///     - For `.identify`: The user ID.
    ///     - For `.screen`: The screen title.
    ///     - For `.event`: The event name.
    ///   - properties: Optional dictionary containing additional context or metadata
    ///     about the analytic event.
    func didTrack(analytic: UserpilotAnalytic, value: String, properties: [String: Any]?)
}
```

**Example Implementation**

```c theme={null}
#pragma mark - UserpilotAnalyticsDelegate

- (void)didTrackWithAnalytic:(UserpilotAnalytic)analytic
                       value:(NSString *)value
                  properties:(NSDictionary<NSString *, id> *)properties {
    NSLog(@"Tracked event - type: %ld, value: %@, properties: %@", (long)analytic, value, properties);
}
```

## Experience Listener

Receives callbacks when experiences start, complete, or are dismissed, and when step state changes. Implement this to forward data to another destination or to react to user actions.

```swift theme={null}
/// The Userpilot experience type.
@objc
public enum UserpilotExperienceType: Int {
    case flow
    case survey
    case nps
}

/// The various states of a Userpilot experience.
@objc
public enum UserpilotExperienceState: Int {
    /// Indicates that the experience/step has started.
    case started

    /// Indicates that the experience/step has been completed successfully.
    case completed

    /// Indicates that the experience/step was dismissed before completion.
    case dismissed

    /// Indicates that the experience/step was skipped.
    case skipped

    /// Indicates that the experience/step was submitted.
    case submitted
}

/// A protocol to observe and respond to state changes in Userpilot experiences.
@objc
public protocol UserpilotExperienceDelegate: AnyObject {

    /// Called when the state of a Userpilot experience changes.
    ///
    /// - Parameters:
    ///   - experienceType: The current experience type.
    ///   - experienceId: A unique identifier for the experience.
    ///   - experienceState: The current state of the experience.
    func onExperienceStateChanged(
        experienceType: UserpilotExperienceType,
        experienceId: NSNumber?, 
        experienceState: UserpilotExperienceState
    )

    /// Called when the state of a specific step within a Userpilot experience changes.
    ///
    /// - Parameters:
    ///   - experienceType: The current experience type.
    ///   - experienceId: A unique identifier for the experience.
    ///   - stepId: A unique identifier for the step.
    ///   - stepState: The current state of the step.
    ///   - step: The current step number in the experience.
    ///   - totalSteps: The total number of steps in the experience.
    func onExperienceStepStateChanged(
        experienceType: UserpilotExperienceType,
        experienceId: NSNumber,
        stepId: NSNumber,
        stepState: UserpilotExperienceState,
        step: NSNumber?,
        totalSteps: NSNumber?
    )
}
```

**Example Implementation**

```c theme={null}
#pragma mark - UserpilotExperienceDelegate

- (void)onExperienceStateChangedWithExperienceType:(UserpilotExperienceType)experienceType
                                      experienceId:(NSNumber *)experienceId
                                   experienceState:(UserpilotExperienceState)experienceState {
    NSLog(@"Experience [%@] type: %ld changed state to: %ld",
          experienceId, (long)experienceType, (long)experienceState);
}

- (void)onExperienceStepStateChangedWithExperienceType:(UserpilotExperienceType)experienceType
                                          experienceId:(NSNumber *)experienceId
                                               stepId:(NSNumber *)stepId
                                            stepState:(UserpilotExperienceState)stepState
                                                 step:(NSNumber *)step
                                           totalSteps:(NSNumber *)totalSteps {
    NSLog(@"Step [%@] of experience [%@] (type: %ld) changed state to: %ld - step %ld/%ld",
          stepId, experienceId, (long)experienceType, (long)stepState,
          step.intValue, totalSteps.intValue);
}
```

<Frame>
  [**For any questions or concerns please reach out to support@userpilot.com**](mailto:support@userpilot.com)
</Frame>
