You are viewing beta documentation for Formie 4.x.
Developers

Reference Tokens

Reference tokens are Formie's variable syntax for inserting dynamic submission, form, site, and user values into settings and content. They resolve when Formie processes a submission — not when your Twig template renders.

Use the variable picker in the control panel wherever it is available, or build the same tokens from Twig or PHP when you override settings in templates.

Where Tokens Are Used

Reference tokens appear anywhere Formie parses variable-aware content, including:

  • Submit action messages, error messages, and other form rich-text settings
  • Email notifications — subject, body, recipients
  • PDF templates
  • Integration mapping fields (CRM, payments, messaging, and so on)
  • Hidden field default values, calculations formulas, client event payloads, and spam keyword lines

Calculations use the same field-reference tokens, but the formula editor is not Twig. See Calculations for expression syntax.

How Tokens Work

A token is a braced string Formie stores in settings, then resolves against the current submission:

{target:identifier}

Examples:

TokenResolves to
{submission:uid}The submission UID
{form:name}The form title
{field:a1b2c3}A field value (stable field reference, not the handle)
{allFields}HTML summary of all fields

Formie resolves tokens in stored content at submit time (or when previewing with sample submission data in the control panel). Twig is not evaluated inside completion messages, notification bodies, or similar settings.

That means these do not work in those settings:

  • Twig output syntax such as {{ submission.uid }}
  • A field handle in place of the stable field reference inserted by the variable picker

Use reference tokens instead — the same strings the variable picker inserts.

Inline Defaults

Add a fallback when the resolved value is empty:

{submission:uid|pending}

Transforms and Metadata

Some contexts support transforms and extra metadata on the token body:

{timestamp;transform=format;preset=isoDate}
{field:child-reference;scope=all}

The variable picker configures these for you. When building tokens manually, match the picker output. See Calculations for transform examples on field references.

Built-in Tokens

These tokens are available on every form. In the control panel, open the variable picker to insert them. From Twig, use craft.formie.ref() with the target and identifier shown in the Twig column.

Summary Selectors

LabelTokenTwig
All form fields{allFields}craft.formie.ref('allFields')
All non-empty fields{allContentFields}craft.formie.ref('allContentFields')
All visible fields{allVisibleFields}craft.formie.ref('allVisibleFields')

Form

LabelTokenTwig
Form name{form:name}craft.formie.ref('form', 'name')
Form handle{form:handle}craft.formie.ref('form', 'handle')

Submission

LabelTokenTwig
Submission title{submission:title}craft.formie.ref('submission', 'title')
Submission ID{submission:id}craft.formie.ref('submission', 'id')
Submission UID{submission:uid}craft.formie.ref('submission', 'uid')
Submission URL{submission:url}craft.formie.ref('submission', 'url')
Submission date{submission:date}craft.formie.ref('submission', 'date')
Submission status{submission:status}craft.formie.ref('submission', 'status')

Site

LabelTokenTwig
Site name{site:name}craft.formie.ref('site', 'name')
Site handle{site:handle}craft.formie.ref('site', 'handle')
Site URL{site:url}craft.formie.ref('site', 'url')
Site language{site:language}craft.formie.ref('site', 'language')

System

LabelTokenTwig
System name{system:name}craft.formie.ref('system', 'name')
System email{system:email}craft.formie.ref('system', 'email')
System reply-to{system:replyTo}craft.formie.ref('system', 'replyTo')

Current User

Values reflect the logged-in user when the submission is made, or the submission's linked user when applicable.

LabelTokenTwig
User IP address{user:ip}craft.formie.ref('user', 'ip')
User ID{user:id}craft.formie.ref('user', 'id')
User email{user:email}craft.formie.ref('user', 'email')
Username{user:username}craft.formie.ref('user', 'username')
User full name{user:fullName}craft.formie.ref('user', 'fullName')
User first name{user:firstName}craft.formie.ref('user', 'firstName')
User last name{user:lastName}craft.formie.ref('user', 'lastName')

Current Date/Time

LabelTokenTwig
Current date/time{timestamp}craft.formie.ref('timestamp')

Use transform metadata for formatted output — for example {timestamp;transform=format;preset=isoDate}. The picker exposes the available format options.

Environment

Environment references are disabled by default. Add only safe names to referenceEnvironmentAllowlist in config/formie.php:

return [
    'referenceEnvironmentAllowlist' => ['PUBLIC_CONTACT_EMAIL'],
];

The picker lists only those names and never includes their values. A reference to any other name is denied. Build an allowlisted token from Twig with:

{{ craft.formie.ref('env', 'PUBLIC_CONTACT_EMAIL') }}

Field Tokens

Field values use a stable field reference, not the field handle. Each field on a form has a reference ID that stays consistent when the handle changes.

ApproachWhen to use
Variable picker (control panel)Default — inserts {field:reference} or {field:reference:selector} for you
craft.formie.refField(form, 'handle')Twig overrides when you know the field handle
craft.formie.ref('field', 'reference', 'selector')Advanced — when you already have the reference string
{# Resolves the field handle to the stable reference token #}
{{ craft.formie.refField(form, 'email') }}

{# Nested or composite field selector #}
{{ craft.formie.refField(form, 'address', 'city') }}

Some fields expose multiple selectors, such as Name, Address, Date/Time and Table columns. Nested Group and Repeater fields use the child field’s own stable reference rather than a selector on the parent. Repeater children also include an explicit scope, such as {field:child-reference;scope=all}. Use the Variable Picker to see the values and scopes available for the current field.

Do not type {field:myFieldHandle}. Handles are for templates and refField() — stored tokens must use the field reference.

Custom Variables

Register project-specific variables with namespaced {custom:vendor/name} tokens. See Custom variable sources.

{{ craft.formie.ref('custom', 'acme/campaign') }}

Building Tokens from Twig

Use craft.formie.ref() and craft.formie.refField() when overriding form settings in templates — for example a dynamic completion message:

{% set form = craft.formie.forms.handle('contactForm').one() %}

{% do form.setSettings({
    successMessage: 'Thanks! Your reference is ' ~ craft.formie.ref('submission', 'uid'),
}) %}

{{ craft.formie.renderForm(form) }}

craft.formie.ref(target, identifier, selector, options) parameters:

ParameterDescription
targetToken target — for example submission, form, allFields, field, custom
identifierTarget-specific identifier — omit for summary tokens such as allFields
selectorOptional field selector (third segment of a field token)
optionsOptional metadata (transforms, scopes) and default for inline fallbacks

Concatenate the returned string with other text using Twig's ~ operator.

Resolving Tokens in Twig Templates

When you already have a submission in a Twig template and want the resolved value (not the token string), use:

{{ craft.formie.parseContent('{submission:uid}', submission) }}
{{ craft.formie.parseValue('{field:a1b2c3}', submission) }}

These run reference resolution immediately in the current request — unlike tokens stored in form settings, which resolve at submit time.

PHP

use verbb\formie\helpers\References;

// Build a token
References::token('submission', 'uid');
References::field('address-reference', 'city');
References::field('repeater-child-reference', metadata: ['scope' => 'all']);

// Resolve a token against a submission
References::parseContent('{submission:uid}', $submission);
References::parseValue('{field:a1b2c3}', $submission);

Exact Values and Text

Use exact resolution for a slot that expects a value, such as an integration mapping. A Name field returns its NameFieldValue, and a relation field returns its normalized query. Use interpolation when the destination is text. It asks the field for its string representation and encodes replacements for the destination.

In PHP code that already has a Formie submission, create the context once and reuse it:

use verbb\formie\helpers\References;
use verbb\formie\references\ReferenceContext;
use verbb\formie\references\ReferenceOutputContext;

$context = ReferenceContext::forSubmission($submission);
$token = References::field($submission->getForm()->getFieldByHandle('name')->reference);
$result = References::resolveValue($token, $context);

if ($result->diagnostic !== null) {
    throw new \RuntimeException($result->diagnostic->value);
}

$name = $result->value;
$html = References::interpolateText('Hello ' . $token, $context, ReferenceOutputContext::Html);

Four objects carry the information used to resolve a reference:

ObjectPurpose
ReferenceDefinitionDescribes the source shown to editors in the Variable Picker.
ReferenceExpressionHolds the parsed token.
ReferenceContextSupplies the form, submission and other values needed to resolve it.
ResolvedReferenceHolds the result, field/definition metadata and any diagnostic.

These objects are immutable. Call requireValue() when your code cannot continue without a valid result; it throws ReferenceException on a resolution error. Error messages omit submitted values and secrets.

Output Contexts

ContextReplacement behaviour
PlainTextField-owned string value; no HTML interpretation
HtmlEncode HTML special characters once; registered summary blocks use their trusted field templates
EmailHeaderReject carriage returns, line feeds and NUL characters
UrlComponentPercent-encode a value inserted into an authored URL component
StructuredDataEmit JSON-safe data with JSON encoding; whole native values should use exact resolution

Do not pre-escape values or interpolate once and then reinterpret the result as another reference template. Submitted values containing $SECRET, braces or Twig remain data. Authored Twig template files and explicit template fields have their own rendering contract; the reference grammar never executes Twig or PHP.

Stored Slots

Consumers declare whether a slot accepts reference, text or literal. Integration mappings persist this distinction:

['kind' => 'reference', 'value' => '{field:instance-reference}']
['kind' => 'text', 'value' => 'Contact: {field:instance-reference}']
['kind' => 'literal', 'value' => '{This stays literal}']

The Variable Picker's field mode stores an exact reference. Its custom value editor stores interpolated text. Provider options store literals. The custom editor’s Use text exactly as entered action switches to a literal input; Use variables in text restores interpolation. A literal never becomes executable because it contains braces.

Grammar and Diagnostics

Inline field interpolation uses getValueForReference() and its EVENT_MODIFY_VALUE_FOR_REFERENCE event before context-specific encoding. It does not fire EVENT_MODIFY_VALUE_AS_STRING. Text transforms operate on the returned reference value without asking the field to convert it again. Exact untransformed value resolution retains the native field value; structured-data interpolation uses the field's data projection.

The grammar uses {source:identifier:selector;key=value|default}. The selector applies to fields. transform names a registered transform; scope, index and rows select collection values. Metadata values and defaults are percent-encoded by the serializer, so ;, |, braces, plus signs and percent signs round-trip. Version 1 is implicit; ;v=1 is accepted and unsupported versions produce an invalid-expression diagnostic. Use References::token() or ReferenceParser::serialize() instead of concatenating untrusted strings.

Exact field references identify one persisted form-field instance. Handles are secondary, form-local identifiers; ambiguous handles fail instead of choosing the first match. Fixed and nested child fields have their own references. A repeater-child reference must either declare an explicit collection scope in its token (first, last, index, all, count or rows) or receive the current row through ReferenceContext::forSubmission($submission, rows: [$parentReference => 0]). Row indices are zero-based; the picker displays one-based row numbers. Table columns remain selectors on their persisted Table field and never become synthetic fields.

Deleted fields produce missingField; unscoped repeater children produce missingRowScope; undeclared selectors produce invalidSelector. Unknown sources and transforms produce unknownSource and unknownTransform. A default replaces a successfully resolved empty value (null, an empty string or list, or a field value that declares itself empty). Zero and false remain values. It does not hide a deleted field, missing extension or forbidden source.

Plain-text and HTML interpolation leave an unknown, non-Formie brace token unchanged. An unresolved token for a known Formie source records a warning on ReferenceContext::diagnostics and contributes its authored default or an empty string. Exact-value resolution and strict EmailHeader, UrlComponent and StructuredData output contexts throw when the reference cannot be resolved.