Understand how to reference data throughout Tines Formulas
As with Excel or Google Sheets, Formulas consist of multiple components and functions with unique language. Below we define the ways you reference data across Formulas in Tines. Formulas are run using data from previous events, resources, or credentials.
They must be referenced like so:
# accessing properties
my_event.some_prop
💡Note
If your reference data has a property with another character, say a space, then use brackets [] to reference that data:
# accessing properties with spaces
my_event["a prop with a space"]
In the following sections we break down different ways to reference data across Tines formulas. The sections are broken into:
Types to tell the system the structure of the data thus dictating which functions can be applied to the data
Operators to tell the system how to compare data
Functions are actions you can take on the data
Lambdas …
Tags …
Types
Types tell the system the structure of the data. In Tines, the formula language includes the below types, which correspond to the types in standard JSON. System types are text, Boolean, null, numbers, arrays, and objects.
Text
Strings of text. Values must always be wrapped in quotes – both single (‘) or double (“) quotes are accepted. The style does not impact the behavior.
# Double quotes
"this is some text"
# Single quotes
'this is also some text'
Quoted text with a text string is referenced using a backslash (\) at the beginning and end of the quote.
For example: As Einstein said, “Never memorize something that you can look up.”
It would be referenced like this:
# Escaping text
"As Einstein said \"Never memorize something that you can look up.\""
Booleans
True
/False
, or Booleans, are case sensitive. By default, all values are true unless they are FALSE
or NULL
. There is no coercing.
# true
TRUE
# false
FALSE
NULL
Null
values are written with all caps and are falsy:
NULL
# true
IS_BLANK(NULL)
Numbers
Numbers are written in simple notation. They will not include commas.
# number
123
# decimal
123.45
# negative
-123
Arrays
An array, or collection of variables. You can reference an item within an array using square brackets, [], or create an array using the ARRAY
function (learn more about the function here) .
When referencing items in an array, the first item is always position zero, 0. See below:
# my_array = ["first", "second", "third"]
my_array[0]
# "first"
Objects
Usually you will interact with objects that come from your event data, however you can also create an object using the OBJECT
function (learn about the function here).
# referencing an object
OBJECT("key1", "value1", "key2", "value2")
# {key1: "value1", key2: "value2"}
Operators
Operators allow you to compare values or perform basic math on them. Operators must be used together with a function or lambda. Below are a few examples but visit the OPERATOR
section for more:
# check if equal
a = b
# check if greater than
body.count > 1
# multiply
body.count * 5
Functions
Functions perform defined actions on event data. The functions docs go into detail on all the available functions. To help you use functions in real-time, you can see function descriptions and syntax in the product when you hover over a function.
Functions are:
Written in UPPERCASE
Called using its name followed by parentheses, ()
Accept multiple arguments
Can be nested
Learn more about functions including function chaining and lazy evaluation in the Functions section.
#written in UPPERCASE
MY_FUNCTION()
#multiple arguments
MY_FUNCTION(argument1, argument2)
#nested
MY_FUNCTION(FUNCTION1(), FUNCTION2())
Advanced Formulas Language
Below we go into more advanced formulas capabilities for power users.
Lambdas
Lambdas are a custom, reusable function that you create using the LAMBDA
function. This function is a little different from other functions because you specify the placeholders as the arguments to the function.
LAMBDA(a, b, a + b)
Here a
and b
are the arguments that will need to be passed when the lambda is called, and a + b
is the expression that will be evaluated when the lambda is called.
There are three ways of using lambdas: immediately invoked, with an array, or as a local resource.
Immediately invoked
First, they can be immediately invoked i.e. LAMBDA(a, b, a + b)(1, 2)
. This will create a function to add two numbers and then immediately call it. This might not seem very useful, but it can help avoid repetition in cases where you need to reuse the same calculation in multiple places.
For example, if you wanted to check if the current time is between 9 and 5, you might do something like this:
IF(
AND(
DATE("now", "%H") >= 9,
DATE("now", "%H") < 17,
),
"office hours",
"after hours"
)
Using a lambda you could avoid this repetition like so:
LAMBDA(
current_hour,
IF(
AND(
current_hour >= 9,
current_hour < 17,
),
"office hours",
"after hours"
),
)(DATE("now", "%H"))
With an Array function
The next way you can use Lambdas is as an argument to the functions MAP_LAMBDA
, FILTER
, FIND
and REDUCE
.
For example, let's imagine we have the following array of data in a field called fruit
:
[
{
"name": "apple",
"in_stock": 0
},
{
"name": "banana",
"in_stock": 5
},
{
"name": "pear",
"in_stock": 6
}
]
If we wanted to find all the items that are in stock, we could write the following:
FILTER(fruit, LAMBDA(item, item.in_stock > 0))
Or, if we wanted to find the item with the name pear
we could do:
FIND(fruit, LAMBDA(item, item.name = "pear"))
Or, if we wanted to extract all the names, we could do this:
MAP_LAMBDA(fruit, LAMBDA(item, item.name))
As a LOCAL or RESOURCE
The final way you can use lambdas is to assign them to LOCAL
or a RESOURCE
and then call them from somewhere else. This can be a great way of defining your reusable bits of functionality.
Here we have created a lambda for defanging URLs and stored it in a RESOURCE
. The lambda looks like this:
LAMBDA(
url,
url
|> REPLACE(%, ".", "[.]")
|> REPLACE(%, "http", "hxxp")
)
Ensure the lambda in the resource, is defined inside of single value mode:

With this in place, we can use it from any story like so:
RESOURCE.my_lambdas.defang(url)
Tags
Tags are only available in single value mode. You can nest tags inside each other.
There must always be a corresponding end
tag for each tag.
if
elseif
else
endif
These tags all work together to allow you to evaluate sections in text mode conditionally.
At its simplest, you can have an if
and endif
pair:

If this is run with a user named Alice, it will output Hi Alice
, but if the user has no name, it will just output Hi
.
You can also add an else
block to act as a catch-all:

Now, if the user has no name, it will output Hi there
.
Finally, you can add more conditions using elseif
:

You can add as many additional conditions with elseif
as you like.
As mentioned above, formulas do not coerce types, with all but NULL
& FALSE
being truthy. To check if a value is blank write the following:

for
endfor
The for
tag allows you to repeat the same code block multiple times for each item in an array.

This will output User names:
followed by the names of all the users in the array users
.
Within a for
tag, there is a special FORLOOP
variable available with the following properties:
FORLOOP.index0
: The zero-based index of the current loop iteration. That is the first time through the loop, this will be0
, the second time1
, and so on.FORLOOP.index
: The one-based index of the current loop iteration. That is the first time through the loop, this will be1
, the second time2
, and so on.FORLOOP.first
: This will be true the first time through the loop.FORLOOP.last
: This will be true the last time through the loop.
For example, if we wanted to output a comma between every name we could do something like this:
