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

# Track events

> Send the user actions your notification strategy is built on.

```swift theme={null}
Push.track("lesson_completed", properties: ["lesson_id": lesson.id, "score": "92"])
```

Events are the raw material for everything else. The Composer reads them to
find where users drop off, and flows trigger on them. Track the actions that
matter to your product: signing up, finishing a lesson, adding a connection,
starting a trial.

## How events reach us

Events are written to disk first, then uploaded in batches: when 20 are
queued, or every 30 seconds, whichever comes first. A failed upload is retried
later, and an event that arrives twice is counted once, so retries never
double count. Events survive the app being killed.

Call `Push.flush()` to upload right away, for example before a user signs out.

## Events a flow triggers on

Some flows need to react within seconds: "30 seconds after the user finishes
a drill, if they haven't started another." For those, waiting for a batch
would make the send late. List those event names in `immediateEvents` and they
upload as soon as they are tracked:

```swift theme={null}
PushConfiguration(
    apiKey: "pna_...",
    baseURL: URL(string: "https://api.pushnotif.ai")!,
    immediateEvents: ["drill_completed"]
)
```

## Naming

* Use `snake_case` past-tense names: `lesson_completed`, not `CompleteLesson`.
* Names starting with `$` are reserved for [events the SDK reports itself](https://docs.pushnotif.ai/sdk/automatic-events.md).
* Keep names stable. A flow refers to an event by its exact name, so renaming
  one silently stops every flow that triggers on it.

## Properties and types

> [!WARNING]
>
> Comparisons in flows **never convert types**. A condition `score >= 80` only
> matches when `score` arrived as the number `80`, never the string `"80"`.

`Push.track` sends every property as a string. In a flow, compare SDK
properties with `eq`, `neq`, `contains`, `exists` or `not_exists`, using string
values. Number comparisons (`gt`, `gte`, `lt`, `lte`) only match properties that
arrived as JSON numbers, which today means events sent through the
[ingest API](https://docs.pushnotif.ai/api/events.md).

Limits: an event name is at most 128 characters, and an event's properties at
most 32 KB of JSON.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.