Flow data and Liquid reference
You can save visitor data with Set Data and insert it into text with Liquid. Look up action fields, variable expiry, scores, and the data paths available on your site.
Set Data changes visitor data when someone reaches the node. Liquid lets you insert that data into supported text fields. Use this reference to choose an action or find the Liquid path for a value you want to display.
A Set Data action changes a value or assignment. A Liquid expression displays a value without writing it to your email platform.
Flow edits save to your project draft. Normal site visitors use the published flow. Field and tag actions also need a connected integration that supports the operation. When a visitor reaches those actions in a published flow, RightMessage can send or queue the changes to your provider.
Set Data action fields
You'll find Set Data under Actions in the flow builder. In the Set Visitor Data editor, choose an Action Type, then enter its values.
| If you'd like to… | Editor choice | Configuration type and availability |
|---|---|---|
| Add or subtract points | Update Score | score. Always shown. Select an existing score name or enter another name, then set the adjustment. |
| Write to a custom field | Set Custom Field | field. Shown when an email-platform integration is connected. Select the field and enter its value. |
| Store a value in the browser | Add / Update Variable | variable. Always shown. Enter a name and value. A nonempty value exposes Expires:, with Never or In... and a duration. |
| Assign a segment | Set Segment | set_segment. Always shown. Select the group, then one of its segments. |
| Add or remove a tag | Add Tag, Remove Tag | add_tag, remove_tag. Shown when your integration supports tag operations. Select an available tag. Your provider can use a different label for the tag or list picker. |
Add another action adds an action to the same node, with its own type and inputs. The trash control removes an action when the node has more than one. Changing an action's type clears its old settings. Switching between Add Tag and Remove Tag keeps the selected tag.
When a node has several variable or field actions, Add Data currently inserts into the first of those actions, even if you clicked another action's button. Check which value received the data before saving, or type the Liquid expression directly into the intended field.
In the saved configuration, a node has an ordered actions array. Each action has an id and a type. Action IDs prevent the same action from repeating as the flow runs. They're configuration identifiers, not provider field IDs.
| Type | Fields | What happens and what's required |
|---|---|---|
field | field: provider custom-field ID; value: Liquid-capable string | Renders the value and requests a field write. Without a field or integration, nothing happens. The editor excludes native fields from this picker. |
set_segment | segmentGroupId: group ID; segmentId: segment ID | Replaces recorded answers for the group with the chosen segment. Refreshes segmentation and requests active synchronization of configured mappings. |
add_tag | tagId: provider tag ID | Adds the tag, or queues it until the visitor is identified. Requires an integration that supports adding tags. |
remove_tag | tagId: provider tag ID | Removes the tag, or queues its removal until the visitor is identified. Requires an integration that supports removing tags. |
variable | variableName, variableValue, and expiry fields below | Renders and stores a value in the browser. A blank or whitespace-only rendered value deletes it. |
score | score: score name; adjust: numeric amount | Adds the amount to the named runtime score. A new action starts with this type and an adjustment of 1. |
Provider operations run asynchronously. Their order in the array doesn't guarantee that one request finishes before the next action starts.
Use separate Set Data nodes for multiple score adjustments. RightMessage currently uses the node ID to prevent duplicate score adjustments, so it can record only the first score action in a node.
Custom-field writes
The value field supports Liquid and Add Data. For example, {{ score.fit }} renders the current score as a string before requesting the field write.
If the visitor hasn't been identified, the integration can save the write until they're identified later. An identity lookup that's still running can also delay it. A queued write hasn't reached the provider yet. Check debugger warnings for provider failures rather than assuming the write succeeded because the visitor reached the node.
A field action updates an existing field. It doesn't create a field in your provider or identify a contact just because its value looks like an email address.
Segment assignment
The editor has a Question / Segment Group: picker and a Set To Segment: picker. Changing the group clears the selected segment.
This action replaces recorded answers, including in multi-select groups. If a visitor chose several answers, it clears them and records only the selected segment. The action doesn't run if an ID or the group is missing.
It also requests an active sync, which can overwrite mapped provider data. What reaches your provider depends on the group's synchronization settings and whether the visitor is identified. The action doesn't change the group's automatic signal rules.
Tags and identification
For anonymous visitors, RightMessage saves tag actions as pending additions or removals. It can send them after identifying the visitor. If you queue both an addition and a removal for the same tag, the later operation replaces the opposite one.
For identified visitors, RightMessage uses the known email or subscriber ID to request the change. It skips actions with missing tag IDs or unsupported integration methods. Provider errors produce warnings. They don't undo earlier local actions.
This queue belongs to Set Data actions. The Code-node tag methods require an identified visitor and don't queue anonymous tag changes.
Variable values and expiry
Variables live in the visitor's browser storage, not your email platform. Names are case-sensitive. Choose a stable name, such as workforge_recommendation for our example business, WorkForge (opens in a new tab). Avoid using the same name for a variable and a score.
| Field | Default and accepted values |
|---|---|
variableName | The key used by variable.<name> and RM.getVariable(name). |
variableValue | A string that can contain Liquid. The rendered text is stored as a string. Blank output deletes the variable. |
expiresType | 'never' by default. 'duration' enables timed expiry. |
expiresDuration | Duration amount. The editor uses a minimum of 1 and initializes an omitted duration to 1. |
expiresUnit | 'minutes', 'hours', 'days', or 'weeks'. The editor initializes a duration unit to 'hours'. |
The duration starts when the action writes the value, not when you create the flow. A later write replaces both the value and its expiry. Never means there's no scheduled expiry. It doesn't preserve data across devices, browser resets, or cleared storage.
Expired values disappear from the available visitor data. RightMessage removes them when they're read or recalculated. Expiry doesn't trigger a flow or run a callback at that time.
Here's an illustrative action configuration. It hasn't been executed:
If score.fit is 12, this stores the string "team" with an expiry seven days after the action runs. It doesn't write to your provider.
Unlike Set Data, RM.setVariable stores an empty string instead of deleting the value. It also accepts JSON-compatible values, not just rendered text.
How Liquid renders your text
On-site flow templates use LiquidJS with synchronous rendering. {{ expression }} displays a value. {% if condition %} and related tags control which text appears. Liquid isn't JavaScript, and its expressions aren't segment IDs for data-rm-if.
Text without Liquid markers passes through unchanged. If parsing or rendering fails, RightMessage returns the original template text rather than an error object. A visible {{ ... }} token can mean the Liquid is malformed. Missing visitor data can also mean the data hasn't loaded, rather than that the provider field is blank.
Liquid output is text. It isn't automatically a JavaScript literal, JSON document, escaped HTML value, or URL-safe parameter. Use the appropriate filter for its destination, such as escape for HTML text or url_encode for a URL value. In Code nodes, use typed RM getters rather than inserting visitor text into JavaScript source.
Here's an illustrative template. It hasn't been executed:
This chooses one text branch. It doesn't assign the visitor to a segment.
Current dates in Set Data values
Put date logic in the action's value, not its field ID or variable name. The on-site renderer supports the LiquidJS date filter (opens in a new tab).
This illustrative Set Data value saves the date when the visitor reaches the action:
The output is a string such as 2026-10-13. 'now' is a quoted special input to the filter, not a RightMessage visitor-data path. On-site rendering uses the visitor's browser clock and the runtime's local timezone by default. It doesn't schedule an action for that date.
A variable action keeps the rendered date in browser storage. A field action requests a write to an existing provider field. That field must accept the date's format. Timed variable expiry is separate from the date string.
On-site visitor data paths
RightMessage builds the available visitor data from several sources. Data can be absent while it's still loading. Your connected provider appears under its runtime integration name, not a universal contact or esp object.
| Path | What you can read |
|---|---|
score.<name> | Numeric sum of current runtime score adjustments. Scores aren't persisted variables. |
variable.<name> | Stored value that hasn't expired. Set Data values are strings. Code-node values can have other JSON-compatible types. |
input.<questionId> | Direct stored input value keyed by question ID. Unlike the Code-node getter, it doesn't fall back to segment-option labels. |
segments.<segmentId> | Current segment decision, normally boolean. Missing data isn't a positive match. |
segments.names.<groupId> | Selected segment name with HTML removed. Multiple winning names are joined with , . No winning segment means no name entry. |
phrases.<phraseId> | Phrase text selected for the visitor's current segments, including its configured fallback when applicable. |
query.current.<name> | Current URL query value only. |
query.<name> | Current query value, otherwise its most recent stored pageview occurrence, with the stored first page as a final fallback. |
currentpage.title | Current document title. |
currentpage.url | Current absolute URL. |
currentpage.pathname, currentpage.hostname, currentpage.protocol, currentpage.port | Current URL components. |
currentpage.searchParams.<name> | Current page's query parameter from the URL. |
utm.current.source, utm.current.medium, utm.current.campaign, utm.current.term, utm.current.content | Current page's corresponding utm_* query values. |
utm.source, utm.medium, utm.campaign, utm.term, utm.content | Current truthy UTM value, otherwise its most recent truthy stored occurrence. These aren't guaranteed first-touch values. Unlike query, this lookup skips empty values. |
referrer.url, referrer.domain, referrer.path | Referrer from the stored first page. A missing or invalid referrer produces no values. |
location.country, location.city | Geolocation values when RightMessage has location data. They can be absent. |
jsdata.<name> | A browser window value. This is visitor-controlled data, not a secret or a server-side variable. |
<provider>.email, <provider>.urlEncodedEmail | Loaded email and its URL-encoded form. |
<provider>.isAnonymous | Whether the integration currently has anonymous visitor context. |
<provider>.subscriberId | Persisted provider identifier. Depending on the integration, this can be an email rather than the provider's canonical numeric ID. |
<provider>.customFields.<token> | Loaded custom-field value by templating token. JSON object or array strings beginning with { or [ are parsed when valid. |
<provider>.<nativeToken> | Native field value at the provider object's root, not under a universal nativeFields object. |
<provider>.tagIds, <provider>.listIds | Arrays of currently loaded IDs. |
<provider>.tags, <provider>.lists | Loaded objects such as { id, name }. Availability depends on the provider. |
<provider>.events, <provider>.purchases, <provider>.totalRevenue | Provider event, purchase, and revenue data when available. |
<provider> is a placeholder in this table, not literal Liquid syntax. Get the integration name and field tokens from your project's data picker or inspected visitor data.
The name current is reserved under query. Empty strings and the string '0' are valid current query values and don't fall back to history. This matters when someone arrives with a campaign parameter and then visits a page without it.
For names that don't work with dot notation, Liquid bracket notation keeps the exact key. These illustrative expressions haven't been executed:
Older score-source paths still work for compatibility. Use the paths above for new templates. RightMessage can convert numeric-looking variable strings to numbers for score comparisons, while variable.<name> keeps the stored value. A variable and score with the same name can have different types.
Differences between flow, email, and HTML templates
| Where you're using data | What to know |
|---|---|
| Set Data value | Liquid renders text before the action writes or stores it. |
| Code node | Liquid renders before JavaScript runs. Add Data translates simple score, variable, and input tokens into local RM getter calls. |
| On-site widget or flow text | Uses the site's current visitor data. Provider fields need an available profile. |
| Provider-native personalized email | Uses your email platform's template syntax and data at sending time, not necessarily LiquidJS or the browser paths above. |
data-rm-if HTML attribute | Accepts a segment ID only, not a Liquid expression. |
__rm_test | Overlays selected visitor data for testing. It doesn't change the normal data structure or publish a draft. |
Values from a visitor, URL, or browser storage don't prove that someone has permission to access protected data. Keep that data behind your application's own authentication and server-side access checks.
For provider-specific sending syntax, see email personalization. For browser testing, see simulate visitor data with __rm_test.