Appearance
Logic & Control Nodes
Last updated
Logic nodes decide which way a run goes and reshape values. Fields ending in (or {{var}}) or (if no input) accept {{name}} — or a wired data dot, which now overrides the field the same way a value typed into it would. A dot only carries a value once its own node has actually run earlier in that execution; wire it from something upstream in the same path, not a sibling branch.
Condition
If/else. Continues from True or False.
| Field | Default | Notes |
|---|---|---|
| Left value / {{var}} | — | e.g. {{value}} |
| Operator | == | ==, !=, >, <, >=, <= |
| Right value / {{var}} | — | e.g. 85 |
== and != compare the texts as typed (true = true, but 1.0 ≠ 1). The other four compare as numbers. Condition does not set any variable.
Compare Value
Compares a tag, or a value / {{var}}, with a value as numbers, stores true/false in result, and continues from True or False. Out also fires whatever the answer — workflows built before the True/False outputs existed keep working. When several outputs are wired, Out runs first, then True or False.
| Field | Default | Notes |
|---|---|---|
| Compare | A value or {{var}} | A value or {{var}}, or A tag |
| Left value | — | With A value or {{var}}: a number or {{var}} |
| Tag | — | With A tag: the tag's live value is read when the node runs |
| Operator | == | Same six as Condition |
| Right value | — | A number or {{var}} |
On/off values count as numbers: true and on are 1, false and off are 0. A value that is not a number never matches.
String Compare
Continues from True or False and stores result. Case-sensitive.
| Field | Default | Options |
|---|---|---|
| Left string | — | |
| Operator | Equals | Equals, Not equals, Contains, Starts with, Ends with, Regex |
| Right string / pattern | — | For Regex, a JavaScript pattern without slashes, e.g. ^LOT-\d{6}$. An invalid pattern is treated as no match |
Math
| Field | Default | Notes |
|---|---|---|
| Operation | Add (+) | Add, Subtract, Multiply, Divide, Modulo, Power, Absolute value, Round, Floor, Ceiling, Square root, Sin, Cos, Tan, Average, Min, Max |
| A (if no input) | 0 | Number or {{var}} |
| B (if no input) | 0 | Ignored by the one-value operations (Absolute value … Tan) |
| Decimal places | blank | Rounds the result |
| Output variable | result |
- Text that is not a number counts as 0.
- Divide and Modulo by 0 divide by 1 instead — 25 ÷ 0 gives 25, with no error.
- Sin, Cos and Tan work in radians.
- Average, Min and Max use A and B.
Expression
Runs a line or two of JavaScript and stores the returned value.
| Field | Default | Notes |
|---|---|---|
| Expression (return value) | return vars.myVar * 2; | JavaScript, typed as-is |
| Output variable | result |
Inside the code you have vars (the run's variables — you can also assign to them, vars.limit = 90;), triggerData, and Math, Date, JSON, Number, String, Boolean, Array, Object. There is no access to tags, the database or the network — use a script for that. The code must return something. An exception fails the run with Expression error: ….
The code runs in the same locked-down sandbox as scripts, with a 2-second time limit of its own, so a mistake like while (true) {} fails just this step (Expression error: timed out after 2s) instead of freezing the appliance. Keep an Expression to a quick calculation; anything longer or heavier belongs in a script run from a Run Script node.
Examples:
javascript
return Math.round((Number(vars.good) / Number(vars.total)) * 1000) / 10;javascript
return vars.rows.length > 0 ? vars.rows[0].batch : 'none';{{variables}} are not replaced inside the code — read them from vars instead.
Fork
| Field | Default |
|---|---|
| Number of branches | 2 |
Starts Branch 1, Branch 2 and Branch 3 at the same time — in parallel, unlike several wires from one output, which run one after another. Only branches up to Number of branches run: with the default 2, a wire from Branch 3 is ignored. Values above 3 add no more dots. If any branch fails, the run fails and the other branches stop at their next node. Gather the branches with a Join. See Parallel branches.
Join
| Field | Default | Options |
|---|---|---|
| Continue when | All branches have arrived | All branches have arrived, or The first branch arrives |
Wire the end of each Fork branch into the Join's In. With All, every branch stops at the Join until the last one arrives, and that one continues from Out — exactly once. With The first branch arrives, the first continues and the rest stop there. The Join counts the wires into it, so a branch that does not reach it (because a Condition sent it elsewhere) leaves an All Join waiting; History then says Join (all) never continued.
Loop
| Field | Default | Notes |
|---|---|---|
| Type | Count | Count or For-each array |
| Count (if type=count) | 5 | Accepts {{var}} |
| Array variable (if type=each) | items | The name of a variable holding a list — no braces |
Runs the chain wired to Loop body once per pass, then the chain wired to After loop. On each pass loopIndex is 0, 1, 2…, loopCount is the total, and in for-each mode loopItem is the current item. Lists come from Split String, Read DB, Decode JSON, Call URL or Expression. If the variable is not a list, the body runs zero times.
{{loopItem}} of a database row shows [object Object]; take a field with an Expression: return vars.loopItem.weight;.
Jump To
| Field | Default |
|---|---|
| Target label | — |
Continues the run at the node whose Node Label matches Target label. Case and surrounding spaces are ignored. The run fails with Jump To: no node is labeled "…" if none matches, or if more than one node has that label — give the target a label no other node uses.
A jump back to an earlier node counts toward the 1,000-step limit like a wire loop does; use the Loop node for repetition.
Convert
| Field | Default | Options |
|---|---|---|
| From type | Number | Number, String, Hex, Binary, Octal |
| To type | String | Number, String, Hex, Binary, Octal, Boolean |
| Value (if no input) | — | |
| Output variable | result |
- To Hex / Binary / Octal: gives
0xFF,0b1010,0o17. The From type is not used. - To Number from Hex:
FFor0xFF→ 255. From Binary:1010or0b1010→ 10. - To Boolean: empty,
0andfalse→ false; anything else → true.
Encode JSON / Decode JSON
| Node | Field | Default |
|---|---|---|
| Encode JSON | Source variable (name, no braces) | data |
| Encode JSON | Output variable | json |
| Decode JSON | JSON input (or {{var}}) | {{json}} |
| Decode JSON | Output variable | data |
Decode JSON fails the run with Invalid JSON: … if the text is not JSON.
Reformat Date/Time
Formats a date and time: the value wired into Timestamp, else Value, else the current time.
| Field | Default | Options |
|---|---|---|
| Value (or {{var}}) | — | An ISO date such as 2026-09-15T13:05:00Z, or a Unix time in seconds or milliseconds. Empty means now. Anything that isn't a date fails the run |
| Format | ISO 8601 | ISO 8601 (UTC, e.g. 2026-09-15T13:05:00.000Z), Date only, Time only, Date + Time, Unix timestamp (seconds), Custom |
| Custom (YYYY-MM-DD HH:mm:ss) | YYYY-MM-DD HH:mm:ss | Used when Format is Custom. Tokens: YYYY year, MM month, DD day, HH hour (24 h), mm minute, ss second; anything else is kept as typed, e.g. DD/MM/YYYY HH:mm |
| Locale | en-US | Controls Date only / Time only / Date + Time, e.g. en-GB → 15/09/2026 |
| Output variable | result |
Date only, Time only, Date + Time and Custom use the appliance's time zone.
Date/Time Compare
Continues from True or False and stores result.
| Field | Default | Options |
|---|---|---|
| Date A (or {{var}}) | — | Any date text JavaScript understands: 2026-09-15T06:00:00, ISO strings |
| Operator | Before | Before, After, Equal, Same day |
| Date B (or {{var}}) | — |
A date that cannot be read makes every comparison false.
Concat String
| Field | Default |
|---|---|
| Input count | 2 |
| Separator | empty |
| String 1 (if no input) / String 2 (if no input) | — |
| Output variable | result |
Only two string fields are offered, so raise the count only if you are happy with empty extra parts. You can usually skip this node: a text field such as Line {{line}} – {{state}} does the same.
Split String
| Field | Default |
|---|---|
| Input (or {{var}}) | — |
| Delimiter | , |
| Number of outputs | 3 |
| Output variable | parts |
Stores the whole list of parts in the output variable, and also on the Part 1–Part 3, Remainder and Parts[] dots — wire one of those directly into a downstream field instead of writing an Expression, unless you need an index the fixed dots don't cover.
Example: a barcode reader sends LOT-4471;PN-2230;QTY-48. Split with Delimiter ; into parts, then an Expression return vars.parts[2].replace('QTY-', ''); into qty.