Skip to help content
RightMessage

Code node JavaScript API

Look up flow Code node RM methods, return values, visitor data, and asynchronous email-platform writes.

Available on the Grow, Scale, and Pro plans.

Updated

View as Markdown

A flow Code node runs your JavaScript on the visitor's page to read data, change it, or display a result. Its local RM object is separate from the browser's window.RM command queue and rm:* events. See Browser JavaScript commands and events for those interfaces.

Code changes save to the project's draft. They affect normal visitors after publication. The methods use the installed project's configuration and available integration, not a REST API token. Browser code is visible to visitors. Keep credentials and authorization decisions on your server.

Code node editor with a WorkForge score result, JavaScript Code, Add Data, and AI GenerateOriginal
Code node editor with a WorkForge score result, JavaScript Code, Add Data, and AI Generate

Code editor controls

The flow builder lists Code under Actions. The node editor is titled Execute or Embed Code.

ControlEffect
Friendly NameLabels the node in the flow. It does not change the code's behavior.
JavaScript CodeContains the browser JavaScript or HTML insertion content described below.
SelectorCSS selector for the HTML insertion path. The field appears when the code contains HTML-like markup or document.querySelector. Merely showing this field does not mean the runtime will use the HTML path.
Add DataOpens the flow data picker when data is available. Selecting a token inserts its translated expression at the cursor, or appends it if the editor cursor is unavailable.
AI GenerateOpens Generate JavaScript Code with AI. Enter what the code should do or how existing code should change, then choose Generate Code.

Display Mode Detected is an editor hint based on static analysis. The actual returned value determines whether the runtime displays content.

Execution and display results

The runtime renders Liquid in the code first, then executes the result synchronously with new Function('RM', code). Top-level await is not supported. Returned Promises are not awaited.

ResultFlow behavior
Nonempty stringDisplays the string as widget content instead of continuing past the node. Strings can contain HTML.
HTMLElementDisplays the element as widget content.
{ display: true, content }Displays a truthy content value. Use a string or an element.
undefined or nullContinues the flow without display content.
Number, boolean, Promise, empty string, or other non-displayable valueLogs a warning and continues.
Synchronous exceptionLogs the error and failed code, records a debugger error, and continues. Earlier side effects are not rolled back.

A separate HTML-insertion path applies when the source contains HTML-like markup but no return followed by whitespace. It parses the source as HTML and appends it to Selector, or to body when no selector is set. Top-level script elements are recreated to execute them. A missing target records an error. This detection is text-based, so an HTML-looking JavaScript string can select the insertion path unexpectedly.

For a JavaScript calculation that displays HTML, an explicit return avoids that ambiguity. Illustrative example, not executed:

JavaScript
const result = document.createElement('p');
result.textContent = `Your WorkForge fit score is ${RM.getScore('fit')}.`;
return result;

Expected result: the widget displays a paragraph containing the current score. Using textContent keeps visitor data out of raw HTML.

Variables and scores

MethodArgumentsReturn and effect
RM.getVariable(name)name: stringStored JSON-compatible value, or null when missing or expired. Reading an expired value removes it.
RM.setVariable(name, value, options = {})String name, JSON-compatible value, optional expiry object belowundefined. Persists the value in browser storage and refreshes variable context.
RM.getScore(scoreName)String score nameCurrent score, or 0 when absent.
RM.adjustScore(scoreName, amount)String name and numeric adjustmentundefined. Adds an adjustment and refreshes score-dependent state. Negative amounts subtract.
RM.setScore(scoreName, value)String name and numeric valueundefined. Replaces existing adjustments for that score with the given value.

setVariable accepts these nested options:

OptionDefaultValues
expiresTypenullUse 'duration' for a timed value. Other values do not add an expiry.
expiresDurationnullDuration amount. Supply a positive number.
expiresUnitnull'minutes', 'hours', 'days', or 'weeks'.

An expiry requires all three duration settings and a recognized unit. There is no timer callback at expiry. Reads and context refreshes omit expired values. Each write replaces the previous value and expiry. Without expiry options, the value has no scheduled expiry, but clearing browser data can remove it.

Unlike a Set Data node, RM.setVariable(name, '') stores an empty string. It does not delete the variable. Values must survive JSON serialization. Circular objects and unsupported JSON values are not valid storage inputs.

Scores are calculated runtime values, not durable variables. For a value that must survive a page load, use a variable. See Flow data and Liquid reference for the distinct score, variable, and input paths.

Illustrative calls and values, not executed:

JavaScript
RM.setVariable('workforge_tier', 'team', {
	expiresType: 'duration',
	expiresDuration: 7,
	expiresUnit: 'days'
});
RM.setScore('fit', 10);
RM.adjustScore('fit', 5);
console.log(RM.getVariable('workforge_tier')); // "team"
console.log(RM.getScore('fit')); // 15

Question inputs

MethodArgumentsReturn and effect
RM.getInput(questionIdOrText)Exact question ID, or case-insensitive trimmed question textStored input value. For a segment-choice question without a direct input value, returns the selected option label or comma-separated labels. Returns null for no answer or an unknown question.
RM.setInput(questionIdOrText, value)Same lookup plus a valueundefined. Records and persists the input. An unknown question logs an error and changes nothing.

Question text matching compares stored text, including any markup. IDs avoid ambiguous or edited labels. setInput stores an answer. It is not a form submission or a guarantee that an email-platform field has been written.

Segment answers

MethodArgumentsReturn and effect
RM.getSegments()NoneArray of active segment ID strings from current segmentation.
RM.addSegment(segment)Segment ID beginning seg_, or segment nameundefined. Records a hard answer and clears other recorded answers in the same group.
RM.addSegment(group, segment)Group ID or name, then segment ID or nameSame effect, with lookup constrained to that group.
RM.removeSegment(segment)Segment ID or nameundefined. Removes that recorded answer.
RM.removeSegment(group, segment)Group ID or name, then segment ID or nameSame removal with group lookup.

Names are compared case-insensitively after trimming. A single name that matches several groups logs a warning and uses the first match. Failed lookups log an error and do nothing. Use IDs for stable references.

addSegment replaces sibling answers even in a multi-select group. These methods change recorded answers, not the group's signal rules. Removing an answer does not guarantee that the visitor stops matching a signal-based segment.

Unlike window.RM.push(['addSegment', id]), Code-node segment methods do not emit the public browser command's segmentation refresh events. They also do not guarantee an immediate provider sync.

Email-platform fields

Field methods require an active integration. Field lookup checks custom and native fields by ID first, then by case-insensitive trimmed templating token. Pass an ID as a string or a token returned by RM.listCustomFields().

MethodArgumentsReturn and failure behavior
RM.getCustomField(fieldIdOrToken, parseJson = false)Field ID or token, optional booleanCurrent loaded field value, or null when the integration, field, or value is missing. With parseJson: true, returns parsed JSON when parsing succeeds. On parse failure, warns and returns the original value.
RM.setCustomField(fieldIdOrToken, value)Existing field ID or token and provider-compatible valuePromise resolving to undefined when a field resolves. Missing integration or field logs an error and returns undefined. Provider failure is caught and logged, so a resolved Promise is not a success receipt.

setCustomField routes native fields through their native-field identifier. It can queue a field write while identity is missing or being resolved. Queueing is not confirmation of delivery. It does not create a field, and a read immediately after a write is not a guaranteed refreshed provider value.

Email-platform tags

MethodArgumentsReturn and effect
RM.addTag(tagId)Exact provider tag ID, preserving its typeundefined. Starts an asynchronous addition.
RM.removeTag(tagId)Exact provider tag IDundefined. Starts an asynchronous removal if the integration supports it.
RM.hasTag(tagId)Exact provider tag IDBoolean based on currently loaded tag IDs.

Tag-name lookup is not supported. Both write methods require an identified visitor with an email or subscriber ID. Missing integration or identity logs an error and does not queue a tag. This differs from Set Data tag actions, which can queue anonymous visitors' changes.

Provider errors are logged asynchronously. Tag methods do not return a Promise or delivery receipt, and hasTag is not a post-write acknowledgement. Without integration or identity, hasTag returns false and logs a message.

Available questions, segments, fields, and context

MethodReturn shape
RM.listQuestions()Array of { id, text, options: [{ id, label, segmentId }] }. Omits questions with empty text or only empty HTML.
RM.listSegments()Object keyed by group name, with arrays of { id, name, isActive }. Duplicate group names can overwrite a key.
RM.listCustomFields()Array of { id, token, value } for loaded custom and native fields. Returns [] and warns without an integration.
RM.getVisitorContext()Shallow-frozen object containing serializable visitor-context entries. Functions and source objects are skipped. Unserializable entries become '[Not serializable]'.

getVisitorContext() does not deep-freeze nested values or fetch missing profile data. Its integration namespace depends on the connected provider. It can include personal information and should not be sent to unrelated analytics systems or public logs.

Illustrative discovery result, not executed:

JSON
{
	"Lifecycle": [
		{ "id": "seg_workforge_lead", "name": "Lead", "isActive": true },
		{ "id": "seg_workforge_customer", "name": "Customer", "isActive": false }
	]
}

Add Data and AI Generate

Add Data translates simple score, variable, and input tokens into RM.getScore, RM.getVariable, and RM.getInput calls. Other tokens can become comments rather than executable expressions. In particular, an integration-data comment does not mean the field methods above are unavailable.

AI Generate uses the existing code and the flow's questions, scores, and variables as context. A successful result replaces the node's code in the draft. Generation is not execution, a security review, or publication. Review generated code for display returns, provider writes, and repeated side effects before publishing.

For a provider write, verify the result in the connected integration. A finished Code node is not a delivery confirmation.

Still need a hand?

Tell us what you’re trying to do and where you’re getting stuck.

support@rightmessage.com