Sequences
Build automated drip campaigns with delays, conditions, and event-based triggers.
Sequences are automated email workflows that send a series of emails to contacts over time. They are the core of Kraiter's automation capabilities — use them for onboarding flows, nurture campaigns, re-engagement series, and more.
A sequence is defined using a YAML format that specifies triggers, steps, delays, conditions, and exit conditions.
Creating a sequence
Create (or replace) a sequence with upsert, keyed by a sequence ID. Provide a name and the YAML definition as content:
const sequence = await kraiter.sequences.upsert('onboarding', {
name: 'onboarding',
content: `
trigger:
event: signup.completed
steps:
- action: email
template: welcome-email
- action: delay
duration: 1d
- action: email
template: getting-started
- action: delay
duration: 3d
- action: condition
property: contact.properties.hasCompletedOnboarding
operator: equals
value: true
onTrue: exit
- action: email
template: onboarding-reminder
`,
});YAML format
The sequence definition has three top-level keys: trigger, steps, and optionally exitConditions.
Trigger
The trigger determines how contacts are enrolled in the sequence. Every sequence must declare an event-based trigger — a sequence submitted without a trigger event is rejected. Contacts are enrolled automatically whenever a matching event is tracked for them:
trigger:
event: purchase.completedSteps
Steps are executed in order for each enrolled contact. There are three step types:
Email step
Sends an email using a named template:
- action: email
template: welcome-emailThe template must exist before the sequence is activated. The email is sent using the contact's email address and their properties are available as Liquid variables.
Delay step
Pauses the sequence for a specified duration before continuing to the next step:
- action: delay
duration: 3dSupported duration units:
| Unit | Example | Description |
|---|---|---|
m | 30m | Minutes |
h | 2h | Hours |
d | 3d | Days |
w | 1w | Weeks |
You can combine units: 1d12h means one day and twelve hours.
Condition step
Evaluates a condition and branches based on the result. If the condition is true, the onTrue action is taken; otherwise, the sequence continues to the next step.
- action: condition
property: contact.properties.isVip
operator: equals
value: true
onTrue: skipAvailable actions for onTrue:
- exit — Remove the contact from the sequence
- skip — Skip the next step and continue
Condition operators:
| Operator | Types | Description |
|---|---|---|
equals | all | Exact match |
notEquals | all | Not equal |
contains | string | String contains substring |
greaterThan | number, date | Greater than |
lessThan | number, date | Less than |
exists | all | Property has a value |
notExists | all | Property has no value |
You can also check segment membership in a condition:
- action: condition
segment: high-value-customers
onTrue: exitExit conditions
Exit conditions are evaluated before each step. If any exit condition is true, the contact is removed from the sequence immediately. This is useful for stopping a sequence when the contact's situation changes.
exitConditions:
- property: contact.unsubscribed
operator: equals
value: true
- property: contact.properties.hasConverted
operator: equals
value: trueComplete example
Here is a full sequence definition for a trial expiry campaign:
trigger:
event: trial.started
exitConditions:
- property: contact.properties.plan
operator: notEquals
value: "trial"
steps:
- action: email
template: trial-welcome
- action: delay
duration: 3d
- action: email
template: trial-tips
- action: delay
duration: 4d
- action: condition
property: contact.properties.activatedFeature
operator: equals
value: true
onTrue: skip
- action: email
template: trial-feature-prompt
- action: delay
duration: 5d
- action: email
template: trial-expiring-soon
- action: delay
duration: 2d
- action: email
template: trial-expiredThis sequence:
- Sends a welcome email immediately when a trial starts
- Follows up with tips after three days
- Checks whether the user has activated a feature — if yes, skips the prompt
- Sends an expiry warning at day twelve
- Sends a final email at day fourteen
- Exits early if the contact upgrades from the trial plan
Enabling and disabling sequences
A sequence is controlled by a single enabled flag rather than a multi-state lifecycle. While disabled, no contacts are enrolled and no steps are processed. Toggle it with update (a partial metadata update):
// Enable the sequence so it starts enrolling and processing contacts
await kraiter.sequences.update('onboarding', { enabled: true });
// Disable it — enrolment and step processing stop
await kraiter.sequences.update('onboarding', { enabled: false });Editing a sequence's content with upsert never flips the enabled flag implicitly — enabling and disabling is always an explicit action. While a sequence is disabled, contacts already partway through remain at their current step and resume when it is re-enabled.
Enrolling contacts
Enrolment is automatic and event-driven: when you track the sequence's trigger event for a contact, that contact is enrolled. There is no separate manual-enrolment endpoint — to enrol a contact, track the trigger event for them:
// Enrols the contact into any sequence triggered by 'signup.completed'
await kraiter.events.track({
email: 'alice@example.com',
name: 'signup.completed',
});A contact can only be active in the same sequence once at a time. If they have already completed or exited the sequence, tracking the trigger event again re-enrols them.
Dry-run testing
Before activating a sequence, test it with a dry run. A dry run simulates the sequence execution without actually sending emails:
const result = await kraiter.sequences.dryRun('onboarding', {
contactId: 'CONTACT_ID',
});
console.log(result.steps); // Shows what would happen at each stepThis helps you verify that conditions, delays, and exit conditions behave as expected before going live.