Skip to main content

Journeys

Journeys let you build multi-step programs that guide members through a series of steps over days, weeks, or months. Each journey is a directed graph of steps — some run in sequence, others in parallel, and some branch based on conditions.

Use journeys for:

  • Patient onboarding — Welcome message, insurance verification, intake form, first appointment scheduling
  • Chronic care management — Multi-week programs with check-ins, assessments, and escalation paths
  • Training programs — Sequential modules with prerequisites and completion tracking
  • Re-engagement campaigns — Automated outreach sequences with branching based on member responses

Journey Status

Every journey has a status that controls whether it accepts new enrollments and processes steps:

StatusWhat It Means
DraftBeing designed. Members cannot be enrolled.
ActiveAccepting enrollments and processing steps.
PausedTemporarily frozen. No steps advance, but enrolled members remain in place.
ArchivedRead-only. Historical reference only.

Creating a Journey

  1. Go to Journeys in your workspace
  2. Click New Journey
  3. Enter a name and optional description
  4. The journey starts in Draft status — you can design it fully before activating

Once you have added steps and connections, set the journey to Active to begin enrolling members.

Building the Step Graph

A journey is made up of steps connected by edges. Steps are the things that happen; connections control the order.

Step Types

TypePurpose
ActionExecutes a workflow or requires manual completion
WaitPauses progression until a trigger fires
CheckpointGate that requires all required parent steps to complete before proceeding
GoalTerminal step linked to a journey goal

Adding Steps

  1. Open your journey
  2. Click Add Step on the canvas
  3. Choose the step type
  4. Configure the step name, trigger, and optional workflow

Connecting Steps

Draw connections between steps to define the order of progression:

  • Click a step's output handle and drag to another step's input
  • A member moves from one step to the next when the parent step completes and the child step's trigger fires
  • You can connect one step to multiple children (branching) or multiple parents to one child (convergence)

Triggers

Each step has a trigger type that controls when it becomes eligible for a member:

TriggerHow It Works
ManualRequires explicit activation by staff or an AI agent
Time ElapsedFires a set number of seconds after the previous step completed. Configure the duration in the step settings.
Date RelativeFires relative to a date field on the member's enrollment (e.g., 7 days after enrollment). Configure the field name and offset.
Step CompletedFires when a specific other step completes. Select the target step in the configuration.
Tag MatchFires when the member gains matching labels. Specify which labels to watch for.
CEL ExpressionFires when a custom CEL expression evaluates to true. Write the expression in the trigger CEL field.

The journey's heartbeat periodically checks time-based triggers (Time Elapsed and Date Relative) and advances steps that are ready.

Connections and Conditional Branching

Connections between steps have three important properties:

  • Required — When a connection is marked as required, the child step cannot become eligible until this parent completes. Checkpoint steps require all required parents to complete.
  • CEL Condition — An optional CEL expression evaluated at runtime. If the condition is false, the child step stays pending and is re-evaluated on each heartbeat cycle. This enables both conditional branching and time-gated advancement.
  • Timeout (seconds) — An optional fallback for connections that have a celCondition. If the condition stays false for longer than this many seconds, the child step is marked as timed_out (a terminal status) rather than waiting forever. A timeout alone — without a celCondition — has no effect, because the step is never blocked in the first place.

Example — conditional branching: After a screening step, you might have two connections:

  • Connection to "Schedule Appointment" with condition member.data.screening.risk_level == "high"
  • Connection to "Send Resources" with condition member.data.screening.risk_level == "low"

The member follows only the branch whose condition matches.

Weekly (or Any Fixed-Interval) Cadence

To advance a member one step every 7 days, use a celCondition that checks how long ago the parent step completed. The heartbeat re-evaluates the condition every few minutes; once 7 days have elapsed, the condition becomes true and the child step becomes eligible.

CEL condition for "7 days after parent completed":

days_since(parent_step.completed_at) >= 7

Using the CLI:

# Connect Week 1 → Week 2 with a 7-day gate
gr journeys connections create -w $WID --journey-id <id> \
--data '{
"parentStepUuid": "<week-1-uuid>",
"childStepUuid": "<week-2-uuid>",
"celCondition": "days_since(parent_step.completed_at) >= 7"
}'

Repeat for each pair of consecutive steps (Week 2 → Week 3, and so on).

How it works: When Week 1 completes, Week 2 starts in pending status. For the first 6 days, days_since(parent_step.completed_at) >= 7 returns false and the step stays pending. On day 7, the condition returns true, the step becomes eligible, and it is dispatched. The member's journey workflow wakes at the computed day-7 boundary, with a periodic sweep (every ~15 minutes) as a fallback.

Important: Do not use timeoutSeconds alone for time-based advancement. timeoutSeconds is a fallback timeout for steps that are blocked by a condition — if the condition never unblocks, the step is marked timed_out (skipped/terminated) instead of waiting indefinitely. It is not a delay mechanism. To delay a step by N days, always use a celCondition as shown above.

Available CEL variables on connections:

VariableTypeDescription
parent_step.completed_atISO timestamp stringWhen the parent step completed
parent_step.activated_atISO timestamp stringWhen the parent step was activated
parent_step.eligible_atISO timestamp stringWhen the parent step became eligible
parent_step.statusstringCurrent status of the parent step
journey.enrolled_atISO timestamp stringWhen the member enrolled in the journey
days_since(ts)integerDays between ts and now (truncated)
member.*member objectMember labels, data fields, and properties
nowtimestampCurrent UTC time

Evaluation Order

When multiple connections leave a step, the order field controls which conditions are evaluated first. Lower numbers are evaluated before higher numbers.

Goals

Goals represent the high-value outcomes of a journey — the end-states you are trying to achieve.

  • Goals are linked to goal-type steps in the journey
  • Each goal can have an optional monetary value for tracking ROI
  • When a member completes a goal step, the goal is marked as achieved

To create a goal:

  1. Open the journey
  2. Go to the Goals section
  3. Click Add Goal
  4. Enter a name, optional description, and optional value
  5. Link the goal to a goal-type step in the journey

Enrolling Members

Single Member

  1. Open the journey
  2. Go to the Members tab
  3. Click Add Member
  4. Search for and select a member
  5. Click Enroll

The member's enrollment starts immediately. Their first step(s) begin in pending status and advance to eligible once trigger conditions are met.

Bulk Enrollment with a Member Filter

  1. Click Add Member
  2. Choose Use a member filter
  3. Select or create a saved member filter to target a group
  4. Leave "Auto-enroll" unchecked for a one-time enrollment
  5. Click Enroll

All members currently matching the filter are enrolled at once.

Auto-Enrollment (Continuous)

Auto-enrollment continuously watches for new members who match a filter and enrolls them automatically.

  1. Click Add Member
  2. Choose Use a member filter
  3. Check Auto-enroll matching members continuously
  4. Click Enroll

The filter is saved on the journey. On every heartbeat cycle, the system re-evaluates the filter and enrolls any newly matching members who are not already enrolled.

When auto-enroll is active, the Members tab shows which filter is linked. You can change or remove the auto-enroll filter at any time.

You can also set an auto-enroll filter via the API or CLI:

yarn gr journeys update -w $UUID --id $JOURNEY_UUID --data '{"autoEnrollFilterId": 123}'

To remove it, set autoEnrollFilterId to null.

Note: Members who were previously unenrolled (canceled) are not automatically re-enrolled, even if they match the filter. This prevents unwanted re-enrollment of intentionally removed members.

Step Progression

Each member's progress through a step follows this lifecycle:

StatusMeaning
PendingStep exists but prerequisites are not yet met
EligibleAll prerequisites are satisfied and trigger conditions are met
In ProgressStep has been activated (workflow running, waiting for action)
CompletedStep finished successfully
SkippedBypassed (manual skip or conditional branch not taken)
FailedStep execution failed

When a step completes, the heartbeat evaluates downstream connections to determine which child steps should become eligible next. If all goal steps are completed, the member's journey is marked as completed.

Monitoring Progress

Viewing Enrolled Members

Open the journey's Members tab to see all enrolled members and their current status. Each enrollment shows:

  • Member name
  • Enrollment status (active, completed, canceled)
  • Current step progress
  • Enrollment date

Step Statuses

Click on a member's enrollment to see their step-by-step progress. Each step shows its current status and when it last changed.

Goal Progress

The Goals section shows aggregate progress — how many enrolled members have achieved each goal.

Experiment breakdown (A/B testing)

When your workspace has Experiments enabled, you can filter goal reporting by Experiment:

  1. Open the Journey
  2. Choose an Experiment from the goal reporting selector
  3. Each goal shows per-Group metrics: exposed, achieved, and conversion rate

Filtering rules for this view:

  • Only Members enrolled in this Journey who have an experiment exposure for the selected Experiment appear in the breakdown
  • Members assigned to a Group elsewhere but never exposed in this Journey context are excluded
  • Counts below five display as "<5" for privacy; conversion rate is hidden when the exposed denominator is suppressed

See Experiments (A/B Testing) for authoring and eligibility filters.

Re-Enrollment

If a member needs to go through a journey again, you can re-enroll them. A new enrollment is created, and the member starts from the beginning with fresh step statuses.

Unenrollment

To remove a member from a journey:

  1. Open the journey's Members tab
  2. Find the member's enrollment
  3. Click Unenroll or Cancel

The enrollment is marked as canceled. The member's progress is preserved for historical reference but no further steps will advance.

Journey Notes

Use the notes field on a journey to document internal context — design decisions, clinical protocols, or operational notes. Notes are visible only to workspace administrators and are not shown to members.

Automation with Actions

Journey lifecycle events can trigger Actions in the event rule system, letting you attach automation to key moments:

EventWhen It Fires
journey:enrolledA member is enrolled in a journey
journey:completedA member completes a journey
journey_step:dueA step's trigger time arrives
journey_step:enteredA member step transitions to in progress
journey_step:completedA member step transitions to completed

See Routines for more on attaching automation to events.

Active Hours

Active Hours let you restrict when a journey can advance for each member. When configured, the engine will not move a member's pending step to eligible, and will not dispatch eligible steps, outside the allowed window. Any work that is already in-flight (dispatched steps, running workflows, member replies) is never blocked — only new outbound advancement is gated.

If no Active Hours are set, the journey runs around the clock (the default behavior).

How to Configure

Open the journey's settings panel and enable the Active Hours toggle. The editor shows a row for each day of the week. Each day can be:

  • Enabled with a start time and end time (HH:MM, 24-hour)
  • Disabled — the journey does not advance for any member on that day

At least one day must be enabled. The default template enables Monday–Friday, 09:00–18:00.

Timezone Mode

Because Gravity Rail serves members across time zones, Active Hours has two modes:

ModeBehavior
Member (default)Times resolve in each member's own timezone (Member.timezone, falling back to the workspace timezone). A 09:00 window opens at 9 AM local time for each member independently — an EST member and a PT member on the same journey gate three hours apart.
WorkspaceTimes resolve in the workspace timezone for everyone. The window opens simultaneously for all enrolled members. Use this for campaign-style journeys where "all at 9 AM ET" matters more than each member's local time.

Select the mode from the dropdown above the day grid in the Active Hours editor.

If a member's timezone changes, the new timezone takes effect on the next window evaluation — no re-enrollment is required.

Out-of-Window Policy

When a member's step would advance but the current time is outside the window, the step holds: it stays eligible and is dispatched as soon as the window next opens. Steps are never skipped or canceled by the Active Hours gate.

Configuring via API or CLI

Pass an activeHours object when creating or updating a journey:

gr journeys update -w $WID --id $JOURNEY_UUID --data '{
"activeHours": {
"days": [
{"day": "monday", "enabled": true, "start": "09:00", "end": "17:00"},
{"day": "tuesday", "enabled": true, "start": "09:00", "end": "17:00"},
{"day": "wednesday", "enabled": true, "start": "09:00", "end": "17:00"},
{"day": "thursday", "enabled": true, "start": "09:00", "end": "17:00"},
{"day": "friday", "enabled": true, "start": "09:00", "end": "17:00"},
{"day": "saturday", "enabled": false},
{"day": "sunday", "enabled": false}
],
"timezone_mode": "member",
"out_of_window_policy": "hold"
}
}'

To remove Active Hours and make the journey always-on again, set activeHours to null.

Tips

  • Start with a simple linear journey — Get comfortable with steps and triggers before adding branches.
  • Use checkpoints for convergence — When parallel branches need to rejoin, add a checkpoint that requires all parent steps.
  • Test in draft mode — Design and review the full step graph before setting the journey to active.
  • Use auto-enrollment carefully — Make sure your member filter is specific enough to avoid enrolling the wrong people.
  • Monitor failed steps — Check the Members tab regularly for steps that failed and may need manual intervention.