Skip to content
Expedify
4 min

Text Response

The node that ends a chat workflow by saying something back. One textarea — and the templating inside it does less than its documentation claims, which is worth knowing before you rely on it.

A workflow that answers a person has to say something at the end. Everything before that point — the lookup, the branch, the model call — produces data, and data is not a reply. Something has to turn it into a sentence and put it in front of the user.

Text Response is that something. It is the last node in almost every chat-driven workflow you will build: the user types, the workflow does its thinking, and this node writes back.

Three fields, and only one of them is the node

text

What it holds
Response text template with variable substitution support

typing_indicator

What it holds
Show typing indicator before response Defaults to false.

delay

What it holds
Delay before sending response (in seconds) Defaults to 0.

Only text does work. The other two are reported in the node's output and nothing acts on them — the node does not pause, and the streamed reply carries the message alone. Worth knowing before you spend an afternoon tuning a delay that never happens. The field is also labelled Delay (ms) in the builder while the schema describes it in seconds, so there is no reading of it that is safely correct.

What the text field can actually do

It substitutes values. Write {{crmmanager_1.total}} and the number appears; write {{crmmanager_1.results[0].name}} and it reaches into an array and an object to find it. That is genuinely useful and it is most of what you need.

What it does not do is branch or loop, whatever the documentation says. {{#if}}, {{else}}, {{#each}} and {{@index}} are all described as supported, and the node contains a working implementation of them. In a real workflow run you never reach it: the engine resolves every {{…}} in a node's configuration before the node executes, and that pass does not understand the directives. It strips them and blanks the loop variables, so what the node finally receives has no branch left in it.

The visible symptom is specific and worth recognising, because you will meet it before you know the cause: both halves of your conditional appear in the reply, one after the other, with the loop reduced to a single empty row. That is what a customer receives. There is no error.

So the working rule is short. Substitute values in the template; make decisions with a Condition node; build repeated lines upstream. That is also what the rest of this course has been telling you to do for other reasons — a rule you can see on the canvas beats a rule buried in a sentence.

A worked example

Someone asks about their account in a chat. The workflow looks up their deals, a Condition decides which of two replies applies, and each reply substitutes what it needs.

The branch is a node, and the template just fills in blanks

This workflow was run: the condition took the false path and only the second reply fired.

YesNo

Scroll for all 5 steps →

  • The Condition reads {{crmmanager_1.total}} and sends the run down one of two edges. Both destinations are Text Responses; neither has to know why it was chosen.
  • response_1 substitutes three values, including {{crmmanager_1.results[0].name}} — an index and a field, in one reference. That kind of path works.
  • response_2 is a fixed sentence. Most replies on an empty branch are, and that is fine.

It can only see what is wired into it

A node's template resolves against the output of the nodes connected directly into it. Not the whole run. In the workflow above, the trigger is two hops away from either reply, so {{trigger_1.message}} does not resolve there — even though the trigger obviously ran, and even though its message is visible in the execution log.

This surprises people because the log shows every node's output and the template can only read one of them. If you need the user's original message in a reply that comes after a lookup, wire the trigger into the response node as a second edge, or carry the value forward through a Set Variable.

What breaks

A wrong path does not fail. It gets printed. When a reference cannot be resolved, the node does not raise, does not stop the run, and does not leave a blank — it substitutes the literal text <crmmanager_1.title not found> into the reply and sends it. The run is green. The execution log says the node succeeded. The customer received a message with angle brackets in it.

An earlier version of this workflow used {{item.title}} for a deal, because deals sound like they have titles. The column is name. Nothing objected and the workflow validated. Check field names against the node that produces them, not against what the field ought to be called.

Both branches appearing at once means you used the conditional syntax. If a reply arrives containing your “if” text and your “else” text glued together, nothing is broken in your logic — the template directives were flattened before the node ran. Move the decision into a Condition node and the symptom goes away.

Try it

  1. Wire a User Message Trigger straight into a Text Response, set text to You said: {{trigger_1.message}}, and test it in the chat panel. Two nodes is the whole loop.
  2. Now put any node between the two and run it again. The message stops resolving, because the trigger is no longer directly upstream — that is the wiring rule, seen once.
  3. Add a CRM Manager search and reference {{alias.results[0].name}} in the reply. Indexed paths are the part of the templating you can rely on.
  4. Write a reply using {{#if}} and {{else}} and run it. Read what comes back — both halves, joined. That is the failure this lesson exists to make recognisable.
  5. Replace it with a Condition and two Text Responses, and run it again.
  6. Finally break one field name on purpose and read the chat panel. The angle brackets are the lesson.

Next: Response Builder — the same job when a paragraph of text is not enough, and the reply needs a table or a chart the user can actually read.

Related lessons