Stage scope: this stage covers only what Build and Manage Wix Automations lists; do not perform any workflow that needs a guide marked "not yet published". "Stage" and "not yet published" describe how this skill is being rolled out; never mention them to the user. Explain a limit in product terms: what can't be done through the API here and where the user can do it instead (for example, in the automations builder).
{{…}}TL;DR
{{expression}}; fields via var("dotted.path") (double quotes, one argument); arguments separated by ;; string literals in double quotes and URI-encoded.eq/gt/gte/lt/lte take NUMBERS only (strings → stringEq, dates → date*); if()'s first argument is boolean. There are no operators.arrayMap(array;"path"), aggregate with array*. A single-value field can never be filled from an array — ask the user which item.| Form | Example |
|---|---|
| Literal | {{"text"}}, {{10}}, {{true}}, {{["a","b"]}} |
| Variable | {{var("contact.name.first")}} |
| Function | {{concat(var("a");" - ";var("b"))}} |
| Text with embedded expressions (string fields only) | Hi {{var("contact.name.first")}}, your total is {{toString(var("total"))}} |
MUST:
var("path") with ONE argument — {{fieldName}} is not supported.var('x') is an unknown variable to the builder). In JSON escape them: "{{var(\"contact.email\")}}".; between arguments, no leading/trailing/double ;, balanced parentheses. No whitespace outside string literals — {{ concat(… or sum( 1;2) is unreadable to the builder.5, -3, 12.5). Never 0.5, .5, -0.25, 05 or 1e3 — the builder's parser rejects them (conditions, filters, delays and rate limits stop loading). Write divide(1;2) instead. Percentages follow the same rule: 10% of x is divide(x;10) and 15% is divide(multiply(x;15);100), never multiply(x;0.1).var("triggered-emails-1.messageId")); a space inside a segment is invalid.{{…}} exactly as encodeURIComponent does — this is how the builder's panels and the platform store them: "a@b.com" → "a%40b.com", "50%" → "50%25", "New York" → "New%20York", "&" → "%26". Letters, digits and - _ . ! ~ * ' ( ) stay as they are, so uuids and arrayMap paths are unchanged. Do NOT encode var("…") paths (except in trigger filters, where the filter panel encodes the path too — Automations Trigger Configuration) or text outside {{…}}, nor a date-time literal in a formula field (§2). Decode literals when you read an existing automation. Action formula fields display literals as stored, so in string fields keep fixed text outside {{…}} (Hi {{var("contact.name.first")}}, welcome!) rather than in concat("…").Prefix rules: trigger fields have no prefix; action outputs "<namespace>.<field>" (namespace = the step's namespace, e.g. createTask-1); set variables "setVariable.<key>"; identity enrichment "contact.…" / "member.…". siteInfo.* is not available — don't reference it.
sum(n;n;…) · subtract(n;n) · multiply(n;n;…) · divide(n;n) · average(n;…) · min(n;…) · max(n;…) · median(n;…) · mod(n;n) · round(n;decimals) · abs(n) → number · eq(n;n) · gt(n;n) · gte(n;n) · lt(n;n) · lte(n;n) → boolean (numbers only)arraySize(a) · arraySum(a) · arrayMultiply(a) · arrayAverage(a) · arrayMin(a) · arrayMax(a) · arrayMedian(a) → number · arrayMap(a;"item.path") → arrayconcat(s;s;…) · substring(s;start;length) (0-based) · lower(s) · upper(s) → string · stringLen(s) → number · stringEq(a;b) · stringHasSubString(s;sub) · startsWith(s;prefix) · endsWith(s;suffix) · isEmptyString(s) → booleanhour(dt) · minute(dt) · year(d) · month(d) · day(d) → number · weekDay(d) → lowercase day name · dateEq/dateBefore/dateAfter(d;d) (calendar date) · dateTimeEq/dateTimeBefore/dateTimeAfter(dt;dt) → boolean · addToDate(d;years;months;days) · subtractFromDate(d;years;months;days) → date-time · now() → date-time stringtoString(v) → string · toNumber(v) → numberif(bool;then;else) · and(b;b;…) · or(b;b;…) · not(b) · isEmpty(v) (any value, incl. arrays) → boolean (if → its branches' value)Arity (write exactly these counts; the builder flags missing and extra arguments for fixed-arity functions): var, not, toString, toNumber, upper, lower, stringLen, abs, isEmptyString, isEmpty, every array* aggregate = 1 · comparisons, round, subtract/divide/mod, arrayMap = 2 · if, substring = 3 (always pass the length) · addToDate/subtractFromDate = 4 · now = 0 · and/or/concat/sum/multiply ≥ 2 · min/max/average/median ≥ 1.
Argument types the builder enforces (convert with toString()/toNumber()):
| Parameter | Accepts |
|---|---|
number (math, comparisons, substring offsets, date offsets) | number literal, number/integer var, number-returning function; wrap a string format: number var (money values) in toNumber() — the platform rejects it bare |
string (text functions, concat) | string literal/var/function — never a number or boolean (wrap in toString()) |
boolean (if arg 1, and, or, not) | comparison, boolean var, isEmpty/isEmptyString/startsWith/… |
date (year, month, day, weekDay, dateEq/Before/After, addToDate…) | a var whose schema has format: date or date-time, a "YYYY-MM-DD" literal, or a function (now(), addToDate(…)) |
date-time (hour, minute, dateTimeEq/Before/After) | a var with format: date-time, a function, or an ISO date-time literal — a format: date var or plain-string var is rejected |
array (array* functions, isEmpty) | array var or arrayMap(…); no other function takes an array argument |
An encoded date-time literal ("2026-12-25T10%3A00%3A00Z") is not recognized as a date in a formula field — pass a "YYYY-MM-DD" literal or a function, or make the whole field a plain ISO value (§4). This exception is for formula fields only: in a CONDITION the panel itself writes date-time literals encoded and reads both forms (§2 of Automations Conditions (not yet published)).
Semantics: stringEq and stringHasSubString are case-insensitive (normalize with lower() if it matters). Booleans: use the value directly (if(var("isVip");…), not(var("isVip"))), never eq(var("isVip");true).
Never use in a formula field (the builder flags them as unknown functions):
toEpoch, arrayFilter, hasSubstring, textWithExpressions, contains, arraySome, arrayEvery, arrayIncludesAnyOf/AllOf/Only, stringContains, numberContains, boolEq, numberEq/numberGt/numberGte/numberLt/numberLte. (Several of these ARE the condition vocabulary — §2 of Automations Conditions (not yet published) — and contains/arraySome the trigger-filter vocabulary.)
Do not exist (never guess): replace, replaceAll, trim, split, join, indexOf, regex/match, ceil, floor, parseInt, parseFloat, random, filter, reduce, sort, switch, loops, try/catch, coalesce, formatDate, formatNumber, formatCurrency, titleCase, add, addDays, equals.
if() needs a boolean first argumentValid first arguments: a comparison (eq, gt, stringEq, dateBefore, startsWith, …), a genuinely boolean field, or and/or/not/isEmptyString/isEmpty.
In number and boolean target fields BOTH branches must return exactly the field's type — a number literal/var/function for a number field. A nested if as a branch counts as "any" and is flagged there: wrap it (toNumber(if(…))) or, for booleans, use and/or. Nested if is fine in string fields.
{{if(stringEq(var("status");"active");"Active";"Inactive")}}{{if(or(isEmpty(var("contact.name.first"));isEmptyString(var("contact.name.first")));"there";var("contact.name.first"))}}{{if(var("status");…)}} when status is a string · ❌ {{if("active";…)}}{{…}}; no expression may return an array.format: number) — Exactly ONE {{…}} covering the whole value, returning a number — or a plain number literal. No surrounding text.{{…}} returning boolean — or true/false.{{}} (2026-12-25T16:00:00Z), or ONE expression: a function (now(), addToDate(…)) or a var. For a date-time field the var must be format: date-time — wrap a format: date var as addToDate(var("d");0;0;0).{{var("…")}} of the same shape.dynamicValuesOptions.enabled in the UI schema — Literal only — no {{…}} (Automations Action Configuration §3).A strict dynamic field requires the exact return type/format. skipActionExpression is "{{true}}" or absent.
var("items[0]"), var("items.0.name"), var("items[0].name") are all invalid. Don't invent firstItem/items.id helper paths either.{{arrayMap(var("order.items");"product.name")}} — second argument is a quoted literal path (never $_ or an expression).{{arraySize(var("lineItems"))}}, {{arraySum(arrayMap(var("lineItems");"totalPrice.value"))}}. Never arraySum(var("items.price")) — a path cannot cross an array boundary.join; an arrayMap result can't go into concat or a string field.arraySum/arrayMin/arrayMax/arrayMedian/arrayMultiply fail at runtime.does the order contain X) belong in a condition (§3 of Automations Conditions (not yet published)) or, for complex logic, a code condition.date* compare calendar dates, dateTime* instants (argument formats: §2). addToDate/subtractFromDate offset by whole years/months/days.{{dateAfter(var("d");subtractFromDate(var("x");0;0;7))}}. Day differences can't be computed renderably (no toEpoch) — use a DELAY, such a comparison, or a code condition.dateEq(var("birthdate");now()). Compare month and day: {{and(eq(month(var("contact.birthdate"));month(now()));eq(day(var("contact.birthdate"));day(now())))}} — in a formula field; as a condition use code or a boolean set-variable (§4 of Automations Conditions (not yet published)).{{dateAfter(var("order_date");concat(toString(year(var("order_date")));"-10-31"))}}. Use year(now()) only when the rule is about the current calendar year.{{or(and(eq(month(var("d"));12);gt(day(var("d"));25));and(eq(month(var("d"));1);lt(day(var("d"));5)))}}; pick gt/gte from the user's wording.{{toString(month(var("d")))}}/{{toString(day(var("d")))}}/{{toString(year(var("d")))}} in a string field.toString() numbers/booleans before text functions; toNumber() string format: number fields before math; neither converts arrays.
{{if(startsWith(var("price");"%24");substring(var("price");1;subtract(stringLen(var("price"));1));var("price"))}} ("%24" is the encoded "$").{{upper(substring(var("t");0;1))}}{{lower(substring(var("t");1;subtract(stringLen(var("t"));1)))}}.{{}} and parentheses, ; separators, double-quoted strings, no whitespace outside strings, no 0.x/.x/exponent numbers.substring 3, round 2).eq/gt…, strings to text functions (toString numbers), dates with the right format, arrays only to array*/isEmpty; if arg 1 boolean and, in number/boolean fields, both branches of the field's type; arrayMap arg 2 a literal path.var() path exists in the aggregated schema of THIS step (ancestors only). If the unknown path has an array prefix (items.id where items is an array), element access is inexpressible — stop, don't respell.$_ appears only inside arraySome/arrayEvery predicates (conditions/filters), bare (never var($_) or $_.x).Last updated: 13 October 2026