Dynamic Variables
Overview
Dynamic variables are objects that can be set and accessed within a playbook. Any valid Python object can be a dynamic variable. This includes ints, strings, dictionaries, etc. Variables themselves have no type information associated with them; however, playbook steps do. Steps may attempt to coerce dynamic variables into the expected data type; however, it is mostly on the caller to pass the correct types.
Dynamic variables can be passed to playbook steps as arguments directly, or they may be embedded in a larger string, where they will act more as global variables (or macros), getting replaced by a string representation of themselves.
Syntax
Double curly braces ({{ }}) demarcate dynamic variables from the surrounding text. Anything that goes between the braces is a dynamic variable. The most basic use of the dynamic variable is as a simple dictionary lookup.
![]() |
The general data structure you are using matters within the usage of the dynamic variable. JSON is the easiest data format to consume and use. XML may be converted into JSON directly so that it may also be used. The following examples assume that you are able to use a JSON format. |
Let's look at some examples. Say you have an object (array) named users
which has the following structure:
{
'Alvian': 42,
'Kreb': 413,
'Mandu': 1
}
Example 1
You can then use dynamic variables to access the values of that object.
{{ vars.users.Alvian }}
This statement will evaluate to 42.
Example 2
There are {{ vars.users.Kreb }} Krebs in FortiSOAR.
This statement will evaluate to the string "There are 413 Krebs in FortiSOAR."
Example 3
{{ vars.users.does_not_exist }}
This statement would evaluate to an error and would be displayed as:
no such element: users['does_not_exist']
Example 4
Say you modified the object (array) named users
to have the following structure:
{
'Alvian': 42,
'Kreb': {
'original': 413,
'pi': 3.14
},
'Mandu': 1
}
To access the secondary array is as easy as adding an additional key for the key-value pair you desire to access.
{{ vars.users.Krebs.pi }}
This statement would evaluate to 3.14. An alternative format for accessing the variable, which may be used in case of special characters present, is:
{{ vars.users['Krebs']['pi'] }}
This statement would evaluate identically to the previous, 3.14.
Implementation
The major driving force behind dynamic variables is Jinja2 templates. A general overview of how Jinja2 works can be found here.
Specifically, to render a template, Jinja takes two arguments: a context and a template string. The template string is the dynamic variable itself, which is provided by users in the playbook. The context object, on the other hand, will be created automatically before each and every playbook step. It contains various helper functions as well as the internal representation of the dynamic variable data.
Scope
Scope for dynamic variables is defined by the COPY_ENV_FOR_REFERENCE_WORKFLOW
setting. Use this setting to pass variables to a reference playbook.
By default, the COPY_ENV_FOR_REFERENCE_WORKFLOW
is set to false
.
Functionality
There are several top-level objects that can be accessed within a dynamic variable.
Dictionary-like Objects
Most ordinary variables are stored under the vars namespace. Whenever a variable is declared using: class:workflow.tasks.set_variable
, it will go under vars
. Additionally, the playbook engine will automatically set the following variables:
vars.result
: This contains the return value of the previous playbook step.vars.input.records
: This contains information about what triggered a playbook, i.e., the body of the inbound request.vars.request.headers
: This contains the metadata of all the headers that are part of the playbooks environment, and which can be used in the playbooks, such asX-RUNBYUSER
which is a jinja template to retrieve the name of the user who triggered the playbook. Some other parameters are, trigger type, authorization, accept, host, content-type, etc.vars.input.params.api_body
: This contains the data passed from a Custom API Endpoint trigger.
Built-in Functions & Filters
Functions
arrow
: Datetime functions:
{{ arrow.utcnow().int_timestamp }}
In version 7.0.0, FortiSOAR has updated the arrow library, due to which the timestamp
attribute has been changed into int_timestamp
for DateTime jinja expressions, . For more information see, https://arrow.readthedocs.io/en/latest/releases.html#id4
![]() |
New playbooks must use the |
More documentation can be found here
uuid
: returns a uuid using python'suuid.uuid4()
function
{{ uuid() }}
Filters
See the Jinja Filters and Functions chapter for information.
FAQS
How are dynamic variables used in condition steps?
Decision steps use dynamic variables with logical equalities of the form:
{{ 8 == 8 }}
This statement will return either the string 'True,' or 'False' which will automatically be converted into a real boolean value.
![]() |
Decision steps advanced interface does not require the use of curly braces like |