> For the complete documentation index, see [llms.txt](https://docs.amply.tools/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.amply.tools/developer-guide/handling-callbacks.md).

# Handling callbacks

The SDK emits internal lifecycle events — "I initialized," "a session started," "a campaign was shown" — that your app can subscribe to. Most apps ignore them. A few use them for diagnostics, to gate UI until the SDK is ready, or to log campaign impressions into their own analytics tool.

A PM should read this as: "the developer can optionally listen for SDK milestones. Useful for debugging or mirroring campaign impressions into another system, not required for the SDK to work."

**Use this when** you want to react to SDK lifecycle — log initialization timing, block UI until first config arrives, mirror campaign impressions. **Don't use this when** you just want to track app-level actions — that's [Tracking events](/developer-guide/tracking-events.md).

## What gets emitted

The SDK emits system events that your listener can observe: `SdkInitialized`, `ConfigFetchStarted`, `ConfigFetchFinished`, `SessionStarted`, `SessionFinished`, `CampaignShown`, `EventTriggered`, and `CustomPropertyChanged`. `CampaignResolved` is stats-only and is not delivered to this listener. See [Events](/reference/events.md) for the full canonical list, each event's exact properties, and which ones are observable here.

Each event carries a `name`, a `timestamp`, a `type` (`system`), and a `properties` map with event-specific details.

## Subscribing to system events

{% tabs %}
{% tab title="iOS (Swift)" %}

```swift
import AmplySDK

class SdkEventsAdapter: SystemEventsListener {
    func onEvent(event: EventInterface) {
        print("Amply system event: \(event.name) props: \(event.properties)")
        // Example: log to your analytics tool
        if event.name == "CampaignShown" {
            Analytics.log("amply_campaign_shown", params: event.properties)
        }
    }
}

// Hold a strong reference from your own side (e.g., on AppDelegate) so the adapter stays alive.
let adapter = SdkEventsAdapter()
amply.setSystemEventsListener(listener: adapter)
```

{% endtab %}

{% tab title="Android (Kotlin)" %}

```kotlin
import tools.amply.sdk.events.EventInterface
import tools.amply.sdk.events.SystemEventsListener

class SdkEventsAdapter : SystemEventsListener {
    override fun onEvent(event: EventInterface) {
        Log.d("Amply", "system event: ${event.name} props=${event.properties}")
        if (event.name == "CampaignShown") {
            Analytics.log("amply_campaign_shown", event.properties)
        }
    }
}

amply.setSystemEventsListener(SdkEventsAdapter())
```

{% endtab %}

{% tab title="React Native (TS)" %}

```ts
import Amply, { systemEvents, formatSystemEventLabel } from '@amplytools/react-native-amply-sdk';
import { useEffect } from 'react';

export function useSdkDiagnostics() {
  useEffect(() => {
    let unsubscribe: (() => void) | undefined;
    let unmounted = false;

    systemEvents.addListener(event => {
      console.log('Amply system event:', formatSystemEventLabel(event));
      if (event.name === 'CampaignShown') {
        Analytics.log('amply_campaign_shown', event.properties);
      }
    })
      .then(unsub => {
        if (unmounted) unsub();
        else unsubscribe = unsub;
      });

    return () => {
      unmounted = true;
      unsubscribe?.();
    };
  }, []);
}
```

{% endtab %}
{% endtabs %}

## React Native hook

React Native also exposes a hook that collects recent system events for rendering in a debug view:

```tsx
import { useAmplySystemEvents, formatSystemEventLabel } from '@amplytools/react-native-amply-sdk';

export function SdkEventsLog() {
  const { events, reset } = useAmplySystemEvents({ maxEntries: 50 });

  return (
    <View>
      <Button title="Clear" onPress={reset} />
      {events.map(e => (
        <Text key={`${e.name}-${e.timestamp}`}>
          {formatSystemEventLabel(e)}
        </Text>
      ))}
    </View>
  );
}
```

`useAmplySystemEvents` accepts `{ maxEntries, dedupe, onEvent }`. It manages subscription and cleanup for you.

## Pending events at startup

System events can fire before your listener is registered (for example, `SdkInitialized` fires during construction). The SDK queues these early events and delivers them to the listener as soon as it's set. Register your listener as early as possible — ideally immediately after SDK construction — to see the full timeline.

## When to use this API vs ignore it

Use it:

* Mirroring `CampaignShown` into your own analytics tool to reconcile funnels
* Blocking a loading state until `ConfigFetchFinished` on first launch
* Logging `SessionStarted`/`SessionFinished` timing for diagnostics

Ignore it:

* For normal event tracking — call `track(...)` directly instead
* For deeplink handling — use `registerDeepLinkListener` / `addDeepLinkListener`
* For remote config — the SDK applies it internally

## One listener at a time (native iOS / Android)

On iOS and Android, `setSystemEventsListener` replaces any previously-set listener. On React Native, `systemEvents.addListener` adds to a list of subscribers and returns an unsubscribe function per subscription.

## Related

* [Tracking events](/developer-guide/tracking-events.md) — your custom events, not SDK lifecycle
* [Testing your integration](/developer-guide/testing-your-integration.md) — use these callbacks to confirm initialization and config fetch
* [iOS SDK reference](/reference/sdk-ios.md) — exact signatures
* [Android SDK reference](/reference/sdk-android.md) — exact signatures
* [React Native SDK reference](/reference/sdk-react-native.md) — exact signatures


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.amply.tools/developer-guide/handling-callbacks.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
