XeniaXenia Docs

Triggers

PreviousNext

The seven nodes that start a journey, and what each one brings with it.

A trigger is what enrols a person into the journey. Every journey needs at least one, and the trigger you choose decides what the journey can ever know about the person: everything downstream reads facts that the trigger, or a data driver under it, produced.

Webhook

Starts the journey when an outside system posts to a URL Xenia generates for this node. Use it for your own backend, a form, or a tool with no Xenia connector.

Pair it with a Webhook Response node and the journey becomes a synchronous API: the caller waits, the journey decides, the response node answers.

Configure

SettingWhat it does
Body parametersThe body fields you expect. Each name becomes a variable downstream
Webhook IDThe id callers post to. Generated by the node, not typed
Authorization tokenThe shared secret callers must present. Generated with Generate Token

Required: an authorization token. The panel also gives you the URL and a copyable cURL command, so you can test the trigger before wiring anything to it.

Produces

One variable per declared body parameter, with the type you gave it.

Watch out

  • Declaring the body parameters is what makes them readable. A field you post but did not declare is not a variable and cannot be tested.
  • Prefer a connected service's own trigger when one fires for the same event. The customer then arrives already identified.

Scheduler

Starts the journey on a clock: once, on a repeat, or on a cron expression. This is the trigger for batch work, such as a weekly digest or a dated campaign.

Configure

SettingWhat it does
Schedule modeOne time, every X minutes, every X hours, daily, weekly, or cron
TimezoneIANA timezone the schedule is read in, for example America/New_York
Scheduled date/timeWhen to fire, for one-time mode
Interval1 to 59 minutes, or 1 to 23 hours, for the every-X modes
Day of weekFor weekly mode
Time of dayHH:MM, for daily and weekly modes
Cron expressionA Spring cron expression, for example 0 0 9 * * *

Required: a schedule mode. One-time mode also requires the date and time; cron mode also requires the expression.

Produces

{{trigger_timestamp}}, {{trigger_timezone}}.

Watch out

  • A scheduled run brings in no customer, so it produces no customer facts at all. Load the people yourself with an Audience Lookup or an API Request before any node that needs an address.
  • The timezone is this node's, never the customer's: everyone fires at the same wall-clock moment. Left blank it falls back to the server's timezone, so set it.
  • For a per-customer pause inside a running journey, use Wait / Delay, not a second trigger.

Event Trigger

Starts the journey when a named event arrives from the web tracker or the events API. Use it for on-site and in-app behaviour you already track.

Not shown in Shopify-billed workspaces.

Configure

SettingWhat it does
Event nameThe event to match, exactly as your site or app sends it
Custom parametersExtra fields sent with the event. Each name becomes a variable

Required: the event name.

Produces

{{event_name}}, {{event_type}}, {{event_timestamp}}, {{email}}, {{visitor_id}}, {{customer_id}}, {{device_id}}, {{user_id}}, {{url}}, {{referrer}}, and the campaign attribution the event carried: {{utm_source}}, {{utm_medium}}, {{utm_campaign}}, {{utm_content}}, {{utm_id}}. Plus one variable per declared custom parameter.

Watch out

  • The event name must match what is actually sent. There is no list to pick from, so confirm the name against your web tracker setup.
  • The customer arrives as ids and an email only. For order history or spend, add Enrich Customer or an Audience Lookup before any rule that tests them.

Shopify Trigger

Starts the journey on a store or storefront event, with the customer already identified and the order or cart attached. Needs a connected Shopify store.

Configure

SettingWhat it does
Shopify shopThe connected store to listen to
Event typeWhich store event starts the journey
ThresholdSeconds for time.on.page, or scroll percent for scroll.depth

Required: the store and the event type.

Events

EventFires when
order.created, order.paid, order.cancelledAn order changes state
checkout.startedA shopper begins checking out
customer.created, customer.updatedA customer record is added or changed
product.updateA product changes
page.viewA shopper loads a storefront page
exit.intent, add.to.cart, time.on.page, scroll.depthA shopper behaves a certain way on the storefront

Produces

{{shopDomain}} and {{eventType}} always, and then a set that depends entirely on the event:

EventWhat it carries
order.*The full order: totals, currency, financial and fulfilment status, tags, timestamps, the customer, the shipping address, and the first line item's title, price, quantity, SKU and ids. order.cancelled adds {{payload.cancel_reason}} and {{payload.cancelled_at}}
checkout.startedCheckout id and token, email, the customer's email and first name, totals, currency, created date
customer.created, customer.updatedId, email, first and last name, created date
product.updateId, title, status, updated date
page.viewPage URL and type, visitor id, device type, new-visitor flag, referrer, UTM source, medium and campaign, locale, logged-in flag, customer id, cart total and item count
Behavioural eventsThe raw {{payload}} only

Watch out

  • checkout.started may arrive with an empty email, because a guest has not necessarily typed one yet. Guard any send that depends on it, and give a recovery journey a wait of at least fifteen minutes before the first send, since checkout data does not arrive instantly.
  • Behavioural events are emitted by the storefront pixel and need their threshold set. Nothing fires where the pixel is not installed.
  • On page.view the visitor is anonymous: no email, no phone, no name, and a customer id only when they happen to be logged in. Sort them on what the page view does carry, and end each path on a Shopify Variant or a Shopify Popup.
  • Shopify Variant is hard-blocked on a page.view trigger. With this node set to any other event, every Shopify Variant on the canvas is an error and the journey will not publish.

Meta Lead Trigger

Starts the journey when someone submits a Meta Lead Ad form, on submission rather than on a later sync. Needs a connected Meta account.

Not shown in Shopify-billed workspaces.

Configure

SettingWhat it does
Meta connectorThe connected Meta account
Page IDNarrow to one Facebook page. Blank accepts every page on the account
Form IDNarrow to one lead form. Blank accepts every form
Lead fieldsThe form's questions, fetched from Meta. Each becomes a variable

Required: the connector.

Produces

{{lead.id}}, {{lead.created_time}}, {{lead.form_id}}, and one lead. prefixed variable per fetched form question.

Watch out

  • Only the three built-in lead fields exist until you fetch the form's questions into the node. Fetch them first, or the journey cannot test anything the lead answered.
  • What a lead can be tested on is whatever that specific form asks. Two journeys on two forms do not have the same variables.
  • For a form on your own site, use a Webhook trigger instead.

HubSpot Trigger

Starts the journey when a HubSpot contact, deal, or company changes. Needs a connected HubSpot account.

Configure

SettingWhat it does
HubSpot connectorThe connected HubSpot account
Event typeWhich CRM change starts the journey
Property filterOnly fire when this property changes, for propertyChange events
Property value filterOnly fire when the changed property takes this value

Required: the connector and the event type.

Event types are contact.creation, contact.propertyChange, contact.deletion, deal.creation, deal.propertyChange, company.creation, and company.propertyChange.

Produces

{{eventType}}, {{portalId}}, {{objectId}}, {{subscriptionType}}, {{objectTypeId}}, {{propertyName}}, {{propertyValue}}, {{changeSource}}, plus enrichment that depends on the object:

  • Contact events add {{email}}, {{customer_email}}, {{firstName}}, {{lastName}}, {{phone}}, {{lifecycleStage}}, {{leadStatus}}.
  • Company events add {{company_name}}, {{company_domain}}, {{city}}, {{region}}, {{country}}, {{industry}}, {{company_type}}, {{lifecycleStage}}, {{phone}}.
  • Deal events add nothing.

Watch out

  • A deal.* event makes no properties testable, so a deal journey knows the deal changed and nothing about the person. Add a lookup before any node that needs an address, and do not plan a branch on deal fields.
  • contact.deletion runs no enrichment, so the contact properties are absent rather than empty.
  • A propertyChange event fires on every change unless you name the property to filter on.
  • A batch from HubSpot can mix creation and property-change events, and creation is not necessarily first.

Personalization Resolve

Starts the journey when a storefront or app calls the personalization resolve API for a content key, and the journey decides what fills that slot. See Personalization API for the developer side.

Not shown in Shopify-billed workspaces.

Configure

SettingWhat it does
Content keyThe key everything wired beneath this node resolves under. Defaults to the node id
Persistence variableThe fact returning visitors are bucketed by, so one person keeps seeing one variant. Blank uses the visitor id
Custom parametersExtra fields passed in the resolve() call's data argument. Each becomes a variable

Required: the content key.

Produces

Thirteen fields arrive on every call with no setup: {{path}}, {{query}}, {{deviceId}}, {{visitorId}}, {{customerId}}, {{email}}, {{url}}, {{referrer}}, {{utmSource}}, {{utmMedium}}, {{utmCampaign}}, {{utmContent}}, {{utmId}}. Plus one variable per declared custom parameter.

Watch out

  • The content key must match the key the site actually asks for, or nothing resolves.
  • The names are camelCase here, unlike the Event Trigger's snake_case equivalents. That difference comes from the SDK wire contract.
  • Browser and PHP clients read those fields off the request. A Node or SSR client binds them once when it is created, so empty values on a server-rendered page mean that binding is missing.
  • {{query}} is one flat object, not a variable per query-string key.