The visual builder where journeys are designed, with the full trigger, channel, logic, and integration node reference.
The Journey Orchestrator is the canvas. You drag nodes from the palette, connect them, configure each one, and the result is a journey: a flow a real customer moves through, one step at a time.
Nodes are dragged from the palette on the left. Selecting a node opens its properties panel, where you configure it and see the variables it makes available to everything downstream.
The builder has three tabs:
The right-hand Build with AI panel is a designer agent that edits the canvas with you. Describe the journey you want and it plans the nodes, adds them, wires them, and fills in configuration.
Two things make its output usable rather than decorative:
While an AI turn is running, structural edits are locked so the canvas and the agent's plan cannot diverge mid-turn.
Every node publishes variables that downstream nodes can use. A trigger publishes
what it received, a data driver publishes what it fetched, and a channel node
consumes them as {{token}} placeholders in copy, recipients, and URLs.
The properties panel lists what is available at that point in the flow, which is also what the AI writer receives when you draft content from a node. If a variable is not listed at a node, nothing upstream of it produces that value on that path.
What enrolls a person into the journey. Every journey needs at least one.
Fires when your system posts to the journey's generated URL. The panel gives you the URL, an authorization token, and a copyable cURL command, so you can test it before wiring anything up. Declare the request body parameters you intend to send; those become the variables downstream nodes can read.
Fires when a schedule elapses. Pick a schedule mode and a timezone, then fill in what that mode needs:
Fires when a named event arrives from the web tracker or events API. Configure the event name, which must match what you send.
Fires on a store or storefront event. Configure the Shopify store and the event type:
Time on Page and Scroll Depth ask for a number: how many seconds, or how far down the page.
The behavioral triggers were designed with storefront popups in mind, and popup delivery is not enabled yet. Until it is, pair these triggers with a delivery node that does exist, such as a Shopify Variant or an email, rather than expecting an overlay.
Checkout data does not arrive instantly, and guest checkouts have no email address attached at the moment the checkout is created. Give a recovery journey a wait of at least fifteen minutes after the checkout trigger before the first send, or it will fire on incomplete data.
Fires when a Meta Lead Ad form is submitted. Configure the Meta Marketing connector, and optionally narrow to a single page ID and form ID. Leave those blank to accept every form on the account.
Fires on a HubSpot CRM event. Configure the HubSpot connector and event type, then optionally a property and a property value filter so the journey only starts when that property changes to a value you care about.
These end a path by sending something. Each one needs its channel connected in the same environment.
Every channel node starts with a connector, which is the account it sends through. If the connector is missing, the node cannot run.
Configure the connector, send mode, to, from, and from name. Send mode decides the rest:
Recipients accept a literal address, a comma-separated list, or a {{variable}} such
as {{customer_email}} that resolves per person.
Configure the SMS or Twilio connector and the message body. Sender ID is optional and overrides the default number.
Configure the push and in-app connector, title, and body. Optional: deep link to open a specific screen, device token to target one device, image URL, and custom data as JSON for your app to read.
Configure the connector, recipient phone, and message type. Template messages are pre-approved and open a session, so they take a template, a template language, and optional template params as a JSON array. Free-form messages take a message body instead.
Configure the connector, contact ID, title, body, and layout. Optional: image URL, CTA label and CTA link, deep link, device token, and a message expiry in hours.
Configure the voice call connector and the TTS message to be spoken. Agent override and phone number override let one node deviate from the connector defaults.
Routes the flow true or false. Built in the condition builder over the variables available at that point, so it is the same set the properties panel lists. Conditions can be grouped and nested rather than kept flat.
Pauses the journey. Pick a wait mode:
Classifies with a model and routes on the result. Configure the AI provider connector, model, and prompt, then an output type:
Gates the flow on a date comparison. Configure a timezone and an operator (before, after, or between). Between also asks for an end date and time.
Splits traffic across variants A, B, C and beyond. Each variant takes a single-character label. Add and remove variants down to a minimum of two. The node runs in one of two strategies.
Manual, the default. Each variant takes a traffic percent. The last variant is
managed for you and marked Auto: it absorbs whatever is left so the total always
reaches 100, which is why its field is locked.
MAB, switched on with Enable MAB (Multi-Armed Bandit). Allocation stops being
something you set and becomes something the bandit learns. Variant percentages are
replaced by auto-allocated, and a MAB Stats panel shows impressions, conversions,
and posterior data per variant, refreshing every 30 seconds.
Success goal is the conversion signal the bandit optimizes toward. Until you set one, the bandit stays on an even split and learns nothing. Three kinds:
Event and Shopify goals take a goal window in hours, defaulting to 168 (seven
days). Send events to /api/events/trigger carrying the same visitor id.
A step goal only teaches the bandit when reaching that step is variant-dependent. If every participant funnels through it, such as a shared Checkout both arms lead to, the bandit cannot tell the variants apart and the split stays even. For a purchase, signup, or anything that happens after the journey, use Fires an event or Shopify order instead. The node warns you when it detects this.
Rollout controls how the bandit starts and how it serves:
current, meaning it begins from the manual
percentages above and moves only once data justifies it, or even, meaning it
begins from an even split and explores all variants equally.While there is too little data to be confident, the stats panel reports safe mode and falls back to a uniform split. That is the bandit protecting you, not a fault.
Persist Flow Output Path pins a participant to one arm. Tick Keep same variant for same upstream value. With it off, the same person can land in different variants on different runs, which contaminates any result you read.
When on, supply the field to pin against. Xenia takes a fast hash of that field's value
and routes on it, so the same value always resolves to the same variant. {{token}}
wrapping is stripped, so {{userId}} and userId are equivalent.
For Shopify, pin on payload.visitorId. Event and Shopify goals credit conversions
by visitor identity, so pinning on a different field than the goal matches means a
participant can be assigned one variant and have their conversion credited elsewhere.
Keep both on the visitor id.
Fetch data mid-journey so later nodes can use it.
Calls any HTTP endpoint. Configure the URL and HTTP method, then authorization:
Optionally add headers, body, and query params as JSON, plus a timeout in milliseconds.
Configure the Klaviyo connector and an operation. Depending on it: lookup by to choose how the profile is matched, a Klaviyo list, or an event name with optional event properties as JSON.
Configure the Contentful connector and select the entries to resolve.
Configure the Content Cloud connector and a content key for the resolve API and SDK. You can also paste entry IDs directly.
Configure the connector type and connector name, then the data object to read, a read mode, and an optional filter as JSON.
Loads the stored Shopify profile, orders, and engagement metrics for the person in the journey. No configuration, since it acts on whoever is in the run.
Checks whether the customer purchased since abandoning checkout, so a recovery send can be suppressed. Configure a fallback lookback in hours, used when the run carries no checkout timestamp to measure from.
Adds the customer to a price rule's eligibility list and outputs the coupon code for use in a message. Configure the price rule, discount code, optional code prefix, start date, end or expiry, maximum total uses, and customer eligibility.
Runs several branches at once. Add and remove branches, then pick a failure mode:
Loops over each item in a collection. Configure the array to iterate and a batch size.
Rejoins paths that were split. Configure when this step runs:
Gives each incoming path its own follow-up. Configure the input lanes and the display, which shows one lane at a time to keep a busy canvas readable.
Each of these needs its connector configured in the same environment, and each needs an email field telling it which variable identifies the person.
Configure the audience and an operation: CHECK to test
membership, or ADD and REMOVE to change it.
Configure the Meta Marketing connector, audience ID,
and operation (ADD or REMOVE). Takes an email field and an optional
phone field for matching.
Sends a server-side conversion event. Configure the connector, event name, and action source. Optional: phone field, currency, value field for the amount, and event source URL.
Configure the HubSpot connector and email field, then the properties to write back.
Configure the connector, list ID, operation (ADD
or REMOVE), and email field. The list must be a static list.
Configure the connector, email field, deal name, pipeline, and deal stage. Amount is optional.
Shows saved Visual Editor page variants, and ends the path. Configure the Shopify store and the variants to serve. The list is ordered, and you move entries up and down to control precedence when several variants target the same page. See the Shopify Visual Editor.
Returns a custom HTTP response to the webhook caller, and ends the path. Configure the response status code, response message, and optional response headers as JSON.
This is what lets another system ask Xenia a question and get an answer straight back: it calls the journey, the journey runs, and the response step replies.
Runs another journey as a step, so shared logic lives in one place. Start by importing from an existing journey, then set the guards that stop it running away:
Composition is cycle and depth guarded, so a sub-journey cannot recurse forever. The cooldown and maximum spawn settings are the per-customer half of that protection. Set them deliberately on any event-driven sub-journey.
Any node's configuration can be saved to the Node Library and reused. In the properties panel, pick a saved instance for that node type and its fields are filled in.
Each journey carries a briefing: the plain language statement of what it does and who it targets. It is required before a journey can go to review, because it is what reviewers read to judge risk. Write it for a colleague who has not seen the canvas.
A journey is a draft while you build it, goes to review when you submit it, becomes approved when someone signs it off, is published when it goes live, and is stopped if you pause it.
Triggers invoke a journey only when its status is active. A draft journey in Production accepts nothing, which is the usual explanation for a webhook that works locally and appears dead in production.
Editing a live journey is allowed, and Xenia warns you when you do. Changes take effect only after republishing, so the running version is whatever was published last.