> 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/reference/events.md).

# Events

Reference for events the SDK emits on your behalf and events you track yourself.

## Event types

Every event the SDK records has a `type` of either `system` or `custom`:

| Type     | Who emits it               | Example             |
| -------- | -------------------------- | ------------------- |
| `system` | SDK, automatically         | `SessionStarted`    |
| `custom` | Your app, via `track(...)` | `PurchaseCompleted` |

Both flow through the same pipeline and appear together in `getRecentEvents(...)`. System events are also delivered to `SystemEventsListener` as they fire.

***

## Standard events (SDK-emitted)

These fire automatically. You don't need to track them. This is the complete list. Most are **observable** via the system-events listener — subscribe with `setSystemEventsListener(...)` (iOS/Android) or `addSystemEventListener(...)` (React Native). One (`CampaignResolved`) is recorded for server-side stats only and is never a frequency-cap input; the **Observable** column says which events are delivered to your listener.

| Name                    | When it fires                                                                                                                              | Properties                                           | Observable |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------- | ---------- |
| `SdkInitialized`        | Once per session, after the SDK finishes setting up and before the first campaign fetch.                                                   | none                                                 | yes        |
| `ConfigFetchStarted`    | Just before the SDK requests the campaign configuration.                                                                                   | none                                                 | yes        |
| `ConfigFetchFinished`   | When the campaign fetch completes (success or failure).                                                                                    | `campaignCount`, `success`, `campaigns`              | yes        |
| `SessionStarted`        | When a new session begins — either cold (first launch after install or full restart) or warm (app returning to foreground after timeout).  | `type`                                               | yes        |
| `SessionFinished`       | When the current session ends.                                                                                                             | none                                                 | yes        |
| `CampaignShown`         | When a campaign is activated and delivered in response to an event.                                                                        | `source`, `campaignId`                               | yes        |
| `EventTriggered`        | After every `track(...)` call, mirroring the custom event that was just recorded.                                                          | `sourceEvent`, `properties`                          | yes        |
| `CustomPropertyChanged` | When you set, update, remove, or clear a custom property. Usable as a campaign **trigger** so you can react to the moment a trait changes. | `key`, `oldValue`, `newValue`                        | yes        |
| `CampaignResolved`      | When a presented (blocking) campaign action resolves or is skipped. **0.5.0+.** Mainly for stats — counted per campaign server-side.       | `campaignId`, `result`, `unavailableReason` (0.5.2+) | stats      |

### SdkInitialized

Fires once after construction/initialization finishes. Use this to know when it's safe to read `getDataSetSnapshot(...)` or query cached campaigns.

```
name:       "SdkInitialized"
type:       "system"
properties: {}
```

### ConfigFetchStarted

Fires before the network request that loads the campaign configuration.

```
name:       "ConfigFetchStarted"
type:       "system"
properties: {}
```

### ConfigFetchFinished

Fires after the campaign configuration has been fetched (or failed to fetch). The cached configuration has already been applied by the time this event fires.

```
name:       "ConfigFetchFinished"
type:       "system"
properties: {
  "campaignCount": 3,
  "success":       true,
  "campaigns": [
    { "id": "c_abc", "name": "Welcome offer" },
    { "id": "c_def", "name": "Day-2 check-in" }
  ]
}
```

| Property        | Type    | Description                                         |
| --------------- | ------- | --------------------------------------------------- |
| `campaignCount` | number  | Number of campaigns now active in memory.           |
| `success`       | boolean | `true` if the fetch completed without error.        |
| `campaigns`     | array   | One entry per active campaign with `id` and `name`. |

### SessionStarted

Fires at the start of every session.

```
name:       "SessionStarted"
type:       "system"
properties: { "type": "cold" }
```

| Property | Type   | Description                                                                                                                                                     |
| -------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`   | string | `"cold"` for the first session of an install or a full process restart, `"warm"` for a session resumed after the app was backgrounded past the session timeout. |

### SessionFinished

Fires when the current session ends.

```
name:       "SessionFinished"
type:       "system"
properties: {}
```

### EventTriggered

Fires immediately after each `track(...)` call. The original event is mirrored in the `sourceEvent` and `properties` fields. This exists so downstream listeners (dashboards, analytics forwarders) see a uniform system-event stream for every tracked action.

```
name:       "EventTriggered"
type:       "system"
properties: {
  "sourceEvent": "PurchaseCompleted",
  "properties":  { "sku": "premium_yearly", "price": 59.99 }
}
```

| Property      | Type   | Description                                      |
| ------------- | ------ | ------------------------------------------------ |
| `sourceEvent` | string | The `name` of the custom event that was tracked. |
| `properties`  | object | The exact property map passed to `track(...)`.   |

### CampaignShown

Fires when a campaign is activated in response to a triggering event.

```
name:       "CampaignShown"
type:       "system"
properties: {
  "source":     "PurchaseCompleted",
  "campaignId": "c_abc"
}
```

| Property     | Type   | Description                                    |
| ------------ | ------ | ---------------------------------------------- |
| `source`     | string | Name of the event that triggered the campaign. |
| `campaignId` | string | Identifier of the activated campaign.          |

### CustomPropertyChanged

Fires whenever a custom property is set, updated, removed, or cleared — i.e. on every `setCustomProperty(...)`, `removeCustomProperty(...)`, and `clearCustomProperties()`. Because it carries the key and both the previous and new value, you can use it as a campaign **trigger** to react to the moment a trait changes, not just to the trait's current value.

```
name:       "CustomPropertyChanged"
type:       "system"
properties: {
  "key":      "plan_tier",
  "oldValue": "pro",
  "newValue": "free"
}
```

| Property   | Type                | Description                                                                 |
| ---------- | ------------------- | --------------------------------------------------------------------------- |
| `key`      | string              | The custom property that changed.                                           |
| `oldValue` | primitive \| absent | The value before the change. Absent when the property is newly set.         |
| `newValue` | primitive \| absent | The value after the change. Absent when the property is removed or cleared. |

### CampaignResolved

**0.5.0+.** Fires when a campaign's presented (blocking) action finishes — completed, dismissed, unavailable, or skipped. It is emitted mainly for server-side observability (counted per campaign) rather than as a signal your app reacts to, and it is never a frequency-cap input.

```
name:       "CampaignResolved"
type:       "system"
properties: {
  "campaignId":        "c_abc",
  "result":            "Unavailable",
  "unavailableReason": "TimedOut"
}
```

| Property            | Type   | Description                                                                                                                                                                                                                                                                     |
| ------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `campaignId`        | string | Identifier of the campaign whose action resolved.                                                                                                                                                                                                                               |
| `result`            | string | One of `Completed`, `Dismissed`, `Unavailable`, `SkippedNoPresenter`, `SkippedNoContinuation`.                                                                                                                                                                                  |
| `unavailableReason` | string | **0.5.2+.** Present only when `result` is `Unavailable`, to say why the gate failed open: `TimedOut` (the deadline elapsed before the action reported), `PresenterFailed` (the action handler threw), or `PresenterReported` (the handler itself reported it couldn't proceed). |

***

## Custom events

Custom events are the events you define to describe what users do in your app.

### Targeting on events

Events aren't only triggers — campaign audience rules can target them directly: how many times an event has happened for a user (or whether it ever has), when they first or last did it, and property filters so that only matching occurrences count ("`Purchase` where `product` equals `pro`"). Requires apps built with SDK 0.6.1 or later; on older builds such campaigns simply never match. See [Targeting and audiences](/concepts/targeting-and-audiences.md#targeting-on-past-behavior) for the full model.

### Naming

* Use a short, stable string. Once an event name is in the wild, changing it breaks every campaign targeting it.
* **Recommended:** `PascalCase` for event names and `snake_case` for property keys. Names are just strings — the SDK accepts any value — but this house convention keeps things readable: events read like action constants (`PurchaseCompleted`, `WorkoutCompleted`), properties read like data fields (`plan_tier`, `source_screen`).
* Describe an action, not a screen. `PurchaseCompleted` is useful; `PurchaseScreen` isn't — you'll want to track both the screen view and the purchase as separate events.
* Reserve the system event names above for the SDK. Don't emit an event called `SessionStarted` yourself.

### Suggested naming patterns

| Pattern             | Example                             | Use for                                     |
| ------------------- | ----------------------------------- | ------------------------------------------- |
| `<Object><Verb>`    | `PaywallViewed`, `TrialStarted`     | Lifecycle or funnel steps.                  |
| `<Feature><Action>` | `ExportClicked`, `FilterApplied`    | Feature-level interactions.                 |
| `<Outcome>`         | `PurchaseCompleted`, `SignupFailed` | Terminal events you'll target campaigns on. |

### Property conventions

* Keys are strings. We recommend `snake_case` for property keys (e.g. `plan_tier`, `source_screen`) so they read differently from the `PascalCase` event-name recommendation.
* Keep the set of keys per event name stable. If `PurchaseCompleted` sometimes has `price` and sometimes doesn't, campaigns that depend on `price` will behave inconsistently.
* Prefer machine-readable values. `"currency": "USD"` beats `"currency": "US Dollars"`.
* Don't pack structured blobs into a single string. Use multiple keys instead.

### Property value types

The SDK accepts primitive values only. What counts as a primitive depends on the platform.

| Platform         | Accepted value types                                  |
| ---------------- | ----------------------------------------------------- |
| iOS (native)     | `String`, `Int`, `Int64`, `Float`, `Double`, `Bool`   |
| Android (native) | `String`, `Int`, `Long`, `Float`, `Double`, `Boolean` |
| React Native     | `string`, `number`, `boolean`                         |

Arrays, nested objects, `null`, and date objects are not supported as property values. Serialize dates to a number (Unix milliseconds) or a string (ISO 8601) before passing them.

### Example

{% tabs %}
{% tab title="iOS" %}

```swift
amply.track(
  event: "PurchaseCompleted",
  properties: [
    "sku": "premium_yearly",
    "price": 59.99,
    "currency": "USD",
    "is_trial": false
  ]
)
```

{% endtab %}

{% tab title="Android" %}

```kotlin
amply.track(
  "PurchaseCompleted",
  mapOf(
    "sku" to "premium_yearly",
    "price" to 59.99,
    "currency" to "USD",
    "is_trial" to false
  )
)
```

{% endtab %}

{% tab title="React Native" %}

```ts
await amply.track({
  name: "PurchaseCompleted",
  properties: {
    sku: "premium_yearly",
    price: 59.99,
    currency: "USD",
    is_trial: false,
  },
});
```

{% endtab %}
{% endtabs %}

***

## Related

* [SDK reference — iOS](/reference/sdk-ios.md) — full API, including `track` and `setSystemEventsListener`.
* [SDK reference — Android](/reference/sdk-android.md) — same for Android.
* [API reference](/reference/api-reference.md) — how events travel from the SDK to the server.
