> ## 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 Listener

Called when a deep link is triggered from a Userpilot experience or notification.
Use this to handle in-app routing.

```js theme={null}
url: String — The deep link URL to be handled by your app.
```

## Analytics Listener

Called when an analytics event is triggered by the Userpilot SDK.
Use this to mirror or log SDK-level events into your analytics system.

Parameters:

```js theme={null}
analytic: "Identify" | "Screen" | "Event"

value: String — Event value, if any.

properties: Map<String, Any> — Additional metadata for the event.
```

## Experience Listener

Called when an experience or its step changes state. Includes two callback types:

**onExperienceStateChanged**
Triggered when the overall state of an experience changes.

```js theme={null}
experienceId?: Int — Unique ID of the experience (optional)

experienceType: "Flow" | "Survey" | "NPS"

experienceState: "Started" | "Completed" | "Dismissed" | "Skipped" | "Submitted"
```

**onExperienceStepStateChanged**
Triggered when the state of a specific step within an experience changes.

```js theme={null}
stepId: Int — Unique identifier of the step

experienceId: Int — ID of the parent experience

experienceType: "Flow" | "Survey" | "NPS"

stepState: "Started" | "Completed" | "Dismissed" | "Skipped" | "Submitted"

step?: Int — Step index (optional)

totalSteps?: Int — Total number of steps in the experience (optional)
```

**Note:** Both callbacks are sent under the same event name: UserpilotExperienceEvent

```js theme={null}
useEffect(() => {
        if (Capacitor.isNativePlatform()) {
            let analyticsListener: PluginListenerHandle
            let experienceListener: PluginListenerHandle
            let navigationListener: PluginListenerHandle

            const setupListeners = async () => {
                analyticsListener = await UserpilotPlugin.addListener(
                    'UserpilotAnalyticsEvent',
                    (event: any) => console.log('Analytics Event:', JSON.stringify(event, null, 2))
                )

                experienceListener = await UserpilotPlugin.addListener(
                    'UserpilotExperienceEvent',
                    (event: any) => console.log('Experience Event:', JSON.stringify(event, null, 2))
                )

                navigationListener = await UserpilotPlugin.addListener(
                    'UserpilotNavigationEvent',
                    (event: any) => {
                        console.log('Navigation Event', JSON.stringify(event, null, 2))
                        if (event?.url) handleDeepLink(event.url)
                    }
                )
            }

            setupListeners()

            return () => {
                if (analyticsListener) analyticsListener.remove()
                if (experienceListener) experienceListener.remove()
                if (navigationListener) navigationListener.remove()
            }
        }
    }, [])
```

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