> Fetch clean Markdown by appending `.md` to any page URL under https://signalwire.com/docs or requesting it with the HTTP header `Accept: text/markdown`. The root index at https://signalwire.com/docs/llms.txt lists the available documentation indexes. # Variables > Syntax, scopes, deployment modes, and how to access nested data with SWML variables. SWML provides a variable system for accessing call or message information, storing intermediate state, and passing data between sections. This page covers **how to use** variables: syntax, scopes, accessing nested fields, and deployment-mode differences. For the authoritative field-by-field reference of what each scope contains, see the per-flavor overviews: * [Calling webhook and variable payload](/docs/swml/reference/calling#webhook-payload) — `call`, `params`, `vars`, `envs` * [Messaging webhook and variable payload](/docs/swml/reference/messaging#webhook-payload) — `message`, `params`, `vars` For JavaScript expressions on top of variables, see [Expressions](/docs/swml/reference/expressions). For template transformation functions, see [Template Functions](/docs/swml/reference/template-functions). ## Syntax Wrap a variable name in `${...}` or `%{...}` anywhere inside a string value, and SignalWire substitutes the current value when the script runs. Use it to personalize a greeting with the caller's number, pass a request body through to your backend, or pick a reply based on the inbound message body. The two flavors of SWML accept slightly different forms. ### Calling In a Calling document, `${...}` and `%{...}` are interchangeable — pick whichever reads more naturally in your YAML or JSON. **Reference a value.** Use a plain path like `${call.from}` or `%{vars.user_choice}`. Works for any field on `call`, `params`, `envs`, or `vars`. If the path is valid but the value isn't set, the placeholder resolves to an empty string. If the placeholder body isn't a plain path — for example, it includes operators, method calls, or other JavaScript — it's evaluated as a JavaScript expression instead. See [Expressions](/docs/swml/reference/expressions). #### YAML ```yaml version: 1.0.0 sections: main: - play: url: 'say: This call is from ${call.from}' ``` #### JSON ```json { "version": "1.0.0", "sections": { "main": [ { "play": { "url": "say: This call is from ${call.from}" } } ] } } ``` ### Messaging A Messaging document uses `%{...}` only. **Reference a value.** Use a plain path like `%{message.from}` or `%{vars.reply_message_id}`. Works for any field on `message`, `params`, or `vars`. If the path is valid but the value isn't set, the placeholder resolves to an empty string. #### YAML ```yaml version: 1.0.0 sections: main: - reply: body: 'Received message from %{message.from}: %{message.body}' ``` #### JSON ```json { "version": "1.0.0", "sections": { "main": [ { "reply": { "body": "Received message from %{message.from}: %{message.body}" } } ] } } ``` ## Variable scopes The variables available at runtime are the same fields delivered on the inbound webhook payload for each SWML flavor. See the [Calling webhook and variable payload](/docs/swml/reference/calling#webhook-payload) and the [Messaging webhook and variable payload](/docs/swml/reference/messaging#webhook-payload) for the authoritative list of scopes (`call` / `message`, `params`, `vars`, `envs`) and every field inside them. ## Accessing nested data Variables can hold simple values, nested objects, or arrays. Use dot notation (`.`) for object properties and bracket notation (`[]`, zero-based) for array elements. The patterns below work identically inside `${...}` and `%{...}`; the examples use calling syntax and the [`set`](/docs/swml/reference/calling/set) method to seed the data. #### YAML ```yaml version: 1.0.0 sections: main: - set: user: name: Alice address: city: Seattle employees: - name: Alice role: Engineer - name: Bob role: Manager - play: url: 'say: ${user.name} lives in ${user.address.city}' - play: url: 'say: ${employees[0].name} is an ${employees[0].role}' - play: url: 'say: ${employees[1].name} is a ${employees[1].role}' ``` #### JSON ```json { "version": "1.0.0", "sections": { "main": [ { "set": { "user": { "name": "Alice", "address": { "city": "Seattle" } }, "employees": [ { "name": "Alice", "role": "Engineer" }, { "name": "Bob", "role": "Manager" } ] } }, { "play": { "url": "say: ${user.name} lives in ${user.address.city}" } }, { "play": { "url": "say: ${employees[0].name} is an ${employees[0].role}" } }, { "play": { "url": "say: ${employees[1].name} is a ${employees[1].role}" } } ] } } ``` The same patterns apply in messaging — for example, `%{message.media[0].url}` accesses the first media attachment's URL. ## Deployment modes SWML can be hosted in two places, which affects how variable values get into your script. ### Serverless (Dashboard-hosted) The SWML document lives in the SignalWire Dashboard. SignalWire evaluates the placeholders against the live runtime context — no HTTP fetch is involved. #### YAML ```yaml version: 1.0.0 sections: main: - set: department: sales - play: url: 'say: You are calling from ${call.from}' - play: url: 'say: Department is ${vars.department}' ``` #### JSON ```json { "version": "1.0.0", "sections": { "main": [ { "set": { "department": "sales" } }, { "play": { "url": "say: You are calling from ${call.from}" } }, { "play": { "url": "say: Department is ${vars.department}" } } ] } } ``` ### Server-based (external URL) SignalWire POSTs the runtime context to your server and your server returns the SWML document in response (see the [Calling](/docs/swml/reference/calling#webhook-payload) or [Messaging](/docs/swml/reference/messaging#webhook-payload) payload reference for the request shape). You have two ways to use the variables: **1. Return SWML with placeholders.** SignalWire substitutes at runtime — exactly the same syntax used in serverless mode. Best when you just need to interpolate values into otherwise-static SWML. **2. Substitute server-side before responding.** Read variables from the request body in your server code, then build a SWML document with the values already filled in. Best when you need logic, transformations, or external lookups that can't be expressed as a placeholder. > **Note** > > The `${...}` in the example below is **JavaScript template-literal syntax**, not SWML > variable expansion — it's interpolated by Node.js before the response is sent. ```javascript // Example: Node.js / Express server app.post('/swml-handler', (req, res) => { const { call, vars, envs, params } = req.body; // Pull values out of the request and apply your own logic const department = params.department || 'support'; const callerNumber = call.from; // Build SWML with concrete values already substituted res.json({ version: '1.0.0', sections: { main: [ { play: { url: `say: Welcome to ${department}` } }, { play: { url: `say: Calling from ${callerNumber}` } }, ], }, }); }); ``` See the [Deployment Guide](/docs/swml/guides/deployment) for complete server setup instructions. > How to use variables in SWML scripts