Journey limits and rules
Who can enter a journey and when, re-entry, what each step checks before it runs, and how self-hosters stop the engine.
Entry
A person enters only while the journey is open: live, past its start time (if any) and before its end time (if any).
| Entry | When a person enters |
|---|---|
| An event | When the event arrives. Property filters must pass. Events more than an hour old are ignored, so a device coming back online with old events doesn't start journeys. |
| Joining a segment | When the 15-minute membership refresh sees them join. When entry opens (at launch, start time or resume), everyone already in the segment who was never in the journey enters too. |
Who may enter. With Only people in a segment, only that segment's members can enter, whatever the entry.
Installs. An install arrives before the app identifies the person, so they enter as the device. When the app sets their identifier, their place moves to that person; they don't start again.
Control groups. At entry, the project control group (Engagement Settings, up to 20%) is checked first, then the journey's own (1 to 50%). Anyone held back by either is counted as held, gets nothing, and never enters later.
Re-entry
Nobody is in the same journey twice at once. After they leave, Re-entry decides:
| Setting | Behaviour |
|---|---|
| Only once, ever | At most one entry, ever. |
| Again after they leave | Can enter again after leaving. With an event entry, only an event after they left counts, so a retried or late event can't re-admit them. |
| Again after some days | Can enter again that many days (1 to 365) after leaving. |
People held in a control group never re-enter, whatever the setting.
How long people stay
A person leaves at the first of: their path ends, they reach a goal, or 90 days after entry. Waits and in-app steps never run past day 90; the person then leaves as expired.
A goal takes a person out from any step, even mid-wait. The goal's window doesn't limit this exit; it only decides what the report counts as a conversion.
What each step checks
| Step | Checks before it acts | When it can't act |
|---|---|---|
| Push | The person has an iOS or Android device with a push token. With quiet hours, the push goes out between 09:00 and 21:00 on the device's clock, otherwise at the next 09:00 there (UTC if the device's time zone is unknown). The project's daily push cap applies. | The person moves on without a push: no device, no token, web-only, or daily cap reached. |
| In-app message | The device gets the message at its next sync and shows it on its own triggers, with the message's own limits. | The person moves on once they've seen it or its Keep it for days (1 to 30) run out. If in-app messages are off for the project, nobody sees it and everyone waits out those days. |
| Wait | Waits 5 minutes to 30 days. With Move on early if they…, moves on when the person does the event, opens the push or clicks the in-app message above. | If time runs out first, the person takes the timeout branch. A wait right after a quiet-hours push counts from when the push actually goes out. |
| Split | Checks the condition (an event in the last 1 to 90 days, a segment, an attribute, or the platform), or assigns a fixed percentage path. | If event data can't be read, the person waits and the split retries. Nobody goes down a default branch. |
| Set attribute | Writes a journey_ attribute on every device of the person. |
Waits move on within a minute of their time. Splits, pushes and attribute steps run immediately, up to 20 in a row per pass; longer chains continue in the next pass a minute later.
The daily push cap counts per person per UTC day across every push campaign and journey. Set it under Pushes per person per day in Engagement Settings, from 1 to 50, or leave it empty for no cap.
Build limits
| What | Limit |
|---|---|
| Steps per journey | 60 |
| Loops | Not allowed. A step can't point back to an earlier step. Paths may join. |
| Filters on an entry event, a wait's event or a split's event | Up to 5, on custom events and screens only. System events (install, app open, link opened…) take none. |
| Goals | Up to 3 |
| Attribute keys | journey_ followed by up to 40 lowercase letters, digits or _. Values up to 255 characters. |
| Running journeys per project | 20, live and paused together |
| Segments in use per project | 20, shared with in-app messages |
| Files per journey | 30 files and 100 MB: images up to 1 MB, MP4 video up to 20 MB, MP3 or M4A audio up to 10 MB |
Changing a live journey
Once launched, the map is fixed. You can still change:
- the name
- a push step's title, text, link, image, data, sound and quiet hours
- an in-app step's content, triggers, limits and days kept
- a wait's length
- a percentage split's percentages
- a set-attribute step's value
Entry, re-entry, goals, control group, start and end times, and steps and connections can't change. Duplicate the journey and launch the copy instead.
Pausing stops entries and moves, and holds queued pushes and in-app messages. Resuming releases them and admits anyone who joined the entry segment meanwhile. An ended journey admits nobody new; people inside finish their paths.
Data kept per person
The journey keeps one row per person:
| Re-entry | Row kept |
|---|---|
| Only once, ever | While the journey runs |
| Again after they leave, event entry | One day after the person leaves |
| Again after some days | That many days after they leave |
| Ended journeys | Deleted once nobody is left inside |
Counts and reports are stored separately and never change.
Self-hosting
Journeys are available wherever in-app messages are. Without them, the dashboard and API answer "Journeys are not enabled".
JOURNEYS_ENABLED=false is an emergency stop for the journey engine. While off:
- nobody enters or moves to their next step
- events that would start a journey, meet a goal or end a wait are dropped, not queued
- the dashboard and API keep working: you can read, edit, launch, pause and end journeys
IN_APP_ENABLED=false stops journeys too.
When the engine is back on, overdue waits move at the next run, and anyone past 90 days leaves as expired. Events from the off period are lost: waits for them take the timeout branch, and people who reached a goal then stay in the journey (the report still counts the conversion). Segment members who joined meanwhile enter only after a pause and resume.
The engine runs on the journeys Sidekiq queue, with its scheduler on maintenance. JOURNEY_STEP_MAX_WORKERS (default 4, 1 to 64) caps concurrent step workers.