A variable can help you store a piece of information once and reuse it (a name, a count, a reference to a connection) anywhere Buttons lets you reference variables. Which variables you can see and use at a given point depends on scope: where a variable was defined determines where it's visible. Understanding scope up front avoids the most common variable mistake: two variables with the same name that turn out to be in different scopes, and don't refer to the same value at all.
Connection: a reference to one of your configured connections, used to swap which connection a control targets at runtime rather than fixing it permanently. The variable holds which connection to use, not any of that connection's values.
Routing Endpoint: a reference to a routing port or bundle, the routing equivalent of the Connection type.
Feedback: a read-only value driven directly by a connection's own feedback, rather than something you set yourself. Defining one means picking both the feedback and, if that feedback takes its own options (such as which input to watch), those options too: set once when you create the variable, not per position.
Self (inside one element only)→ Parent (the section or canvas an element sits in, shared by everything directly inside it)→ Position (global definition, one value per position)→ Workflow (global, one shared value everywhere)
Connections also provide variables of their own, such as an ATEM's program input. You don't create these, and they aren't part of the scopes above: see Variables a connection provides.
A Self variable lives inside the specific button, section, or similar element where you define it. It isn't visible anywhere else, not even to a sibling copy of the exact same button. Two separate buttons can each have a Self variable with the same name and different values without conflicting, because neither can see the other's.
A Parent variable is a variable that belongs to the section an element sits in. The element can be a button or another section placed inside it. It isn't a separate kind of variable: it's the section's own Self variable, seen from one of the elements inside the section.
For example, a section with a Self variable camera lets every element directly inside it read that value:
Who reads it
Reference
The section itself
$(self.state.camera)
A button or section directly inside the section
$(parent.state.camera)
There is only one value, stored on the section, so every element in the section sees the same value. When one changes it, they all see the change. This makes Parent variables the way for buttons and sections inside a section to share a value, such as a selected camera that one row of buttons sets and another row uses.
A Parent variable reaches only one level down. An element sees the variables of the section it's directly in, not those of sections further out.
You can create and edit a Parent variable from either side:
Select the section and add a variable under Self on its Variables tab.
Select a button or section inside it and add a variable under Parent on its Variables tab. This adds the variable to the outer section, not to the selected element.
Change a Parent variable's value with the Set Section Variable Internal Action, with Section set to Parent.
Besides state, parent also gives the section's details, such as $(parent.label) and, in a section with pages such as a Folder Section, the active page: $(parent.activePageLabel).
The position's canvas can hold variables too. Buttons and sections placed directly on the canvas read them as $(parent.state.name), the same as elements inside a section.
Creating one: select a button or section placed directly on the canvas, then add the variable under Parent on its Variables tab. That's the only way to create a canvas variable.
Changing it from the position: a Set Section Variable Internal Action on the position can set it.
Changing it from a workflow: not possible. A workflow's Set Section Variable doesn't see the canvas. If a workflow needs to change the value, use a Position variable instead.
A Position Variable's definition is global (creating one makes it available in every position), but its value is set independently per position. This means the variable's name and type are shared everywhere, while what it actually holds depends on which position you're looking at.
A Position Variable can hold a Connection-type value, which is what lets a single position swap which connection its buttons actually control: set the variable to a different connection, and every action using it follows, without editing each button individually.
Reference a Position Variable as $(position.state.name).
Change a Position Variable's value with the Set Position Variable Internal Action.
A Workflow Variable is global for both reading and writing, from anywhere in Buttons, not scoped to the workflow that created it. Creating one requires a Workflow, since that's where the variable is defined and typed, but once created it's visible everywhere, the same as a connection's own variables.
Change a Workflow Variable's value with the Set Workflow Variable Internal Action.
Two different things in Buttons can both be described as a connection variable. Keep them apart:
A Connection-type variable
A connection's own variables
What it is
A variable you create, whose Type is Connection.
Values a connection publishes about its device, such as pgm1_input on an ATEM.
What it holds
Which connection to use.
Live device state: a label, a number, an on or off.
Who sets it
You, for example with Set Position Variable.
The connection itself. You can only read it.
How you use it
Pick it under an action's Connection Variable mode, by its scope, such as position.state.camera.
The connection's Variable Key, a dot, then the name: $(ATEM.pgm1_input).
Where you see it
The Variables tab of the element or position that defines it.
The connection's own Variables tab.
The labels in the app follow the same split. On an action, the Mode option Connection Variable means a Connection-type variable picks the connection at runtime. The Connection Variable workflow node and the Connection Variable tally input read one of a connection's own variables.
Most connections publish variables that report their device's state, such as the input on program, a transition rate, or the device's IP address. Which variables exist, if any, depends on the connection's module, and some only appear once the connection has reached the device.
Select Connect in the sidebar, then select the connection.
Open its Variables tab. The number on the tab is how many variables the connection provides.
Each row shows the variable's name, a description, and its current value. Use Search to filter by name or description. Select the clipboard icon at the start of a row to copy the full reference, such as $(ATEM.pgm1_input), ready to paste into a field or expression.
If the tab says No Variables Available, either the connection hasn't reached its device yet or its module doesn't provide any variables. Check the connection's status first.
The full reference is the connection's Variable Key, set on its Config tab, a dot, then the variable's name: for a connection whose Variable Key is ATEM, that's $(ATEM.pgm1_input). The prefix is what tells Buttons which connection you mean, so it's never optional.
A connection's variables are visible everywhere in Buttons, but they're read-only from outside: only the connection updates them as its device changes. One connection can't see or change another connection's variables.
If you run more than one connection using the same module, give each a distinct Variable Key, otherwise you can't tell their variables apart by name.
No two variables visible in the same place can share a name, but variables in different scopes can, safely, precisely because they're never visible together. Use Variable Scope itself as your main tool for avoiding collisions: keep a value in Self or Parent scope unless it genuinely needs to be seen from elsewhere, and reach for Position or Workflow scope only once something actually needs to be global.