In this guide, you'll learn how to use the powerful JavaScript API available within Code nodes to programmatically interact with RightMessage segmentation data, visitor context, and ESP/CRM integrations.
Overview
Code nodes in the Flow Builder expose a special RM object that gives you programmatic access to visitor data, segmentation, custom fields, tags, and more. This API allows power users to:
Display personalized content based on segmentation data
Transform and manipulate visitor data
Integrate with third-party analytics and tracking tools
Implement custom business logic within flows
Sync data bidirectionally with your ESP/CRM
Who this is for: The Code Node API is designed for power users and developers comfortable with JavaScript. You'll need edit access to flows and basic understanding of JavaScript syntax.
Prerequisites
Before using the Code Node API, ensure you have:
Edit access to flows in RightMessage
Basic JavaScript knowledge
An active ESP/CRM integration (required for custom field and tag operations)
Understanding of your segmentation structure (dimensions and segments)
How Code nodes work
When a Code node executes in your Flow:
RightMessage creates the
RMAPI object with access to current visitor contextYour JavaScript code runs with the
RMobject availableIf your code returns a string or DOM element, it displays in the widget
Any data changes sync back to your ESP/CRM automatically
Pro tip: Use your browser's developer console to debug Code nodes. The API logs helpful messages prefixed with [RM] to assist with troubleshooting.
API Methods
Variables
Variables let you store temporary data during a visitor's session or for longer periods.
RM.getVariable(name)
Retrieve a variable value by name.
// Get a stored variable
const visitCount = RM.getVariable('visit_count');
// Returns null if not found or expired
if (visitCount === null) {
console.log('Variable not found or expired');
}Parameters:
name(string) - The variable name
Returns: The variable value, or null if not found or expired
RM.setVariable(name, value, options)
Store a variable with optional expiration.
// Store a variable that expires in 7 days
RM.setVariable('last_quiz_completed', 'onboarding-quiz', {
expiresType: 'duration',
expiresDuration: 7,
expiresUnit: 'days'
});
// Store a variable without expiration
RM.setVariable('user_preference', 'dark_mode');Parameters:
name(string) - The variable namevalue(any) - The value to storeoptions(object, optional) - Configuration object:expiresType- Set to'duration'to enable expirationexpiresDuration- Number of units until expirationexpiresUnit-'minutes','hours','days', or'weeks'
Scores
Scores allow you to track numerical values like engagement level, product interest, or lead quality.
RM.getScore(scoreName)
Retrieve the current value of a score.
// Get current engagement score
const engagementScore = RM.getScore('engagement');
console.log(`Current engagement: ${engagementScore}`);
// Returns 0 if score doesn't existParameters:
scoreName(string) - The score name
Returns: The score value (number), or 0 if not found
RM.adjustScore(scoreName, amount)
Increase or decrease a score by a specific amount.
// Increase engagement score
RM.adjustScore('engagement', 10);
// Decrease score (use negative number)
RM.adjustScore('engagement', -5);
// Track product interest
RM.adjustScore('product_interest_premium', 15);Parameters:
scoreName(string) - The score nameamount(number) - Amount to adjust (positive or negative)
Use case: Adjust scores based on page visits (e.g., +10 for visiting pricing page) or content engagement to build dynamic lead scoring systems.
Questions and Inputs
Access and modify answers to questions asked in your flows.
RM.getInput(questionIdOrText)
Get a visitor's answer to a specific question.
// Get by question ID
const role = RM.getInput('qst_abc123');
// Get by question text
const businessType = RM.getInput('What type of business do you run?');
console.log(`User's role: ${role}`);Parameters:
questionIdOrText(string) - Question ID or the exact question text
Returns: The answer value, or undefined if not answered
RM.setInput(questionIdOrText, value)
Set or override a visitor's answer to a question.
// Set an answer programmatically
RM.setInput('qst_abc123', 'Enterprise');
// Override based on logic
if (employeeCount > 50) {
RM.setInput('Company size', 'Large');
}Parameters:
questionIdOrText(string) - Question ID or question textvalue(string) - The answer value to set
Segmentation
Programmatically manage visitor segments.
RM.getSegments()
Get an array of all currently active segment IDs for the visitor.
// Get all active segments
const activeSegments = RM.getSegments();
console.log('Active segments:', activeSegments);
// Example output: ['seg_abc123', 'seg_def456']
// Check if visitor is in a specific segment
if (activeSegments.includes('seg_premium_customer')) {
// Show premium content
}Returns: Array of segment IDs
RM.addSegment(dimensionOrSegmentId, segmentIdentifier)
Assign a visitor to a segment.
// Method 1: Using segment ID directly
RM.addSegment('seg_abc123');
// Method 2: Using dimension name + segment name
RM.addSegment('Job Role', 'Marketing Manager');
// Method 3: Using dimension ID + segment ID
RM.addSegment('dim_xyz789', 'seg_abc123');Parameters:
dimensionOrSegmentId(string) - Segment ID (when used alone) or dimension name/ID (when used with second parameter)segmentIdentifier(string, optional) - Segment name or ID
Ambiguous names: If segment names aren't unique across dimensions, specify the dimension name to avoid ambiguity. The API will warn you if multiple segments are found.
RM.removeSegment(dimensionOrSegmentId, segmentIdentifier)
Remove a visitor from a segment.
// Remove by segment ID
RM.removeSegment('seg_trial_user');
// Remove by dimension + segment name
RM.removeSegment('Subscription Status', 'Trial');Parameters:
dimensionOrSegmentId(string) - Segment ID or dimension name/IDsegmentIdentifier(string, optional) - Segment name or ID
Custom Fields (ESP/CRM Integration)
Read and write custom field data from your connected email platform or CRM.
Integration required: Custom field operations require an active ESP/CRM integration. Without one, these methods will return errors in the console.
RM.getCustomField(fieldIdOrToken, parseJson)
Read a custom field value from your ESP/CRM.
// Get by field ID
const companyName = RM.getCustomField('fld_company');
// Get by Liquid token
const industry = RM.getCustomField('{{ subscriber.industry }}');
// Parse JSON data automatically
const preferences = RM.getCustomField('user_preferences', true);
console.log(preferences.newsletter); // Access parsed objectParameters:
fieldIdOrToken(string) - Custom field ID or Liquid templating tokenparseJson(boolean, optional) - Iftrue, attempts to parse the value as JSON
Returns: The field value (string or parsed object)
RM.setCustomField(fieldIdOrToken, value)
Write a custom field value and sync it to your ESP/CRM.
// Set a custom field
RM.setCustomField('fld_last_interaction', new Date().toISOString());
// Update using token
RM.setCustomField('{{ subscriber.lifecycle_stage }}', 'Customer');
// Store JSON data
const userData = { plan: 'premium', signup_date: '2025-01-15' };
RM.setCustomField('user_metadata', JSON.stringify(userData));Parameters:
fieldIdOrToken(string) - Custom field ID or Liquid tokenvalue(string) - The value to set
Real-time sync: Custom field updates sync automatically to your ESP/CRM in real-time, keeping visitor data consistent across platforms.
Tags (ESP/CRM Integration)
Manage tags on identified visitors in your ESP/CRM.
Identification required: Tag operations only work for identified visitors (those with an email address or subscriber ID). Anonymous visitors cannot have tags applied.
RM.addTag(tagIdOrName)
Apply a tag to the identified visitor.
// Add by tag ID (recommended)
RM.addTag('tag_completed_onboarding');
// Add by tag name (ESP-specific)
RM.addTag('VIP Customer');Parameters:
tagIdOrName(string) - Tag ID or tag name
Best practice: Use tag IDs rather than names for more reliable lookups across different ESP platforms.
RM.removeTag(tagIdOrName)
Remove a tag from the identified visitor.
// Remove by tag ID
RM.removeTag('tag_trial_user');
// Remove by name
RM.removeTag('Trial User');Parameters:
tagIdOrName(string) - Tag ID or tag name
RM.hasTag(tagId)
Check if a visitor has a specific tag.
// Check for a tag
if (RM.hasTag('tag_premium_member')) {
console.log('Visitor is a premium member');
// Display premium content
}Parameters:
tagId(string) - Tag ID to check
Returns: true if visitor has the tag, false otherwise
Utility and Debugging
Helper methods to inspect and understand visitor data.
RM.getVisitorContext()
Get a clean, serializable copy of the current visitor context.
// Get full visitor context
const context = RM.getVisitorContext();
console.log('Visitor context:', context);
console.log('Current segments:', context.segments);
console.log('Custom fields:', context.customFields);Returns: Immutable object containing visitor data (frozen to prevent modification)
The returned object filters out circular references and non-serializable values, making it safe for logging and debugging.
RM.listSegments()
Get all available dimensions and their segments with active status.
// List all segments
const allSegments = RM.listSegments();
console.log(allSegments);
// Example output:
// {
// "Job Role": [
// { id: "seg_abc", name: "Marketing Manager", isActive: true },
// { id: "seg_def", name: "Developer", isActive: false }
// ],
// "Company Size": [...]
// }
// Check which segments are active in a dimension
const jobRoleSegments = allSegments['Job Role'];
const activeRole = jobRoleSegments.find(seg => seg.isActive);
console.log('Active job role:', activeRole.name);Returns: Object with dimension names as keys and arrays of segment objects as values
RM.listQuestions()
Get all questions in the flow with their answer options.
// List all questions
const questions = RM.listQuestions();
console.log(questions);
// Example output:
// [
// {
// id: "qst_abc123",
// text: "What's your role?",
// options: [
// { id: "opt_1", label: "Marketing", segmentId: "seg_marketing" },
// { id: "opt_2", label: "Sales", segmentId: "seg_sales" }
// ]
// }
// ]Returns: Array of question objects with their options
RM.listCustomFields()
Get all available custom fields from your ESP/CRM integration.
// List all custom fields
const fields = RM.listCustomFields();
console.log(fields);
// Example output:
// [
// { id: "fld_company", token: "{{ subscriber.company }}", value: "Acme Corp" },
// { id: "fld_plan", token: "{{ subscriber.plan }}", value: "premium" }
// ]
// Find a specific field
const companyField = fields.find(f => f.id === 'fld_company');
console.log('Company name:', companyField.value);Returns: Array of custom field objects with ID, token, and current value
Common Use Cases
Third-party analytics integration
Send segmentation data to analytics platforms like Google Analytics, Mixpanel, or PostHog.
// Get visitor segments
const segments = RM.getSegments();
const segmentList = RM.listSegments();
// Build readable segment names
const segmentNames = segments.map(segId => {
for (const [dimension, segs] of Object.entries(segmentList)) {
const match = segs.find(s => s.id === segId);
if (match) return `${dimension}: ${match.name}`;
}
return segId;
});
// Send to PostHog
if (typeof posthog !== 'undefined') {
posthog.identify(visitorEmail, {
segments: segmentNames,
engagement_score: RM.getScore('engagement')
});
}
// Send to Google Analytics
if (typeof gtag !== 'undefined') {
gtag('event', 'quiz_completed', {
'user_segments': segmentNames.join(', '),
'event_category': 'Engagement'
});
}Conditional content display
Return personalized HTML based on visitor segmentation.
// Get visitor's industry segment
const segments = RM.getSegments();
const segmentData = RM.listSegments();
// Find active industry
let industry = 'General';
if (segmentData['Industry']) {
const active = segmentData['Industry'].find(s => s.isActive);
if (active) industry = active.name;
}
// Return personalized content
if (industry === 'E-commerce') {
return `
<h2>Boost Your Online Store Sales</h2>
<p>Discover strategies specifically designed for e-commerce businesses...</p>
<a href="/ecommerce-guide" class="btn">Get the Guide</a>
`;
} else if (industry === 'SaaS') {
return `
<h2>Scale Your SaaS Business</h2>
<p>Learn how successful SaaS companies use segmentation...</p>
<a href="/saas-guide" class="btn">Get the Guide</a>
`;
} else {
return `
<h2>Personalization for Your Business</h2>
<p>Let us show you how to get started...</p>
<a href="/get-started" class="btn">Learn More</a>
`;
}Dynamic lead scoring
Adjust scores based on visitor behavior and sync to your CRM.
// Increase score for high-value page visits
const currentPage = window.location.pathname;
if (currentPage.includes('/pricing')) {
RM.adjustScore('purchase_intent', 15);
RM.setCustomField('last_pricing_visit', new Date().toISOString());
}
if (currentPage.includes('/enterprise')) {
RM.adjustScore('deal_size', 25);
RM.addTag('enterprise_interested');
}
// Get final score and update CRM
const totalScore = RM.getScore('purchase_intent') + RM.getScore('deal_size');
if (totalScore > 50) {
RM.setCustomField('lead_score', totalScore.toString());
RM.addTag('hot_lead');
}Data transformation and enrichment
Parse and transform ESP/CRM data for use in flows.
// Get JSON data from custom field
const rawPreferences = RM.getCustomField('user_preferences', true);
// Transform and use the data
if (rawPreferences && rawPreferences.newsletter_frequency) {
const freq = rawPreferences.newsletter_frequency;
// Set a segment based on preference
if (freq === 'daily') {
RM.addSegment('Engagement Level', 'Highly Engaged');
} else if (freq === 'weekly') {
RM.addSegment('Engagement Level', 'Moderately Engaged');
}
}
// Enrich data back to ESP
const visits = parseInt(RM.getVariable('total_visits') || '0');
RM.setVariable('total_visits', (visits + 1).toString());
if (visits > 10) {
RM.setCustomField('visitor_type', 'Frequent');
RM.adjustScore('engagement', 5);
}Troubleshooting
Code returns non-displayable value
Symptom: Your code runs but nothing displays in the widget.
Cause: Code returned a non-displayable value (number, boolean, plain object).
Solution: Return a string (HTML) or DOM element. Convert numeric results to strings or wrap in HTML:
// Wrong - returns number
return 42;
// Right - returns string
return '<p>Your score is 42</p>';
// Also right
const score = 42;
return `<div class="score">Score: ${score}</div>`;Visitor not identified errors
Symptom: Console shows "Visitor not identified" when using tag operations.
Cause: Attempting tag operations on anonymous visitors who haven't provided an email address.
Solution: Check visitor identification before tag operations:
// Get visitor context to check identification
const context = RM.getVisitorContext();
if (context.email || context.subscriberId) {
RM.addTag('completed_quiz');
} else {
console.log('Visitor not identified - skipping tag operation');
}Multiple segments found warnings
Symptom: Console warns "Multiple segments found" when adding/removing segments.
Cause: Segment names aren't unique across dimensions.
Solution: Specify the dimension to disambiguate:
// Ambiguous - if "Enterprise" exists in multiple dimensions
RM.addSegment('Enterprise');
// Clear - specifies the dimension
RM.addSegment('Company Size', 'Enterprise');No integration found errors
Symptom: Console shows "No integration found" when using custom field operations.
Cause: No active ESP/CRM integration configured.
Solution: Configure an email platform integration in RightMessage settings before using custom field or tag operations.
Variable expiration not working
Symptom: Variables persist longer than expected.
Cause: Invalid expiration unit or duration format.
Solution: Use only supported units (minutes, hours, days, weeks):
// Wrong - invalid unit
RM.setVariable('temp', 'value', {
expiresType: 'duration',
expiresDuration: 1,
expiresUnit: 'months' // Not supported
});
// Right - valid unit
RM.setVariable('temp', 'value', {
expiresType: 'duration',
expiresDuration: 30,
expiresUnit: 'days'
});Limitations
Tag operations require visitor identification: Anonymous visitors cannot have tags applied or removed
Custom field operations require active ESP/CRM integration: Will fail if no integration is configured
Segment lookup ambiguity: Segment names that aren't unique across dimensions require dimension specification
Data serialization limits:
getVisitorContext()filters out circular references and non-serializable valuesReturn value restrictions: Only strings (HTML) and DOM elements can be displayed; other types are logged but not shown
Getting help
If you encounter issues with the Code Node API:
Check your browser's developer console for
[RM]prefixed log messagesUse
RM.listSegments(),RM.listQuestions(), andRM.listCustomFields()to inspect available dataVerify your ESP/CRM integration is active and properly configured
Test your code in small increments using
console.log()for debuggingContact support with console logs and your code snippet for personalized assistance