Documentation

Conditions reference

Branching primitives — if/then, switch/case, field checks, tags, scoring, filters.

A condition step evaluates context.variables and returns the next step ID. Conditions live in ConditionRegistry. Each one reads its parameters from step.config (or context.variables.stepConfig at runtime) and emits a ConditionResult with a passed flag, a nextStepId, and an optional branchPath label.

Built-in conditions

FieldTypeDescription
if_thenboolean branch

Evaluate one expression. Routes to thenStepId/trueStepId on true, elseStepId/falseStepId on false. Accepts either a flat {field, operator, value} config or a nested condition object.

switch_casemulti-way branch

Pick a branch from a list of cases. Config: field, cases: [{value, flowId}], defaultFlowId. Equality match against field's resolved value.

check_field_valuecomparator

Compare any context field against a literal. Config: field, operator, value, trueFlowId, falseFlowId. Operators include eq, neq, gt, lt, gte, lte, contains, in, regex (delegates to the shared validateValue util).

check_tag_existstag check

Test contact tags. Config: tags (comma-separated string or array), logic (any | all), trueFlowId, falseFlowId. Reads tags from context.variables.tags or context.variables.contact.tags.

check_engagement_scorescore gate

Compare a lead/engagement score against a threshold. Config: scoreThreshold, operator, timeframe, trueFlowId, falseFlowId. Reads from context.variables.engagementScore, .leadScore, or .contact.leadScore. If no score exists, calculates a basic one from available activity.

filter_contactsfilter gate

A pass/stop gate for the current contact. Same shape as check_field_value but the branches are continueFlowId and stopFlowId. Use it as an early exit in a campaign.

gotoredirect

Unconditional jump to another step. Useful for shared sub-flows.

always_executepassthrough

Always passes. Effectively a no-op branch — handy for placeholder slots in template flows.

ab_testexperiment split

Random-weighted branch. Use for A/B testing two action paths.

Operators

check_field_value, filter_contacts, and if_then (when used flat) all delegate to the shared validateValue utility. Operator names are normalized via mapOperatorToValidator. Common ones:

OperatorMeaning
eq / equals / ==Strict equality
neq / not_equals / !=Inequality
gt, gte, lt, lteNumeric / date comparison
containsSubstring or array-includes
inValue is in an array literal
not_inValue is not in an array literal
regexField matches a regular expression
is_empty / is_not_emptyNull/empty check
betweenNumeric range, value is [min, max]

Field paths use dot notation. contact.tags, triggerResult.source, pageVisit.url all work.

Examples

if_then

{
  "id": "branch-1",
  "type": "condition",
  "config": {
    "conditionType": "if_then",
    "field": "contact.country",
    "operator": "eq",
    "value": "US",
    "thenStepId": "us-flow-step",
    "elseStepId": "intl-flow-step"
  }
}

switch_case

{
  "id": "switch-plan",
  "type": "condition",
  "config": {
    "conditionType": "switch_case",
    "field": "contact.plan",
    "cases": [
      { "value": "free",       "flowId": "free-onboarding" },
      { "value": "pro",        "flowId": "pro-onboarding" },
      { "value": "enterprise", "flowId": "enterprise-onboarding" }
    ],
    "defaultFlowId": "default-onboarding"
  }
}

check_engagement_score

{
  "id": "score-gate",
  "type": "condition",
  "config": {
    "conditionType": "check_engagement_score",
    "scoreThreshold": 75,
    "operator": "gte",
    "timeframe": "30d",
    "trueFlowId": "send-to-sales",
    "falseFlowId": "stay-in-nurture"
  }
}

filter_contacts

{
  "id": "must-have-email",
  "type": "condition",
  "config": {
    "conditionType": "filter_contacts",
    "field": "contact.email",
    "operator": "is_not_empty",
    "continueFlowId": "send-step",
    "stopFlowId": null
  }
}

stopFlowId: null ends the flow when the filter rejects.

DynamicQuery-backed segmentation

The filter_contacts condition handles single-field gates. For complex audience segmentation (multi-field AND/OR, nested conditions, aggregations) call into the Dynamic Query module from a custom action — the same query engine powers CRM audience segments and rule-engine rules.

Conditions are pure — they read from context but never mutate the database. To act on the result of a comparison, branch into an action step.