Unify Logo Footer.svg
Unify Applications
Logo
Evaluate JavaScript

Evaluate JavaScript

Logo

4 mins READ

Overview

The evaluateJavaScript action (also referenced as eval-js in the builder) runs arbitrary JavaScript code and captures its return value. It is the escape hatch for computation that cannot be expressed in UnifyApps' template binding syntax — multi-step transformations, recursive operations, third-party algorithm logic, and anything requiring Array.reduce, Map/Set operations, or complex conditional logic.

Sandbox Environment

The expression runs in a restricted JavaScript sandbox with the following characteristics:

  • No DOM accessdocument, window, and browser APIs are not available.

  • No network accessfetch, XMLHttpRequest, and WebSocket are blocked.

  • No timerssetTimeout, setInterval, and requestAnimationFrame are not available. Use a Delay action in the chain instead.

  • Standard library availableJSON, Math, Date, Array, Object, String, RegExp, Map, Set, and other built-in objects work normally.

  • Page scope available (when scope: "page") — this refers to a read-only snapshot of the current page's variable and data source state.

  • Execution timeout: 5 seconds — expressions that run longer are aborted and the onError callback fires.

Warning: Avoid infinite loops. The sandbox enforces a 5-second execution timeout, but tightly looping code can freeze the UI thread for that duration. Test expressions with representative data volumes before using them in production.

Parameters

ParameterTypeRequiredDefaultDescription
expressionstringRequired (required)The JavaScript code to evaluate. The last expression's value (or an explicit return statement in a function body) is captured as the result. Bindings ({{ }}) in this field are resolved before the expression is evaluated, allowing you to inject variable values as literals.
scope"page" | "global"Optional (optional)"page"pagethis is a read-only snapshot of the page's current state (variables, block states, data source responses). globalthis is the global app state (app variables, user profile, app metadata). Use page for most computations; global for cross-page utilities.
outputVariablestringOptional (optional)The ID of the page variable to store the expression's return value in. If omitted, the result is discarded. The variable must already exist — use a Set Page Variable action to create it first if needed.

Accessing Page State in Expressions

When scope is "page", the expression context (this) exposes:

PathDescription
this.variablesAll page variables as a key-value object.
this.dataSourcesAll data source responses indexed by ID.
this.blocksBlock state snapshots indexed by block ID.
this.appUserThe currently authenticated user object.

Alternatively, use bindings to inject values directly into the expression string — they are resolved as JSON literals before the JS engine sees the code:

Injecting a variable value via binding

// expression field: const items = {{ var_cartItems }}; const total = items.reduce((sum, item) => sum + item.price * item.qty, 0); total.toFixed(2)

Step-by-Step Usage Guide

  1. Identify the computation needed: Determine what value you need to compute and which variables or data source fields it depends on. Check whether it can be expressed in a binding expression first — evaluateJavaScript is best reserved for multi-step logic that would be unreadable as a one-liner binding.

  2. Create an output variable: In the Page Variables panel, create a variable to hold the result (e.g. var_computedTotal). Set its initial value to a sensible default (e.g. 0 for a number, "" for a string).

  3. Write the expression: In the action editor, enter your JavaScript. The value of the final expression (or a return statement) is used as the result. Multi-line expressions are supported using a code block that begins with (function() { and ends with })().

  4. Set outputVariable: Set outputVariable to your variable's ID (e.g. var_computedTotal). After the action runs, the variable is updated and any bindings referencing it re-render automatically.

Examples

Calculate a cart total with tax

{ "actionType": "evaluateJavaScript", "payload": { "expression": "(function() {\n const items = {{ var_cartItems }};\n const subtotal = items.reduce((s, i) => s + i.price * i.qty, 0);\n const tax = subtotal * 0.18;\n return (subtotal + tax).toFixed(2);\n})()", "outputVariable": "var_cartTotal", "scope": "page" } }

Generate a slug from a title string

{ "actionType": "evaluateJavaScript", "payload": { "expression": "'{{ var_articleTitle }}'.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '')", "outputVariable": "var_slug", "scope": "page" } }

Parse and reformat a date string

{ "actionType": "evaluateJavaScript", "payload": { "expression": "(function() {\n const d = new Date('{{ var_rawDate }}');\n if (isNaN(d.getTime())) return 'Invalid date';\n return d.toLocaleDateString('en-IN', { day: '2-digit', month: 'short', year: 'numeric' });\n})()", "outputVariable": "var_formattedDate", "scope": "page" } }

Note: When to use Page Functions instead: For reusable logic that needs to be called from multiple places, define a Page Function instead of duplicating evaluateJavaScript actions. Page Functions are named, versioned, and testable in isolation.