Skip to help content
RightMessage
MCP referenceReference

MCP tools for flows and flow nodes

Exact flow and node tool arguments, tree schemas, mutation safeguards, analytics responses, and draft-only behavior.

Available on the Grow, Scale, and Pro plans.

Updated

View as Markdown

Use these tools to build the sequence of questions, conditions, forms, offers, and actions a visitor follows. Read get-flow-summary before editing branches. Use get-flow for metadata and node IDs, not to reconstruct the connections between nodes.

MCP flow access and draft changes

All tools accept optional project_id (string). Omission uses the connection's active project or an accessible project the server can resolve. Pass the ID explicitly when working across projects.

The tools follow the shared MCP authorization and project-selection rules. Grow includes MCP access. There is no additional general flow-plan requirement. New or changed app-embed nodes also require a connection to the embed app in your project. A draft save does not bypass feature requirements applied at publication or execution.

Configuration reads prefer the draft, otherwise the published configuration. Mutations save a validated draft and a configuration snapshot. None publishes the draft or runs the flow. Normal website visitors use the published flow. Previewing a draft can still execute your Code nodes, so the debugger is not a sandbox for arbitrary JavaScript. create-flow-from-description also uses AI generation while drafting.

Shared failures include inaccessible projects, missing entitlement, malformed configuration, and invalid resource references. Errors are MCP errors, not successful resource objects. A modify-flow error can describe a partially saved batch. Its section explains recovery.

Examples are illustrative and were not executed. Request objects show tool-call names and arguments; results omit the MCP transport envelope. Short results are marked as excerpts.

Flow and node schema

A saved flow has id (ofn_…), name, funnelDefinition, and optionally isSystemFlow. A write uses definition for the tree and is_system_flow for the system-flow flag. Do not pass the returned field names as top-level write arguments.

A definition is {type: "root", child: [...]}. child is an ordered array of nodes. Each node has type and an optional _uuid string; whole-definition creation/update assigns missing UUIDs. Node creation assigns the new node's UUID. Keep existing UUIDs when preserving a tree.

Node objects reject properties outside their type's schema. Branch child arrays recursively contain the same node types.

Node typeProperties and defaults
sgsegmentGroupId: dimension ID, question ID, or null in the stored schema. ask boolean defaults to true during creation. split defaults to false, or is an array of {segmentId, child}; both branch properties are required, and segmentId is a segment ID or null.
yesnocondition: logic object, default {} during creation. yes and no: node arrays, default []. Optional note string.
offerofferId: offer/form ID or null. Optional desiredType: form or offer. A placeholder can be stored without a selected item, but cannot show an offer.
redirectRequired url string. open boolean defaults false; sendSubscriberData boolean defaults false.
dataactions array, default []; action fields below.
messageRequired content string.
codeRequired name and code strings; optional selector string.
webhookRequired HTTPS url; method: POST, PUT, or PATCH, default POST. Optional name string. customPayload string defaults empty; fireOnce boolean defaults true; timeoutMs number defaults 10000. Optional includeVisitorContext boolean.
embedapp, content, and target, described below. The stored schema also requires _uuid.
highscoreRequired split array of {score, child}. score is a string or null; child is a node array. Optional mode: scores or variables; optional inverse boolean.
randomRequired split array of {child: [...]} branch objects.
exitNo additional properties.

For a choice-question node, create the segment group and its linked question first. An sg with ask: true and no linked question can return _warnings on whole-flow saves. Do not treat that warning as a working question.

The stored schema permits input-question IDs (raq_…) in segmentGroupId, but create-flow-node currently prevalidates that property against dimension IDs only. Use a complete definition with create-flow or update-flow when inserting a standalone input-question reference; preserve the rest of the tree. Do not invent a dimension for an input question.

Data actions

Each action has required type and id in the saved schema. Mutation normalization generates missing act_… IDs. Valid types are score, field, variable, add_tag, remove_tag, and set_segment. Actions allow additional properties; the useful runtime fields are:

  • score: score name and numeric adjust amount.
  • field: field identifier and value to render into the connected platform's custom field.
  • variable: string variableName and variableValue. Values support Liquid; an empty rendered value removes the variable. For timed expiration, set expiresType: "duration", numeric expiresDuration, and expiresUnit: minutes, hours, days, or weeks. Otherwise the runtime stores no expiration timestamp. The open action schema does not declare numeric bounds for the duration.
  • add_tag and remove_tag: string tagId.
  • set_segment: string segmentGroupId and segmentId. Whole-definition normalization can infer the group from an existing segment; supply both for individual node creation.

These are stored instructions, not immediate contact writes. Once published, field/tag actions depend on the connected provider and visitor identity; assigning a segment updates the answer bank and can trigger configured synchronization.

The runtime currently deduplicates score adjustments by node ID. Multiple score actions in one Set Data node can therefore retain only the first adjustment. See the data-action limits and Liquid reference.

Embed nodes

The production schema supports app: "senja". Content is null for an incomplete draft, or one of:

  • Widget snapshot: {kind: "widget", id: string, name: string, design: string}. id must contain a nonwhitespace character.
  • Wall-of-love snapshot: {kind: "wall_of_love", slug: string, permalink: string, name: string}. slug and permalink must contain nonwhitespace characters.

Targets are either {kind: "element", selector: string, position: "inside"|"before"|"after", pages: logic} or {kind: "page", pages: logic}. All listed target properties are required. Use pages: {"and":[]} for all pages. Extra snapshot/target properties are rejected. Do not put credentials in content.

Creation defaults an omitted embed app to senja, content to null, and target to {kind: "element", selector: "", position: "after", pages: {and: []}}. These defaults make an incomplete draft, not a ready-to-display embed. New or changed embeds check the registered app and the project's local connection without fetching upstream resources. Unknown or disconnected apps return an error. Unchanged saved embeds are not revalidated solely because a connection was removed.

Structural and privacy constraints

A form is an offer node whose selected item's action is not link. Only message and redirect nodes may follow that form in the same branch. Branch before the form when visitors need different terminal content. Whole-flow create/update and individual node insertion reject this structural violation.

System flows run on page views without a widget. Use background nodes: data, code, webhook, embed, yesno, highscore, redirect, random, and exit. Questions, offers, and messages require a widget.

Set sendSubscriberData: true only for an absolute redirect URL on another domain running this same RightMessage project. Leave it false for same-site paths and ordinary links. A webhook URL must start with https://; other URLs return an error instead of creating an action that cannot fire.

Node position object

create-flow-node and move-flow-node accept a position object:

KeyType and behavior
parentParent node UUID string. Omit for root placement, unless a sibling locator resolves a nested branch.
afterSibling UUID string. Inserts after that sibling; without parent, its containing branch is found automatically.
beforeSibling UUID string supported by the positioning service. Inserts before that sibling.
branchFor yesno, yes or no; for sg, a segment-ID string; for random and highscore, a zero-based branch index.
insertAtStartBoolean. Inserts at the beginning of the resolved array.

Within the target array, priority is insertAtStart, then before, then after, then append. Omitted position on node creation appends at root. An unknown parent or sibling, a parent without a child branch, or an invalid branch returns a position error. Use IDs from the current flow, not display names.

list-flows

List compact flow summaries. The only argument is optional project_id; the tool is read-only.

Returns an array with id, name, isSystemFlow, type (system or widget), and widgetCount. When a tree exists, stats contains questionCount, offerCount (unique offers), and conditionCount. An empty configuration returns []. Shared access errors apply.

Illustrative request and result:

JSON
{"name":"list-flows","arguments":{}}
JSON
[{"id":"ofn_workforge","name":"WorkForge intake","isSystemFlow":false,"type":"widget","stats":{"questionCount":1,"offerCount":1,"conditionCount":0},"widgetCount":1}]

get-flow

Read flow metadata and a flat list of node IDs. Requires flow_id (string); accepts optional project_id. No configuration changes occur.

Returns saved flow metadata, removes funnelDefinition, and adds:

  • stats: questionCount, offerCount, uniqueOfferCount, conditionCount, messageCount, redirectCount, hasSegmentRouting, and conditionTypes.
  • _nodeUuids: array of {_uuid, type, name} for non-root nodes. It is not a connected tree.
  • linkedWidgets: array of {id, name, type, isEnabled}.
  • _systemFlowNote for a system flow, plus resolved names alongside known resource IDs.

Missing ID returns flow_id is required. An unknown flow returns a not-found error. Use get-flow-summary to understand routing.

Illustrative request and result excerpt:

JSON
{"name":"get-flow","arguments":{"flow_id":"ofn_workforge"}}
JSON
{"id":"ofn_workforge","name":"WorkForge intake","_nodeUuids":[{"_uuid":"11111111-1111-4111-8111-111111111111","type":"message","name":"Thanks for visiting WorkForge."}],"linkedWidgets":[]}

get-flow-summary

Read a human-readable view of the flow's connections. Requires flow_id (string). Optional days is an integer with default 30; optional project_id uses the shared contract.

Returns text containing YAML, not JSON and not a lossless write definition. It contains a reading guide, nodes keyed by UUID, node-specific text/conditions/branches, and catalogs of available dimensions, offers, questions, and other flows. Question nodes use type: question; non-asking segment routers use router; yes/no nodes use condition in this presentation.

Each question/router's trunk_next shows where it continues when an answer branch does not override it. A branch's next can point to a UUID, return to the trunk, or be (flow-end). Only (flow-end) means termination.

The hosted tool returns a compact summary. Despite the tool's general description mentioning metrics, this response omits analytics, email-platform sync fields, field values, and visitor counts. Changing days does not add those metrics. Use get-flow-performance for analytics. The summary uses the latest stored configuration, not necessarily the live version.

Missing ID returns flow_id is required. Missing configuration/flow or generation failures return Failed to generate flow summary: …. No mutation occurs.

Illustrative request and YAML result excerpt:

JSON
{"name":"get-flow-summary","arguments":{"flow_id":"ofn_workforge","days":30}}
YAML
# Flow: WorkForge intake
nodes:
  11111111-1111-4111-8111-111111111111:
    type: message
    text: "Thanks for visiting WorkForge."

create-flow

Create a draft flow. Requires name (string). Optional definition is the complete tree above; omission creates an empty root with child: []. Optional is_system_flow is boolean, default false; optional project_id uses the shared contract.

Returns the saved flow with its generated ID, normalized tree, and _warnings array when a choice-question node lacks a linked question. It does not create widgets or the resources referenced by nodes. Missing name returns name is required. Invalid definitions, embed access, and post-form structure return errors.

Illustrative request and result:

JSON
{"name":"create-flow","arguments":{"name":"WorkForge intake"}}
JSON
{"id":"ofn_workforge","name":"WorkForge intake","funnelDefinition":{"type":"root","child":[],"_uuid":"00000000-0000-4000-8000-000000000000"}}

update-flow

Change draft metadata or replace a whole tree. Requires flow_id (string) and at least one of name (string), definition (object), or is_system_flow (boolean). Optional project_id uses the shared contract.

Omitted fields remain unchanged. Supplying definition replaces the entire tree, not just the mentioned nodes. Returns the saved flow with normalized nodes and any _warnings. For a small edit, use the node tools instead.

Unknown flow returns Flow not found: …. An empty update returns At least one of name or definition must be provided. even though a system-flow flag alone is also accepted. Invalid configuration and post-form structural errors reject the update.

Illustrative request and result excerpt:

JSON
{"name":"update-flow","arguments":{"flow_id":"ofn_workforge","name":"WorkForge team intake"}}
JSON
{"id":"ofn_workforge","name":"WorkForge team intake","funnelDefinition":{"type":"root","child":[],"_uuid":"00000000-0000-4000-8000-000000000000"}}

create-flow-from-description

Generate a flow and its supporting resources from plain text. Requires description (string). Optional name defaults to New Flow; optional target_flow_id identifies an existing flow; optional project_id uses the shared contract.

The server invokes AI generation, then creates or reuses segment groups and questions, creates offers and personalization phrases as needed, and saves the assembled draft. Existing dimensions can be reused by ID or matching name. This is not a deterministic JSON-tree builder.

A supplied target_flow_id replaces that flow's definition, even if it already contains nodes. The tool supplies the default name New Flow when name is omitted, which can rename the target. Read the target first and provide the intended name.

Returns text summarizing the flow ID/name, dimensions, questions, offers, personalization tokens when created, top-level flow-node count, and generated explanation when available. It is not the full saved object; read the flow afterward for its current structure.

Missing description returns an instruction to describe the flow. Unknown target, no configuration, generation failure, and save validation failures return errors. No publishing or visitor action occurs.

Illustrative request and text result:

JSON
{"name":"create-flow-from-description","arguments":{"name":"WorkForge intake","description":"Ask which team the visitor works in: Operations or Customer Success. Show a link to https://example.com/demo after either answer."}}
Text
Created flow "WorkForge intake" (ofn_workforge) with:
- 1 dimensions: Team
- 1 questions
- 1 offers: WorkForge demo
- 2 flow nodes

Flow logic: Ask the visitor's team, then show the demo link.

duplicate-flow

Copy a draft/current flow. Requires flow_id (string). Optional new_name defaults to the original name plus (Copy); optional project_id uses the shared contract.

Returns the copied flow with a new ofn_ ID and fresh UUIDs for existing nodes throughout its child and branch arrays. It keeps references to the original questions, offers, and segment groups. It does not copy or relink widgets. Missing/unknown flow returns an error; copied configuration must still validate.

Illustrative request and result excerpt:

JSON
{"name":"duplicate-flow","arguments":{"flow_id":"ofn_workforge","new_name":"WorkForge alternate intake"}}
JSON
{"id":"ofn_alternate","name":"WorkForge alternate intake","funnelDefinition":{"type":"root","child":[],"_uuid":"22222222-2222-4222-8222-222222222222"}}

delete-flow

Remove a flow from the draft. Requires flow_id (string); accepts optional project_id.

Returns {deleted: true, flow_id}. It also clears contentId on widgets that referenced the flow. Questions, forms, and offers remain separate resources. Published behavior changes only after publication.

A flow in an active A/B test cannot be deleted; end the test first. Missing ID or unknown flow returns an error. The test protection is explicit for deletion; do not assume every other edit has the same guard.

Illustrative request and result:

JSON
{"name":"delete-flow","arguments":{"flow_id":"ofn_alternate"}}
JSON
{"deleted":true,"flow_id":"ofn_alternate"}

create-flow-node

Add one node to an existing draft flow. Requires flow_id (string) and type (one of the node types above). Optional data holds type-specific node properties; optional position uses the position contract; optional project_id uses the shared contract.

Returns the created node with _uuid, type, and normalized type-specific properties. A linear asking sg can include an informational _note. For branching through the hosted tools, use modify-flow with enable_split; internal underscore-style tool names in diagnostic text are not public tool names.

The tool checks referenced dimensions, offers, and segment conditions before saving. It also simulates insertion to reject forbidden nodes after a form. Missing required IDs/types, unknown type, bad position, missing references, or schema validation produces an error. It saves configuration only; it does not run the new node.

Illustrative request and result:

JSON
{"name":"create-flow-node","arguments":{"flow_id":"ofn_workforge","type":"message","data":{"content":"Thanks for visiting WorkForge."}}}
JSON
{"_uuid":"11111111-1111-4111-8111-111111111111","type":"message","content":"Thanks for visiting WorkForge."}

update-flow-node

Edit one node's properties. Requires flow_id (string), node_uuid (string), and nonempty data (object); accepts optional project_id.

Use the type-specific fields from the schema above. Only supplied properties change. Each supplied object or array replaces that property; for example, replace an embed's complete target, a yes/no node's condition, or a data node's actions array.

_uuid, type, child, split, yes, and no are protected and ignored by this update path. It cannot change a node type or restructure branches. Use create/delete/move, modify-flow for enabling a split, or a deliberate whole-definition replacement.

Returns the saved node. Missing arguments return explicit required-field errors; unknown node/flow returns Node not found: … in flow …. Invalid type-specific properties, non-HTTPS webhooks, or disconnected embeds return errors.

Illustrative request and result:

JSON
{"name":"update-flow-node","arguments":{"flow_id":"ofn_workforge","node_uuid":"11111111-1111-4111-8111-111111111111","data":{"content":"Your WorkForge team is ready."}}}
JSON
{"_uuid":"11111111-1111-4111-8111-111111111111","type":"message","content":"Your WorkForge team is ready."}

move-flow-node

Move a node, with its nested branches, within the same flow. Requires flow_id (string), node_uuid (string), and position (object). Optional project_id uses the shared contract.

Returns {moved: true, node_uuid, flow_id}. The node keeps its UUID; it is removed from its old array and inserted at the requested location. The handler rejects an empty position object, so specify a locator or insertAtStart explicitly rather than sending {}.

Unknown nodes/flows and invalid positions return errors. This saves a draft movement, not a visitor event.

Illustrative request and result:

JSON
{"name":"move-flow-node","arguments":{"flow_id":"ofn_workforge","node_uuid":"11111111-1111-4111-8111-111111111111","position":{"insertAtStart":true}}}
JSON
{"moved":true,"node_uuid":"11111111-1111-4111-8111-111111111111","flow_id":"ofn_workforge"}

delete-flow-node

Delete a node and every nested child below it. Requires flow_id and node_uuid (strings); accepts optional project_id.

Returns {deleted: true, node_uuid, flow_id}. It does not delete separately stored questions, forms, or offers referenced by the removed nodes. The change is draft-only. Missing arguments or unknown flow/node returns an error.

Illustrative request and result:

JSON
{"name":"delete-flow-node","arguments":{"flow_id":"ofn_workforge","node_uuid":"11111111-1111-4111-8111-111111111111"}}
JSON
{"deleted":true,"node_uuid":"11111111-1111-4111-8111-111111111111","flow_id":"ofn_workforge"}

modify-flow

Apply an ordered batch of simplified flow operations. Requires flow_id (string) and nonempty operations (array). A legacy JSON-encoded string is also accepted for operations; use the typed array for new clients. Optional project_id uses the shared contract.

Each operation requires action, one of:

actionRequired and optional properties
insert_nodeRequires type. Use after UUID or parent UUID plus branch to position it; omission appends at root. after_dimension inserts after every question/router for a dimension when neither after nor parent is supplied. Node-specific fields follow below.
delete_nodeRequires node_uuid; removes descendants too.
enable_splitRequires node_uuid for a linear sg. Optional segment_ids string array selects branches; omission uses all segments in its dimension.
update_nodeRequires node_uuid; other properties become a node-property update. Use native stored keys for updates, such as segmentGroupId and offerId, rather than insertion aliases. Protected structure keys remain ignored.

Insertion fields are the node schema with these differences:

  • sg uses dimension for the group ID, optional ask (default true), and starts with split: false. Set enable_split: true to add branches; optional children is an array of child insertion objects, each with its target segment ID in branch.
  • offer uses offer_id, which must identify an existing form or offer.
  • yesno accepts a full logic object or simplified {dimension, operator, segments}. dimension is a group-ID string; segments is an array of segment IDs; operator defaults to include_any, with underscores translated to spaces. Omission creates an empty placeholder condition. Optional yes_path and no_path arrays contain child insertion objects, without positioning fields.
  • Other node types use their native properties: url, open, sendSubscriberData, actions, content, name, code, selector, method, customPayload, fireOnce, timeoutMs, includeVisitorContext, app, target, split, mode, and inverse, as applicable.

The declared operation schema types after, parent, after_dimension, node_uuid, dimension, offer_id, type, url, name, code, selector, method, customPayload, app, and mode as strings. branch is string or integer. ask, enable_split, open, sendSubscriberData, fireOnce, includeVisitorContext, and inverse are booleans. condition and target are objects; content is string, object, or null according to node type. split is boolean or an array of objects; segment_ids is a string array; yes_path, no_path, children, and actions are object arrays; timeoutMs is numeric. Node validation still restricts each field to its applicable node type.

Returns text, with a results heading and zero-based operation entries containing saved node UUIDs. Its current wording says Created even for the updated, deleted, and enable_split result types; read the operation type, not that verb alone.

Insertion validation can reject the batch before any operation runs. Later failures do not roll back earlier successful operations. A failed insertion with inline children or after_dimension can also have saved some nodes. The error lists failures and saved operations. Read get-flow-summary before retrying, then resend only work that did not save.

Other errors include invalid JSON, empty operations, unknown flow, missing per-operation fields, invalid references, and enable_split on an unsuitable node or an already enabled split.

Illustrative request and text result:

JSON
{"name":"modify-flow","arguments":{"flow_id":"ofn_workforge","operations":[{"action":"insert_node","type":"message","content":"Welcome to WorkForge."}]}}
Text
## modify_flow results for ofn_workforge

- Operation #0: Created message node [33333333-3333-4333-8333-333333333333]

get-flow-performance

Read recorded flow executions and node metrics. Requires date_from and date_to (strings: YYYY-MM-DD or ISO 8601 timestamps). Optional flow_id limits the result to one flow; omission returns project-wide metrics. Optional timezone defaults to UTC; optional project_id uses the shared contract.

Date-only boundaries use local midnight through the end of the selected final day in timezone. Explicit timestamp offsets are preserved. The metrics result is cached for five minutes. No configuration changes occur.

Returns:

FieldContract
flowMetricstotalExecutions, completedRuns, unfinishedRuns, uniqueVisitors, identifiedVisitors, avgDurationMs, completionBreakdown, and byFlow.
flowMetrics.completionBreakdownMap of recorded completion-status strings to run counts.
flowMetrics.byFlowArray of {flowId, executions, uniqueVisitors, completionRate}. Rate is a percentage, rounded to two decimal places.
nodeMetricsMap keyed by node ID. Each entry has nodeId, nodeType, visitorCount, and avgDurationMs, with applicable conversionCount, conversionRate, and distributions below.
exposurePagesArray of {url, pathname, hostname, uniqueVisitors, executions}, ordered by unique visitors. These are observed pages, not configured targeting rules.
pathFlowsPresent only for a single flow_id: paths, dropOffs, runsAnalyzed, and analyzedFrom.
estimatesOptional {questions: true} when question figures are estimated; an explanatory note accompanies it.

Node distributions are maps of identifiers to unique-visitor counts: splitDistribution, answerDistribution, branchDistribution, offerDistribution, and bucketDistribution. Question entries can contain estimated and coverage: {status, reason, from}. Unavailable coverage makes question counts and rates null rather than zero. High-volume question estimates are scoped to exposing widgets without requiring exposure-before-answer ordering; do not present them as exact ordered conversion counts.

pathFlows.paths contains {from, to, count} edges; dropOffs contains {nodeId, count}. Path analysis uses the latest 10,000 runs and the final seven days of the requested range, whichever is narrower. analyzedFrom and runsAnalyzed describe that smaller window. Project-wide requests omit paths. Recognized IDs can have resolved name fields added.

A completed run reached the end of its flow; it does not necessarily mean a form submission or a goal conversion. Analytics failures return Flow metrics are unavailable. Please try again later. Required-argument and date parsing errors can also reject a request.

Illustrative request and result excerpt:

JSON
{"name":"get-flow-performance","arguments":{"flow_id":"ofn_workforge","date_from":"2026-10-01","date_to":"2026-10-07","timezone":"UTC"}}
JSON
{"flowMetrics":{"totalExecutions":100,"completedRuns":60,"unfinishedRuns":40,"uniqueVisitors":90,"identifiedVisitors":25,"avgDurationMs":12000,"completionBreakdown":{"completed":60,"dismissed":40},"byFlow":[{"flowId":"ofn_workforge","executions":100,"uniqueVisitors":90,"completionRate":60}]},"exposurePages":[{"url":"https://example.com/welcome","pathname":"/welcome","hostname":"example.com","uniqueVisitors":90,"executions":100}],"pathFlows":{"paths":[],"dropOffs":[],"runsAnalyzed":100,"analyzedFrom":"2026-10-01T00:00:00Z"}}

get-flow-engagements

Read individual response runs, including anonymous visitors, displayed questions with no answers, and skip-only runs. Historical runs without display markers need at least one recorded answer to appear in the response list.

ArgumentType and behavior
flow_idRequired string.
date_from, date_toRequired date strings; the tool advertises YYYY-MM-DD. See the date-boundary limitation below.
emailOptional case-insensitive substring search; shares the search implementation below. Literal *, ?, and backslashes are escaped rather than interpreted as caller-supplied wildcards.
searchOptional string search across email and answer text; takes precedence over email. Matching segment names can also locate choice answers.
outcomeall, completed, abandoned, or closed; default all.
answer_filtersOptional array, combined with AND. Each item requires string segmentId; optional string questionId, segmentGroupId, and nodeId narrow that answer match.
limitInteger, default 25, clamped to 1–100.
search_afterOptional string cursor copied from the previous result's searchAfter.
timezoneOptional string, default UTC, advertised for date display. It does not change the query constructor's date parsing.
project_idOptional string under the shared contract.

A date-only end means midnight. This query parses the supplied boundaries directly. It does not expand a date-only date_to to the end of that day, unlike get-flow-performance. Don't assume the two tools cover identical hours just because you supplied identical dates.

Returns {engagements, total, totalAll, totalEngaged, summary, searchAfter}. Results are ordered by startTime descending, then ID descending. searchAfter is an opaque JSON-encoded string or null. Pass that exact string as search_after for the next page.

Each engagement contains id, timestamp, startTime, nullable email, nullable visitorId, completionStatus, nullable widgetId and widgetTrigger, durationMs, nullable pageUrl, nodes, nullable deviceType and country, plus:

  • outcome: completed for reaching the end, closed for explicit dismissal before the end, otherwise abandoned.
  • engaged: whether a question answer was recorded; skipping alone is not an answer.
  • hasDisplayMarkers: whether a question-show marker exists.
  • stopNode: last unanswered displayed question for an unfinished run, or null.
  • exitNode: terminal content/action node for a completed run, or null.
  • identified: whether a recorded email-question identification succeeded.
  • outcomeLabel: human-readable outcome with the last relevant question, offer, or redirect when available.
  • answers: flat map from question/dimension names to answer values. Multiple-choice names are comma-joined; free text can be prefixed Other: ; skips use Skipped. Repeated labels can overwrite earlier entries, so use nodes for the full path.

nodes preserves the recorded event objects, not the editable flow-node schema. Events use nodeType, nodeId, timestamp, and type-specific fields such as questionId, segmentGroupId, selectedSegmentId (string or array), inputValue, freeformInput, otherText, status, offerId, conversionType, or url. stopNode and exitNode have that same recorded-event shape. Resolved resource-name fields may be added.

Only the first page has summary. It contains entered, answered, answeredRate, completed, completionRate, identified, identifiedCoverage, stopped, and legacyRunsExcluded. Rates are percentages or null when their denominator is zero. Completion rate uses answered/engaged runs, not all entrants. identifiedCoverage is {status: "available"|"unavailable", reason: string|null, from: string|null}; unavailable coverage makes identified null. stopped entries have nodeId, questionId, and count; historical runs without display markers are excluded from those stop counts.

The summary is based on the flow/date range before search, outcome, or answer filters. total counts filtered matching rows. totalAll and totalEngaged mirror first-page entered and answered; subsequent pages return zero for these two fields and null for summary. Preserve the first-page summary instead of treating those later zeros as new totals.

Malformed cursors, invalid outcomes, date parsing, or incomplete analytics queries return errors; unavailable analytics are not a successful empty report. This read can include personal contact and answer data, so share results only with authorized recipients. It changes no configuration or contact data.

Illustrative request and result excerpt:

JSON
{"name":"get-flow-engagements","arguments":{"flow_id":"ofn_workforge","date_from":"2026-10-01","date_to":"2026-10-08","outcome":"completed","limit":25}}
JSON
{"engagements":[{"id":"run_workforge","startTime":"2026-10-03T09:00:00Z","email":null,"visitorId":"visitor_workforge","outcome":"completed","engaged":true,"hasDisplayMarkers":true,"stopNode":null,"identified":false,"outcomeLabel":"Completed · Shown: WorkForge demo","answers":{"Team":"Operations"}}],"total":1,"totalAll":2,"totalEngaged":1,"searchAfter":null}

Still need a hand?

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

support@rightmessage.com