Skip to main content
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:

Naming

  • Use snake_case past-tense names: lesson_completed, not CompleteLesson.
  • Names starting with $ are reserved for events the SDK reports itself.
  • 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

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. Limits: an event name is at most 128 characters, and an event’s properties at most 32 KB of JSON.