> Synerise Documentation — Inserts > > This file contains the complete "Inserts" section of the Synerise documentation. Each article begins with a top-level "# " heading. The manifest listing all sections is at https://hub.synerise.com/llms-full.txt # Insert usage ## Insert usage examples This section presents some practical examples and mechanisms of inserts. In inserts, you use: - Jinjava elements (values), inserted in the following way: `{{ ... }}` Such a value will be printed in the place where it's used. - tags, which are statements that allow you to use functions and build logic. They are inserted in the following ways: `{% ... %}`, `{%- ... -%}` (see ["Tag delimiters"](/developers/inserts/tag#tag-delimiters))
{%- set p = "world" -%}{{ "Hello, " ~ p ~ "!" }} = Hello, world! |
### Objects and arrays
#### Object properties
You can access object properties in the following ways:
- `object.get('property')` - accepts special characters in property names.
- `object.property` - doesn't accept special characters in property names.
- `object['property']` - accepts special characters in property names.
If there is a chance that a property doesn't exist, you need to verify if it's defined, using tests such as [`is defined`](/developers/inserts/exptest#isdefined). Otherwise, rendering might fail or there might be nulls or whitespaces in rendered output.
**Examples**:
{% set exampleProduct = {'size':12,'prop:title':'Item'} %}
{{ exampleProduct.get('size') }} {# renders successfully #}
{{ exampleProduct['size'] }} {# renders successfully #}
{{ exampleProduct.size }} {# renders successfully #}
{{ exampleProduct.get('prop:title') }} {# renders successfully #}
{{ exampleProduct['prop:title'] }} {# renders successfully #}
{{ exampleProduct.prop:title }} {# error in rendering the template (special character in name) #}
{% if exampleProduct.get('color') is defined %} {# verify if property exists to avoid unexpected behavior #}
{{ exampleProduct.get('color') }}
{{ exampleProduct['color'] }}
{{ exampleProduct.color }}
{% endif %}
#### Arrays
You can access values from an array by referring to the index:
{% set exampleArray = [1,2,3] %}
{{ exampleArray[0] }} {# output: 1 #}
{{ exampleArray[2] }} {# output: 3 #}
{% if exampleArray | length > 4 %} {#RECOMMENDED: to avoid errors, verify array size before accessing an index #}
{{ exampleArray[4] }}
{% else %}
Index 4 is out of range
{% endif %}
#### Nested arrays and objects
An object can contain objects and arrays:
{% set exampleObject = {'nestedObject':{'size':12}} %}
{{ exampleObject.nestedObject }} {# output: {size=12} #}
{{ exampleObject.nestedObject.size}} {# output: 12 #}
An array can contain objects and arrays:
{% set exampleArray = [{'size':12,'prop:title':'Item'},{'size':14,'prop:title':'Item2'}] %}
{{ exampleArray[0] }} {# output: {size=12, prop:title=Item} #}
{{ exampleArray[1].size }} {# output: 14 #}
### Expressions
To find out what expressions are and how to create them, read [this article](/docs/crm/expressions).
{% expression %} expression-hash {% endexpression %}
**Example:**
An expression that holds the value of an abandoned cart.
<h1>
Total amount: {% expression %} 4085025a-313e-4a63-a6b4-d19820853912 {% endexpression %}$
</h1>
Output:
<h1>
Total amount: 345$
</h1>
You can also use the expression result as a variable:
{% expressionvar expression-hash %}
{{ expression_result }} {# the result of the expression is stored in this variable #}
{% endexpressionvar %}
**Example**:
The result of an expression that is a number can be rounded:
{% expressionvar 0abc195a-548e-460d-a904-1e285b8adb96 %}
You have {{ expression_result|round }} loyalty points.
{% endexpressionvar %}
### Aggregates
To find out what aggregates are and how to create them, read [this article](/docs/crm/aggregates/creating-profile-aggregates).
{% aggregate aggregate-hash %}
{{ aggregate_result[0] }}
{% endaggregate %}
{% aggregate 0b352529-497e-3cbd-bf3d-fcb6072cef9e %}
<ul>
{%- for item in aggregate_result -%}
<li>{{ item }}</li>
{%- endfor -%}
</ul>
{% endaggregate %}
Output:
<ul>
<li>Home</li>
<li>Sports</li>
<li>Toys</li>
<li>Electronics</li>
</ul>
{%- set getFields=["code"] -%}
{%- promotions fields=getFields [optional arguments] -%}
{{ promotions_result }}
{%- endpromotions -%}
where:
- `getFields` is a variable that declares the promotion properties you want to include in the result.
In this example, only one property is retrieved.
{%- set getFields=["code","discountValue","images"] -%}
{%- promotions fields=getFields -%}
You have available promotions!<br>
{%- for i in promotions_result -%}
Code: {{ i.code }}<br>
Discount: {{ i.discountValue }} USD<br>
<img src="{{ i.images[0].url }}"><br>
<br>
{%- endfor -%}
{%- endpromotions -%}
You have available promotions!<br>
Code: d139125e-88a2-4146-a1b3-d766b94d859d<br>
Discount: 100 USD<br>
<img src="https://upload.snrcdn.net/f2afa4d4d7af216196047d1f7f0613f22a50a8c8/default/origin/f8fa57fa59egrhfgh11987845c19c5c.png"><br>
<br>Code: 501000d9-5f96-4362-9350-eccf592e4e4b<br>
Discount: 20 USD<br>
<img src="https://upload.snrcdn.net/f2afa4d4d7af216196047d1f7f0613f22a50a8c8/default/origin/50d289eff4234tr78a900cdf3bee.png"><br>
<br>Code: 089a9ab2-0171-4eb4-93a5-8d2e12822be1<br>
Discount: 15 USD<br>
<img src="https://upload.snrcdn.net/f2afa4d4d7af216196047d1f7f0613f22a50a8c8/default/origin/7af3145sdffgh3acd0124a25a91.png"><br>
<br>
{%- set getFields = ["code"] -%}
{%- set filterTags = ["foo","bar"] -%}
{%- set sort = ["createdAt,desc"] -%}
{%- promotions fields=getFields displayableOnly=true tagNames=filterTags sort=sort -%}
{{ promotions_result }}
{%- endpromotions -%}
### Personalized promotions
{%- set handbillUuidVar=["UUID"] -%}
{%- handbills handbillUuids=handbillUuidVar [optional arguments] -%}
{{ handbills_result }}
{%- endhandbills -%}
where:
- `handbillUuids` is a list of personalized promotions (handbills) to assign and retrieve. The value must be stored in a variable (`handbillUuidVar` in the snippet above).
- `optional arguments` can be used to filter the results.
See ["Optional arguments"](#optional-arguments-2).
- `handbills_result` is an array of retrieved promotions.
To learn about the returned parameters, see the response of the ["Generate batch handbill for Profile and get Profile promotions" endpoint in the API reference documentation](https://hub.synerise.com/api-reference/loyalty-and-engagement#tag/Handbills/operation/getAssignHandbillsForClient_GET).
This output shows 2 promotions.
`[{handbillUuid=3f56de5a-b560-456d-8c94-cb63bc0c53be, currentRedeemedQuantity=0, headline=, name=test1, priority=250, discountType=NONE, discountValue=0, redeemQuantityPerActivation=1, description=, currentRedeemLimit=0, tags=null, uuid=86c67c62-0b70-4144-a986-688510d00332, redeemLimitPerClient=1000, price=1, params=null, possibleRedeems=0, assignedAt=2025-07-29T14:23:14.057Z, discountMode=STATIC, maxBasketValue=null, activationCounter=0, expireAt=null, code=d98cca9b-e7c0-4639-8bdc-a1d0441068cc, itemScope=LINE_ITEM, displayFrom=null, startAt=null, status=ASSIGNED, lastingAt=2025-07-30T14:23:14.046Z, catalogIndexItems=[Ljava.lang.Object;@75377931, details=null, displayTo=null, lastingTime=0, type=HANDBILL, requireRedeemedPoints=0, minBasketValue=null, images=[Ljava.lang.Object;@2b3c4cdf, discountModeDetails=null}, {currentRedeemedQuantity=0, headline=null, name=test2, priority=250, discountType=AMOUNT, discountValue=0, redeemQuantityPerActivation=null, description=null, currentRedeemLimit=null, tags=null, uuid=01caa294-5d81-4130-ab44-a7427f0ff779, redeemLimitPerClient=324, price=0, params=null, possibleRedeems=1, discountMode=STEP, maxBasketValue=null, activationCounter=0, expireAt=null, code=1067d8f5-1460-4387-abeb-8a4a3e97ec35, itemScope=LINE_ITEM, displayFrom=null, startAt=null, status=ASSIGNED, lastingAt=null, catalogIndexItems=null, details=null, displayTo=null, lastingTime=0, type=GENERAL, requireRedeemedPoints=0, minBasketValue=null, images=null, discountModeDetails={discountUsageTrigger=REDEEM, steps=[Ljava.lang.Object;@41e37d59}}]`
{%- set handbillUuidVar=["3f56de5a-b560-456d-8c94-cb63bc0c53be","c35d0a9-08b1-4c4f-a8cd-0732b1c00b7f"] -%}
{%- handbills handbillUuids=handbillUuidVar -%}
You have available promotions!<br>
{%- for i in handbills_result -%}
{{ i.name }}<br>
<img src="{{ i.images[0].url }}"><br>
<br>
{%- endfor -%}
{%- endhandbills -%}
You have available promotions!<br>
Hot dog + soda<br>
<img src="https://upload.snrcdn.net/f2afa4d45c19c5c.png"><br>
Cheeseburger 50% off<br>
<img src="https://upload.snrcdn.net/fr78a900cdf3bee.png"><br>
Apple pie + coffee<br>
<img src="https://upload.snrcdn.net/f2afd0124a25a91.png"><br>
<br>
{%- set handbillUuidVar=["3f56de5a-b560-456d-8c94-cb63bc0c53be"] -%}
{%- set typeFilterVar=["HANDBILL"] -%}
{%- set statusFilterVar=["ACTIVE","ASSIGNED"] -%}
{%- handbills handbillUuids=handbillUuidVar type=typeFilterVar status=statusFilterVar limit=5 -%}
{%- for i in handbills_result -%}
<img src="{{ i.images[0].url }}"><br>
{%- endfor -%}
{%- endhandbills -%}
### Recommendations
#### Recommendations as Jinjava variable
{% recommendations3 campaignId=campaignId %}
{{recommended_products3}}
{% endrecommendations3 %}
You can find more information, examples, and advanced scenarios in [Inserting recommendations](/developers/inserts/recommendations-v2).
#### Recommendations as JSON
This insert is only available in [Screen Views and Documents](/developers/inserts/screen-views-documents#recommendations).
### Catalogs
To find out what catalogs are and how to create them, read [this article](/docs/assets/catalogs).
#### Extracting values from catalogs
The following method lets you obtain a single value from a catalog.
**Syntax:**
{% catalog.catalogName(itemKey).columnName %}
Or as a variable that you can modify:
{% catalogvar.catalogName(itemKey).columnName %}
{{ catalog_result }}
{% endcatalogvar %}
where:
- `catalogName` is the name of the catalog
- `itemKey` is the value of the unique identifier of the item in the catalog.
This is the value from the column which you selected as **itemKey** (for data imports by API) or **Primary key** (when importing data into the catalog in the Synerise Portal or with Automation Hub).
- `columnName` is the name of the column (attribute) in the item whose value you want to retrieve.
{% set myitemKey = "1234" %}
{% catalog.catalogName(myitemKey).columnName %}
WRONG:
{% catalog.catalogName("1234").columnName %}
<ul>
{% aggregate 0b352529-497e-3cbd-bf3d-fcb6072cef9e %}
{%- for sku_value in aggregate_result -%}
<li id="{% catalog.myCatalog(sku_value).product:retailer_part_no %}">
<a href="{% catalog.myCatalog(sku_value).og:url %}" title="{% catalog.myCatalog(sku_value).og:title %}">
<img src="{% catalog.myCatalog(sku_value).og:image %}">
</a>
</li>
{%- endfor -%}
{% endaggregate %}
</ul>
1. An [aggregate](#aggregates) (line 2) returns a list of 10 SKUs of recently viewed products.
The SKUs will be used as identifiers to retrieve more data about those products from a catalog and display them on a website.
2. On line 3, a loop starts that runs for each SKU in that list.
- `sku_value` is an example name of the iterator variable. You can change it. The value of the iterator is the SKU from the aggregate result.
- `aggregate_result` is the name of the iterable. The `aggregate` insert from line 2 creates this iterable, always under this name.
3. On lines 4-6, attributes from the `myCatalog` catalog are accessed:
1. SKU was set to be the unique item identifier in the catalog when data was imported into `myCatalog`.
2. `sku_value` is replaced with the current iterator value in each iteration of the loop, so the item identified by the SKU is accessed.
3. The values of the following columns are retrieved:
- `product:retailer_part_no`
- `og:url`
- `og:title`
- `og:image`
Output:
<ul>
<li id="000097">
<a href="https://example.com/accessories-for-shaver/cleaner-contribution-to-shavers,id-2369"
title="Cleaning insert for shavers">
<img src="https://example.com/temp/thumbs-new/2/other/cd1c73e35b1db186e79e8a0039b27293_250x200w50.jpg">
</a>
</li>
<li>...</li>
<li>...</li>
<li>...</li>
<li>...</li>
<li>...</li>
<li>...</li>
<li>...</li>
<li>...</li>
<li>...</li>
</ul>
#### Extracting items from catalogs as objects
You can retrieve an entire item as an object and extract values of multiple columns at once using the following syntax:
{% set key = 'itemKey' %}
{% catalogitemv2.catalogName(key) allowEmpty=False %}
{% set object = catalog_result %}
{{ object.get("objectColumn").propertyName }}
{{ object.get("stringColumn") }}
{% endcatalogitemv2 %}
where:
- `itemKey` is the unique key of the item in the catalog
- `catalogName` is the catalog name
- `objectColumn` is the name of the column that stores an object
- `propertyName` is the name of a property in the object
- `stringColumn` is the name of the column that stores a string
- `allowEmpty` is an optional parameter that [manages the handling of non-existing items](#handling-non-existing-items-in-catalogs).
The above code, without any changes, will return `foo` and `bar` for the following catalog:

{% set key = 'itemKey' %}
{% catalogitemv2.catalogName(key) allowEmpty=True%}
{% set object = catalog_result %}
{%- if object.get("name") is defined -%}
{{ object.get("name") }}
{%- else -%}
No item
{%- endif -%}
{% endcatalogitemv2 %}
### Metrics
To find out what metrics are and how to create them, read [this article](/docs/analytics/metrics).
**Syntax:**
{% metrics %} metrics-hash {% endmetrics %}
Or as a variable that you can modify:
{% metricsvar metric_id:metrics-hash %}
{{ metric_result }}
{% endmetricsvar %}
**Example:**
A metric that holds the value of products sold in the last 30 days.
{% metricsvar metric_id:07e93207-4dd4-4239-ab1a-9267118276b0 %}
{% set result = metric_result|int %}
{%- if result > 4500 -%}
Bravo! we achieved the set goal
{%- else -%}
{{ 4500 - result }} USD more to get a goal
{%- endif -%}
{% endmetricsvar %}
Output (the metric result is 2400):
2100 USD more to get a goal
### Customer attributes
You can access customer attributes, such as the name, surname, email, phone number, and more and use them as variables.
By means of those variables, you can personalize the content, for example you can use the name of the customer in the greeting at the beginning of an email.
**Syntax:**
{% customer attr-name %}
**Example:**
A welcome message.
<div class="snrs-wrapper">
<div id="snrsCornerMessage" class="snrs-corner-message-wrap">
<div class="snrs-corner-message">
<div class="snrs-corner-main">
<div class="snrs-corner-message-text">
Hello {% customer firstname %}!
</div>
</div>
</div>
</div>
</div>
Output (the result of the variable is "John"):
<div class="snrs-wrapper">
<div id="snrsCornerMessage" class="snrs-corner-message-wrap">
<div class="snrs-corner-message">
<div class="snrs-corner-main">
<div class="snrs-corner-message-text">
Hello John!
</div>
</div>
</div>
</div>
</div>
#### Inserting attributes conditionally
If you're not sure if an attribute is present in the profiles of all target customers, you can use conditional logic.
For example:
Hello {%- if customer.get('firstname') -%}{{ customer.firstname }}{%- else -%}user{%- endif -%}!
Output:
- If the `firstname` attribute is `John`: `Hello John!`
- If the `firstname` attribute does not exist: `Hello user!`
{%- if "club_member" in customer.keySet() -%} {# checks if the club_member attribute exists #}
{%- if customer["club_member"] == "highPriority" -%}
{# insert HTML code #}
{%- elif customer["club_member"] == "mediumPriority" -%}
{# insert HTML code #}
{%- elif customer["club_member"] == "lowPriority" -%}
{# insert HTML code #}
{%- endif -%}
{%- endif -%}
**Example 2:**
Check if the customer profile includes an entry about the city of residence:
{%- if "city" in customer.keySet() -%}
Check the best prices in {{ customer["city"] }}!
{%- else -%}
Check the best prices in your city!
{%- endif -%}
### Code pools
To find out what code pools are and how to create them, read [this article](/docs/assets/code-pools).
Normally, each code can only be retrieved once. You can override this behavior by [binding the code to a profile](#retrieving-the-same-code-every-time). This code is stored separately, so you can bind a code and still assign other codes (only one code can be bound to a profile). For example, you can bind a code and use it to identify a profile, and still retrieve codes from other pools to use in marketing campaigns.
When a code is assigned or bound to a profile, a [voucherCode.assigned](/docs/assets/events/event-reference/loyalty#vouchercodeassigned) event is generated.
{% voucher %} pool-uuid {% endvoucher %}
If the code pool is empty, doesn't exist, or no more codes are available, the insert fails to render. You can use [try/catch statements](/developers/inserts/tag#trycatch) to handle such cases.
**Example:**
A promotion code from a selected code pool:
<div class="snrs-wrapper">
<div id="snrsCornerMessage" class="snrs-corner-message-wrap">
<div class="snrs-corner-message">
<div class="snrs-corner-main">
<div class="snrs-corner-message-text">
Take your promotional code and use it durning the transaction to get a 50% discount!
<strong>{% voucher %} 274a18d5-e8bd-4fec-82d1-cea0af19af01 {% endvoucher %}</strong>
</div>
</div>
</div>
</div>
</div>
Output (voucher result is "5510018091219"):
<div class="snrs-wrapper">
<div id="snrsCornerMessage" class="snrs-corner-message-wrap">
<div class="snrs-corner-message">
<div class="snrs-corner-main">
<div class="snrs-corner-message-text">
Take your promotional code and use it during the transaction to get a 50% discount!
<strong>5510018091219</strong>
</div>
</div>
</div>
</div>
</div>
#### Using the code as a variable
By using the `vouchervar` tag, you can create a block of code in which the code can be accessed as the `voucher_result` variable.
If the code pool is empty, doesn't exist, or no more codes are available, the insert fails to render. You can use [try/catch statements](/developers/inserts/tag#trycatch) to handle such cases.
**Syntax:**
{% vouchervar id=pool-uuid %}
{{ voucher_result }}
{% endvouchervar %}
**Example:**
In this example, the voucher's value is accessible as a variable and can be converted to capital letters.
{% vouchervar id=5fae8aba-b48e-4144-8d28-db24b1570ab0 %}
<ul>
<li>The voucher value is {{ voucher_result }}.</li>
<li>When capitalized, it becomes {{ voucher_result|capitalize }}.</li>
</ul>
{% endvouchervar %}
The output (the voucher's value is "CapitalizeMe") is:
<ul>
<li>The voucher value is CapitalizeMe.</li>
<li>When capitalized, it becomes CAPITALIZEME.</li>
</ul>
#### Retrieving the same code every time
Setting the `assign` variable to `false` binds a code from a pool to a profile (unless one is already bound) and retrieves that same code for this profile every time. This can be used, for example, to create unique codes that can be used to identify a profile.
Binding codes doesn't have any influence on assigning codes (described earlier).
{% voucher assign=false %} pool-uuid {% endvoucher %}
#### Barcodes
To add a barcode of a voucher to an email template, paste the following code:
{% vouchervar id=pool-uuid %}
{% barcode code= {{voucher_result}}, gray=true, type=EAN_13, hrp=BOTTOM %}
{% endvouchervar %}
The result of that insert will be the HTML code for the image of the barcode.
If you want to get only the URL of the barcode, use the following code:
{% vouchervar id=pool-uuid %}
{% barcodeurl code= {{voucher_result}}, gray=true, type=EAN_13, hrp=BOTTOM %}
{% endvouchervar %}
**Explanation of parameters**:
- `pool-uuid` is the UUID of a voucher pool available on the platform (**Data Modeling Hub > Voucher pools**).
- `gray` defines the color of the barcode. Parameter values:
- `TRUE` - The code is generated in grayscale.
- `FALSE` - The code consists of black and white pixels.
- `type` defines the type of barcode. Parameter values:
- `EAN_13`
- `EAN_8`
- `EAN_128`
- `CODE_39`
- `CODE_128`
- `ITF_14`
- `POSTNET`
- `UPC-A`
- `UPC-E`
- `hrp` (*human readable part*) defines the position of the readable part of the code for customers (usually it takes the form of a string of numbers). Parameter values:
- `NONE` - There is no readable part of the code.
- `BOTTOM` - The readable string is at the bottom of the barcode.
- `resolution` defines the resolution of a bar code in dpi and indirectly affects the width of the narrowest bar.
### Snippets
You can reference a [snippet](/docs/assets/snippets). The content generated from such a reference is updated when the referenced definition changes.
Print the contents of the referenced snippet:
{% snippet %} 6197adde-e1da-4ef1-be40-aa411e2fbdff {% endsnippet %}
Save the referenced snippet to a variable:
{% snippetvar id=6197adde-e1da-4ef1-be40-aa411e2fbdff %}
{{ snippet_result }}
{% endsnippetvar %}
Such a variable can be used in functions.
For example, if the referenced snippet contains a number, you can add it to another number:
{% snippetvar id=6197adde-e1da-4ef1-be40-aa411e2fbdff %}
{{ snippet_result|add(5) }}
{% endsnippetvar %}
### Communication campaign metadata
You can access the ID and variant ID of the communication campaign. Thanks to this, you don't need to manually edit those details after cloning a campaign or copying content between templates.
| Jijava | Example result | Description |
| --- | --- | --- |
| `{{campaignContext.id}}` | `f3ac122e-9305-441c-9081-79d32b5cf06d` | The ID of the communication campaign |
| `{{campaignContext.variantId}}` | `15761220` | ID of the variant. Can be used in all campaign types except for landing pages. |
| `{{campaignContext.version}}` | `2025-06-23T10:36:51.927532232` | Version number. Can only be used in landing pages. |
### Stopping communication from rendering
You can use the `{% terminate [message] %}` insert to completely stop the message from rendering, which means an email is not sent at all, a dynamic content is not displayed, and so on.
When this tag is triggered, a `notSent` ([message](/docs/assets/events/event-reference/email#messagenotsent), [sms](/docs/assets/events/event-reference/sms#smsnotsent), [push](/docs/assets/events/event-reference/mobile-push#pushnotsent), [webpush](/docs/assets/events/event-reference/webpush#webpushnotsent)) or `renderFail` ([inApp](/docs/assets/events/event-reference/inapp#inapprenderfail), [landingpage](/docs/assets/events/event-reference/landing-page#landingpagerenderfail)) is generated. In the event:
- the `exception` (SMS, email, push, web push) or `error` (in-app, landing page) parameter is added, with the value set to `TerminateRenderingException`
- if you added the `message` parameter to the insert, it's saved in the `info` parameter. Otherwise, the default message is `Jinja rendering terminated by user`.
The message doesn't support Jinjava.
This can be useful when you want to terminate a communication when a certain condition is met.
For example, the following communication:
- is terminated for customers whose result of an expression is less than 100.
- informs a customer about the result of the expression if it's 100 or more.
- adds "Expression result too low" as the `info` parameter in the "not sent" event.
{% expressionvar expression-hash %}
{%- if expression_result < 100 -%}
{% terminate Expression result too low %}
{%- else -%}
You have {{ expression_result }} loyalty points.
{%- endif -%}
{% endexpressionvar %}
{% set myFieldContext = {"oneToManyRelation": {"page":2, "limit": 50}} %}
{% set myContext={
"example1":"value1",
"example2":"value2"
}
%}
{% brickworksgenerate schemaId=SCHEMA_ID/APP_ID recordId=RECORD_ID/SLUG context=myContext fieldContext=myFieldContext %}
where:
- The values for the `context` and `fieldContext` arguments must be variables created with `set` (as shown above).
- `myFieldContext` provides paging data for a relation field named `oneToManyRelation`. You can skip this argument if you don't need it.
- `myContext` provides values for two inserts used in the record (regardless of field names): `{{ context.example1 }}` and `{{ context.example2 }}`. You can skip this argument if you don't need it.
Alternatively, you can use `brickworksgeneratevar` to create a `{{ brickworks_result }}` variable for reuse in a template:
{% brickworksgeneratevar schemaId=SCHEMA_ID/APP_ID recordId=RECORD_ID/SLUG context=myContext fieldContext=myFieldContext %}
{{ brickworks_result }} {# prints out the entire record #}
{{ brickworks_result.someString }} {# prints out the value of the someString field #}
{% endbrickworksgeneratevar %}
#### Fetch raw record
This tag can't be used in Brickworks schemas or records. In Documents and Screen Views, if you want to display an entire object instead of just one property, you need to use `{{ brickworks_result|tojson }}`
In singleton schemas, use the API name (`appName`) or UUID of the schema in place of the record identifier.
- The following tag fetches a raw record as defined in the database:
{% brickworks schemaId=SCHEMA_ID/APP_ID recordId=OBJECT_ID/SLUG %}
- The following tag fetches a raw record as defined in the database, but saves the result to a variable for reuse in your template:
{% brickworksvar schemaId=SCHEMA_ID/APP_ID recordId=OBJECT_ID/SLUG %}
{{ brickworks_result }}
{% endbrickworksvar %}
#### Fetch raw records
This tag lets you retrieve multiple records (raw content) from a schema and access the result as an iterable.
This tag can't be used in Brickworks schemas or records. In Documents and Screen Views, if you want to display an entire object instead of just one property, you need to use `{{ brickworks_result|tojson }}`
{% brickworksrecordsvar schemaId=ID/APPID [optional parameters] %}
{# example logic: iterate through result and return record IDs #}
{% for record in brickworks_result %}
{{ record.id }}
{% endfor %}
{# end example logic #}
{% endbrickworksrecordsvar %}
where:
- `schemaId` is the App ID or UUID of a schema.
- `optional parameters` can be used to sort and filter the retrieved records:
- The parameters can be applied in two ways (see [examples](#filtering-examples)):
- as arguments in the tag.
In this case, `slugs`, `ids`, and `filters` must be declared with `set` first.
- as a `filteringParams` object. If you insert the same parameter in both ways, `filteringParams` takes precedence.
- You can use these parameters:
- `sortBy`: a record attribute to sort by and the sorting direction.
**This parameter can't be added to `filteringParams`**
For a list of sorting attributes, see the [/v1/schemas/{schemaIdentifier}/records (Get records) endpoint](https://hub.synerise.com/api-reference/brickworks#tag/Brickworks:-Records/operation/getRecordsFromSchema).
- `search`: a string to search for in the values of fields which are [configured as searchable in the schema](/docs/assets/brickworks/schema-field-types#common-field-properties).
- `filters`: an RSQL string to filter the records.
These following system parameter names must include the `__` prefix: `__id`, `__schemaId`, `__name`, `__slug`, `__status`, `__createdAt`, `__updatedAt`, `__publishedAt`, `__recordVersion`
- `slugs`: a list of record slugs. Looks for exact matches.
- `ids`: a list of record IDs. Looks for exact matches.
{% set parametersVar = {
search: "string",
filters: "status==PUBLISHED",
slugs: ["string","string"],
ids: ["uuid","uuid"]
} %}
{% brickworksrecordsvar
schemaId=string
filteringParams=parametersVar %}
{{ brickworks_result }}
{% endbrickworksrecordsvar %}
{% set filtersVar = "status==PUBLISHED" %}
{% set slugsVar = ["string","string"] %}
{% set idsVar = ["uuid","uuid"] %}
{% brickworksrecordsvar
schemaId=string
search=string
sortBy=createdAt:asc
filters=filtersVar
slugs=slugsVar
ids=idsVar
%}
{{ brickworks_result }}
{% endbrickworksrecordsvar %}
{{ [1, 2, 3] is containingall [2, 3] }}
## IsContaining
Returns `true` if a list contains the provided value.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| list | yes | If this list contains the value provided in the parameters, the test returns `true`. |
**Parameters:**
| Type | Required | Description |
| :--- | :--- | :--- |
| object | yes | The value to search for in the input list |
**Example:**
{{ [1, 2, 3] is containing 2 }}
## IsDefined
Returns `true` if the variable is defined.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| object | yes | The variable to check |
**Example:**
{%- if foo is defined -%}
{# code to render if foo is defined #}
{%- else -%}
{# code to render if foo is not defined #}
{%- endif -%}
## IsDivisibleBy
Returns `true` if a variable is divisible by a number.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| number | yes | The variable to check against the divisor |
**Parameters:**
| Type | Required | Description |
| :--- | :--- | :--- |
| number | yes | The divisor |
**Example:**
{%- if foo is divisibleby 5 -%}
{# code to render if foo can be divided by 5 #}
{%- else -%}
{# code to render if foo cannot be divided by 5 #}
{%- endif -%}
## IsEqualTo
Returns `true` if an object has the same value as another object.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| object | yes | First object for comparison |
**Parameters:**
| Type | Required | Description |
| :--- | :--- | :--- |
| object | yes | Second object for comparison |
**Example:**
{%- if foo is equalto 42 -%}
the foo attribute evaluates to the constant 42
{%- endif -%}
Usage with the selectattr filter:
{{ users|selectattr("email", "equalto", "foo@bar.invalid") }}
## IsEven
Returns `true` if a value is an even number.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| number | yes | The number to check |
**Example:**
{%- if foo is even -%}
{# code to render if foo is an even number #}
{%- else -%}
{# code to render if foo is an odd number #}
{%- endif -%}
## IsIterable
Returns `true` if the object is iterable (for example, a sequence).
{%- if foo is iterable -%}
{# code to render if foo is iterable #}
{%- endif -%}
## IsLower
Returns `true` if a string is all lowercase.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | The string to check |
**Example:**
{%- if foo is lower -%}
{# code to render if the value of foo is all lowercase #}
{%- endif -%}
## IsMapping
Returns `true` if an object is a dictionary.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| object | yes | The object to check |
**Example:**
{%- if foo is mapping -%}
{# code to render if foo is a dictionary #}
{%- endif -%}
## IsNumber
Returns `true` if the object is a number.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| object | yes | The object to check |
**Example:**
{%- if foo is number -%}
{{ foo * 1000000 }}
{%- else -%}
foo is not a number.
{%- endif -%}
## IsOdd
Returns `true` if a number is an odd number.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| number | yes | The number to check |
**Example:**
{%- if foo is odd -%}
{# code to render if foo is an odd number #}
{%- else -%}
{# code to render if foo is an even number #}
{%- endif -%}
## IsSameAs
Returns `true` if a variable points at same object as another variable.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| object | yes | The first variable to compare |
**Parameters:**
| Type | Required | Description |
| :--- | :--- | :--- |
| object | yes | The second variable to compare |
**Example:**
{%- if var_one is sameas var_two -%}
{# code to render if the variables have identical values #}
{%- endif -%}
## IsSequence
Returns `true` if the variable is a sequence. Sequences are variables that are iterable.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| object | yes | The object to check |
**Example:**
{%- if foo is sequence -%}
{# code to render foo is a sequence #}
{%- endif -%}
## IsStringContaining
Returns `true` if an object is a string which contains a specified other string.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | The string that needs to contain the string provided as the parameter |
**Parameters:**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | The string that needs to be included in the string provided as input |
**Example:**
{%- if foo is string_containing 'bar' -%}
{# code to render if foo contains 'bar' #}
{%- endif -%}
## IsString
Returns `true` if an object is a string.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| object | yes | The object to check |
**Example:**
{%- if foo is string -%}
{# code to render if foo is a string #}
{%- endif -%}
## IsStringStartingWith
Returns `true` if an object is a string which starts with a specified other string.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | The string that needs to start with the string provided as the parameter |
**Parameters:**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | The string to check against |
**Example:**
{%- if foo is string_startingwith 'bar' -%}
{# code to render if foo starts with 'bar' #}
{%- endif -%}
## IsTruthy
Returns `true` if a value is *truthy*. `IsTruthy` follows the same implicit conversion rules as `{% if %}` conditions. For `==` and `!=`, type conversion applies only when the other operand is a boolean.
| Input type | Returns `true` | Returns `false` |
| :--- | :--- | :--- |
| Boolean | `true` | `false` |
| Number | Any non-zero number | `0` |
| String | Any non-empty string, except `"false"` | `""` (empty string) or `"false"` |
| null | Never | Always |
| Collection (list, map) | Non-empty | Empty |
| Any other type | Always | Never |
{%- if foo is truthy -%}
{# code to render if foo is truthy #}
{%- endif -%}
{%- if foo is undefined -%}
{# code to render if foo is undefined #}
{%- endif -%}
## IsUpper
Returns `true` if a string is all uppercase.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | The string to check |
**Example:**
{%- if foo is upper -%}
{# code to render if foo is a string and is all uppercase #}
{%- endif -%}
## IsWithin
Returns `true` if a value is contained in a list.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| object | yes | The value to search for in the list |
**Parameters:**
| Type | Required | Description |
| :--- | :--- | :--- |
| list | yes | The list to search in |
**Example:**
{{ 2 is within [1, 2, 3] }}
# Jinjava filters
Jinjava filters let you perform operations on values, such as rounding or formatting. If a filter has more than one parameter, the parameters are listed in the order they need to be provided.
{% set my_number = -53 %}
{{ my_number|abs }} {# returns 53 #}
## add
Adds a number to the existing value.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| number | yes | The number to which the variable/number in the parameters will be added |
**Parameters:**
| Type | Required | Description |
| :--- | :--- | :--- |
| number | yes | A number/variable |
**Example:**
{% set my_num = 40 %}
{{ my_num|add(13) }} {# returns 53 #}
## attr
Renders the attribute of a dictionary.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| object | yes | The dictionary that contains an attribute |
**Parameters:**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | The name of the attribute to render |
**Example:**
The filter example below is equivalent to rendering a variable that exists within a dictionary, such as content.absolute_url.
{% set content = {'absolute_url': 'https://example.com'} %}
{{ content|attr('absolute_url') }}
Output:
https://example.com
## base64 encode/decode
You can encode/decode values with base64.
{% set foo = "example@synerise.com"|base64Encode %}
{{ foo }}
{# returns ZXhhbXBsZUBzeW5lcmlzZS5jb20= #}
{% set baz = foo|base64Decode %}
{{ baz }}
{# returns "example@synerise.com" #}
## batch
A filter that divides items in a list into groups.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| list | yes | A sequence or dict to apply the filter to |
**Parameters:**
| Type | Required | Description |
| :--- | :--- | :--- |
| number | yes | The number of items to contain in each group |
| string | no | The value used to fill in the positions of missing items |
**Example:**
{% set items=[1, 2, 3, 4, 5] %}
<table>
{%- for row in items|batch(3, 'xxx') -%}
<tr>
{%- for column in row -%}
<td>{{ column }}</td>
{%- endfor -%}
</tr>
{%- endfor -%}
</table>
Output code:
<table>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>4</td>
<td>5</td>
<td>xxx</td>
</tr>
</table>
## bool
Converts a value into a boolean using strict conversion rules.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| any | yes | The value to convert into a boolean |
{%- if "true"|bool == true -%}
hello world
{%- endif -%}
The following example shows how `|bool` and implicit conversion can produce different results for the same input:
{% set x = true %}
{% set y = 'string' %}
{% if x == y %}
== {# implicit conversion: non-empty string → true, so true == true #}
{% else %}
!=
{% endif %}
{% if x == y|bool %}
==
{% else %}
!= {# |bool: 'string' is neither 'true' nor '1' → false, so true != false #}
{% endif %}
{% set sentence = "the first letter of a sentence should always be capitalized." %}
{{ sentence|capitalize }}
## center
Uses whitespace to center the value in a field of a given width. This filter will only work in tags where whitespace is retained, such as ``. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | value | yes | The value to center | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | number | yes | The width of the field where the value will be centered | **Example:**## count Returns the number of items in a sequence or mapping. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | value | yes | The sequence/mapping to count | **Example:**<pre> {% set var = "string to center" %} {{ var|center(80) }} </pre>## cut Removes a string from the value of another string. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | The original string | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | The sub-string to remove from the original string | **Example:**{% set services = ['Web design', 'SEO', 'Inbound Marketing', 'PPC'] %} {{ services|count }}## datetimeformat Formats a datetime object and returns a string. The datetime object can be generated with: - [`iso8601_to_time`](#iso8601_to_time) - [`timestamp_to_time`](#timestamp_to_time) - [`strtotime`](#strtotime){% set my_string = "Hello world." %} {{ my_string|cut(' world') }}**Input:** | Type | Required | Description | | :--- | :--- | :--- | | datetime object | yes | The datetime object to format. | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | The format of the date determined by the [directives](#datetimeformat-directives) added in this parameter. | | string | no | Time zone (offset) of the output date. | **Examples:**To get the current UTC time, you can use the `{{ iso_date }}` and `{{ timestamp }}` variables. These variables are initialized automatically; you don't need to declare them first.{% set iso_string = "2023-01-19T09:15:40+03:00" %} {{ iso_string|iso8601_to_time|datetimeformat('%a, %B %d; %H:%M','-01:00') }} {# outputs "Thu, January 19; 05:15" #}### datetimeformat directives The table lists the formatting directives you can use in the Synerise Jinjava implementation. For the purpose of the "Example" column, the time is `2023-01-08T14:15:40.350+00:00`. | Directive | Description | Example | | --------- | ---------------------------------------------- | -------------------------- | | `%a` | Weekday, abbreviated | `Sun` | | `%A` | Weekday, full | `Sunday` | | `%w` | Weekday as number (Sunday is 1, Saturday is 7) | `1` | | `%d` | Day of the month, zero-padded | `08` | | `%b` | Month, abbreviated | `Jan` | | `%B` | Month, full | `January` | | `%m` | Month as number, zero-padded | `01` | | `%y` | Year, without century, zero-padded | `23` | | `%Y` | Year, with century | `2023` | | `%H` | Hour in 24-hour format, zero-padded | `14` | | `%I` | Hour in 12-hour format, zero-padded | `02` | | `%p` | AM/PM information | `PM` | | `%M` | Minutes, zero-padded | `15` | | `%S` | Seconds, zero-padded | `40` | | `%f` | Microseconds, zero-padded | `3500` | | `%z` | UTC offset | `+0000` | | `%Z` | Timezone name (as GMT or GMT±....) | `GMT` | | `%j` | Day of the year, zero-padded | `008` | | `%U` | Week number, Sunday as first day | `02` | | `%c` | Date and time | `Sun Jan 08 14:15:40 2023` | | `%x` | Date | `01/08/23` | | `%X` | Time | `14:15:40` | | `%%` | The `%` character, literal | `%` | ## default If the value is null, it returns the passed default value, otherwise the value of the variable. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | value | yes | The variable to check | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | value | yes | The value to return when the variable is not defined | | boolean | no | Set to `true` to use with variables which evaluate to false | **Example:**{{ 1721894790|timestamp_to_time|datetimeformat('%b %d, %Y; %H:%M') }} {# outputs "Jul 25, 2024; 08:06" #}If you want to use default with variables that evaluate to false you have to set the second parameter to true.// returns 'my_variable is not defined': {% set my_variable = null %} {{ my_variable|default('my_variable is not defined') }} // returns 'Example string': {% set my_variable2 = "Example string" %} {{ my_variable2|default('my_variable is not defined') }}## dictsort Sorts a dict and returns key-value pairs. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | dict | yes | The dict to sort | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | boolean | no | Defines if sorting is case-sensitive. Defaults to `false`. | | string | no | Allowed values: `key`,`value`. Defines sorting by key or by value. Defaults to `key`. | **Example:** Sort the dict by value, case insensitive.{{ ''|default('the string was empty', true) }}Output:{%- set contact = { 'name': 'Alice', 'email': 'alice@example.com', 'phone': '123456789' } -%} {%- for item in contact|dictsort(false, 'value') -%} {{item}} </br> {%- endfor -%}## divide Divides the current value by a divisor. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | number | yes | The number to be divided | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | number | yes | The divisor | **Example:**email=alice@example.com name=Alice phone=123456789## divisible Evaluates to `true` if the value is divisible by the divisor provided in the parameter. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | number | yes | The number to be divided | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | number | yes | The divisor | **Example:** This example is an alternative to using the is [divisibleby expression test](/developers/inserts/exptest#isdivisibleby).{% set my_number = 106 %} {{ my_number|divide(2) }}## escape Converts the characters `&, <, >, ‘,`, and `”` in a string to HTML-safe sequences. Use this filter if you need to display text that might contain such characters in HTML. Marks the return value as a markup string. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | The string to escape | **Example:**{% set num = 10 %} {%- if num|divisible(2) -%} The number is divisible by 2 {%- endif -%}## escape_jinjava Converts the characters `{` and `}` in strings to Jinjava-safe sequences. Use this filter if you need to display text that might contain such characters in Jinjava. Marks the return value as a markup string. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | The string to escape | **Example:**{% set escape_string = "<div>This markup is printed as text</div>" %} {{ escape_string|escape }}## escapejs Escapes strings so that they can be safely inserted into a JavaScript variable declaration. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | The string to escape | **Example:**{% set escape_string = "{{This markup is printed as text}}" %} {{ escape_string|escape_jinjava }}## escapejson Escapes strings so that they can be used as JSON values. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | The string to escape | **Example:**{% set escape_string = "This string can safely be inserted into JavaScript" %} {{ escape_string|escapejs }}## filesizeformat Formats raw file size in bytes into a human-readable format (for example, "13 kB", "4.1 MB", "102 bytes", and so on). **Input:** | Type | Required | Description | | :--- | :--- | :--- | | number | yes | The file size to format | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | boolean | no | Defines if binary prefixes (Mebi, Gibi) should be used. Defaults to `false`. | **Example:**{% set escape_string = "String that contains JavaScript" %} {{ escape_string|escapejson }}## first Returns the first item of a sequence. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | sequence | yes | The sequence to process | **Example:**{% set bytes = 100000 %} {{ bytes|filesizeformat }}## float Converts the value into a floating point number. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | value | yes | The value to convert into a float | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | float | no | The value to return if conversion fails. Defaults to `0.0`. | **Example:** This example converts a text field string value to a float.{% set my_sequence = ['Item 1', 'Item 2', 'Item 3'] %} {{ my_sequence|first }}## forceescape Enforces HTML escaping.{% set my_text = "25.3" %} {{ my_text|float }}**Input:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | The value to escape | **Example:**This may double-escape variables.## format Applies Python string formatting to an object. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | String value to reformat | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | string arguments | yes | Values to insert into the string | **Example:** `%s` can be replaced with other variables or values, for example `%d`.{% set escape_string = "<div>This markup is printed as text</div>" %} {{ escape_string|forceescape }}## fromjson Deserializes data from a string. The string must be a serialized object. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | The JSON string to deserialize | **Example:**{{ "Hi %s %s"|format("Hello", "World!") }}Output:{%- set y = '{"dataX":"b"}' -%} {%- set deserialized = y|fromjson -%} {{ deserialized }}### Using fromjson with arrays To use `fromjson` with arrays, the array must be transformed into an object and then serialized with [tojson](#tojson). Such a situation may occur when arrays are the result of macros or other inserts. In the following example, the array is created for demonstration purposes:{dataX=b}The output is `9` ## groupby Groups a sequence of objects by a common attribute. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | dict | yes | The dict to iterate over and group by a common attribute | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | The name of the common attribute to group by | **Example:** If you have a list of dicts or objects that represent persons with the attributes `gender`, `first_name`, and `last_name` attributes, you can group all the customers by gender this way:// Set the array: {% set array = [{"a":9,"b":10},{"a":12,"b":15}] %} // Put the array in an object: {% set obj = { data:array } %} // Serialize the object: {% set json_obj = obj|tojson %} // Deserialize the object with the array: {% set transformed = json_obj|fromjson %} {{ transformed['data'][0].a }}Output:{%- set contents = [ {'gender': 'male', 'name': 'John'}, {'gender': 'female', 'name': 'Jane'}, {'gender': 'male', 'name': 'Bob'}, {'gender': 'female', 'name': 'Alice'} ] -%} <ul> {%- for group in contents|groupby('gender') -%} <li> Group: {{ group.grouper }} <ul> {%- for content in group.list -%} <li>{{ content.name }}</li> {%- endfor -%} </ul> </li> {%- endfor -%} </ul>## hash Returns the SHA-256 hash of a string.<ul><li> male <ul><li> John </li><li> Bob </li></ul> </li><li> female <ul><li> Jane </li><li> Alice </li></ul> </li></ul>## indent Uses whitespace to indent a string. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | The string to indent | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | number | no | The number of spaces. Defaults to 4. | | boolean | no | If `true`, the first line will be indented. Defaults to `false`. | **Example:**{% set foo = "example@synerise.com"|hash("SHA-256") %} {{ foo }} {# returns cab06d7019d42ed33dcb260dba8860f8028d243dd78184f3b5156d7bdae636dd #}## int Converts the value into an integer. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | value | yes | The value to convert into an integer | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | value | no | The value to return if conversion fails. Defaults to `0`. | **Example:** This example converts a text field string value to a integer.<pre> {% set var = "string to indent" %} {{ var|indent(2, true) }} </pre>## iso8601_to_time Converts an ISO date-time string to a datetime object, which should be further formatted with [`datetimeformat`](#datetimeformat). **Input** | Type | Required | Description | | :--- | :--- | :--- | | string | no* | An ISO date-time string. Can include a timezone. If the resulting object is printed directly, the timezone isn't displayed. You should use formatting to display the time in the correct timezones. See examples below.| *An empty string applies the current time. **Example**{% set my_text = "23" %} {{ my_text|int }}Note that the timezone is not displayed, but it's saved as part of the object. To ensure that the timezone matches the one you want to display, declare it when formatting the time:{{ "2023-01-19T09:15:40+03:00"|iso8601_to_time }} {# returns the following object: 2023-01-19 09:15:40 #}For more details on formatting, see [`datetimeformat`](#datetimeformat). ## join Returns a string which is the concatenation of the values in the sequence. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | sequence | yes | A list of values to join | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | string | no | The separator. Defaults to empty string. | | string | no | Dict object attribute to use in joining **Example:**{{ "2023-01-19T09:15:40+03:00"|iso8601_to_time|datetimeformat('%H:%M:%S','-01:00') }} {# returns the string: 05:15:40 #}Output:{%- set users = [ {'username': 'john'}, {'username': 'jane'}, {'username': 'bob'} ] -%} {{ users|join('|', attribute='username') }}It is also possible to join certain attributes of an object:john|jane|bob## last Returns the last item of a sequence. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | sequence | yes | The sequence to process | **Example:**{{ users|join('|', attribute='username') }}## length Returns the number of items in a sequence or mapping. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | sequence | yes | The sequence to process | **Example:**{% set my_sequence = ['Item 1', 'Item 2', 'Item 3'] %} {{ my_sequence|last }}## list Converts the value into a list. If it was a string, the returned list will be a list of characters. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | value | yes | Value to split into a list | **Example:**{% set services = ['Web design', 'SEO', 'Inbound Marketing', 'PPC'] %} {{ services|length }}## lower Converts a value to lowercase. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | The string to convert into lowercase | **Example:**{% set one = 1 %} {% set two = 2 %} {% set three = 3 %} {% set list_num = one|list + two|list + three|list %} {{ list_num|list }}## map Applies a filter on a sequence of objects or looks up an attribute. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | object | yes | Sequence to apply a filter to or a dict for attribute lookup | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | attribute pointer or string | yes | Filter to apply to the sequence or dict attribute to look up | **Example:** The basic usage is mapping by an attribute. Imagine you have a list of customers but you are only interested in a list of usernames.{{ "Text to MAKE Lowercase"|lower }}Output:{%- set users = [ {'username': 'john'}, {'username': 'jane'}, {'username': 'bob'} ] -%} Users on this page: {{ users|map(attribute='username')|join(', ') }}Alternatively, you can let invoke a filter by passing the name of the filter and the arguments afterwards. A good example would be applying a text conversion filter on a sequence.Users on this page: john, jane, bob## md5 Calculates the MD5 hash of the given object. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | value | yes | Value for MD5 hash calculation | **Example:**{% set seq = ['item1', 'item2', 'item3'] %} {{ seq|map('upper') }}Output:{% set content = {'absolute_url': 'https://example.com/page1'} %} {{ content.absolute_url | md5 }}## multiply Multiplies the current object with the given multiplier. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | number | yes | The number to be multiplied | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | number | yes | The multiplier | **Example:**d22158c78143eeca7fa617577d741866## prettyprint Pretty print a variable. Useful for debugging. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | value | yes | Object to pretty print | **Example:**{% set n = 20 %} {{ n|multiply(3) }}## random Returns a random item from the sequence. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | sequence | yes | Sequence to return a random entity from | **Example:** The following example shows how to return the name of a random item from a recommendation:{% set this_var = "Variable that I want to debug" %} {{ this_var|pprint }}## reject Filters a sequence of objects by applying a [test](/developers/inserts/exptest) to the objects and excluding the ones that match the test. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | sequence | yes | The sequence to test | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | The name of the test to apply | **Example:**{% recommendations3 campaignId=CAMPAIGN_ID %} {% set randomItem = recommended_products3|random %} {{ randomItem.name }} {% endrecommendations3 %}Output:{%- set some_numbers = [10, 12, 13, 3, 5, 17, 22] -%} {{ some_numbers | reject('even') }}## rejectattr Filters a sequence of objects by applying a [test](/developers/inserts/exptest) to an attribute of an object and rejecting the objects that match the test. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | sequence | yes | The sequence to test | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | The name of the attribute to test | | string | no | The name of the test to apply. Defaults to `'truthy'`. | **Example:** This loop rejects any post with the `content.post_list_summary_featured_image` attribute.[13, 3, 5, 17]Output:{%- set contents = [ {'title': 'Post 1', 'post_list_summary_featured_image': 'img1.jpg'}, {'title': 'Post 2', 'post_list_summary_featured_image': ''}, {'title': 'Post 3', 'post_list_summary_featured_image': null} ] -%} {%- for content in contents|rejectattr('post_list_summary_featured_image') -%} {{content.title}} </br> {%- endfor -%}## replace Returns a copy of the value with all occurrences of a substring replaced with a new one. The first argument is the substring that should be replaced, the second is the replacement string. If the optional third argument `count` is given, only the first `count` occurrences are replaced. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | Base string | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | String to replace | | string | yes | The replacement value | | number | no | This many first occurrences are replaced | **Example:**Post 2 Post 3{{ "Hello World"|replace("Hello", "Goodbye") }}## reverse Reverses the object or returns an iterator that iterates over it the other way round. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | value | yes | The sequence or dict to reverse | **Example:**{{ "aaaaargh"|replace("a", "d'oh, ", 2) }}## round Rounds the number to a given precision. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | number | yes | The number to round | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | number | no | The precision of rounding (digits after decimal point). Defaults to 0. | | string | no | The method of rounding. Allowed values: `ceil` (up), `floor` (down), `common` (down if `fraction < .5`). Defaults to `common`. **Example:**{% set nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] %} {%- for num in nums|reverse -%} {{ num }} {%- endfor -%}Even if rounded to 0 precision, a float is returned. The fraction of that float is `.0`{{ 42.55|round }}If you need a real integer, pipe it through int.{{ 42.55|round(1, 'floor') }}## select Filters a sequence of objects by applying a [test](/developers/inserts/exptest) to the objects and only returning the ones that match the test. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | sequence | yes | The sequence to test | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | The name of the test to apply | **Example:**{{ 42.55|round|int }}## selectattr Filters a sequence of objects by applying a [test](/developers/inserts/exptest) to an attribute of an object and returning only the objects that match the test. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | sequence | yes | The sequence to test | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | The name of the attribute to test | | string | no | The name of the test to apply. Defaults to `'truthy'`. | **Example:** This loop selects any posts containing content.post_list_summary_featured_image.{% set some_numbers = [10, 12, 13, 3, 5, 17, 22] %} {{ some_numbers|select('even') }}Output:{%- set contents = [ {'title': 'Post 1', 'post_list_summary_featured_image': 'img1.jpg'}, {'title': 'Post 2', 'post_list_summary_featured_image': ''}, {'title': 'Post 3', 'post_list_summary_featured_image': null} ] -%} {%- for content in contents|selectattr('post_list_summary_featured_image') -%} {{ content.title }} {%- endfor -%}## shuffle Randomly shuffles a given list, returning a new list with all of the items of the original list in a random order. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | sequence | yes | The sequence to shuffle | **Example:** The example below is a standard blog loop, with order randomized on page load.Post 1## slice Slices an iterator and returns a list of lists containing those items. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | sequence | yes | The sequence or dict to slice | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | number | yes | The number of slices to create | **Example:** Create a div containing three `{%- for content in ['a','b','c','d','e']|shuffle -%} {{content}} {%- endfor -%}
{% set items = ['laptops', 'tablets', 'smartphones', 'smart watches', 'TVs'] %}
<div class="columwrapper">
{%- for column in items|slice(3) -%}
<ul class="column-{{ loop.index }}">
{%- for item in column -%}
<li>{{ item }}</li>
{%- endfor -%}
</ul>
{%- endfor -%}
</div>
Output:
<div class="columwrapper">
<ul class="column-1">
<li>laptops</li>
<li>tablets</li>
</ul>
<ul class="column-2">
<li>smartphones</li>
<li>smart watches</li>
</ul>
<ul class="column-3">
<li>TVs</li>
</ul>
</div>
## sort
Sorts an iterable.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| iterable | yes | The sequence or dict to sort |
**Parameters:**
| Type | Required | Description |
| :--- | :--- | :--- |
| boolean | no | If `true`, the sorting order is reversed. Defaults to `false`. |
| boolean | no | If `true`, sorting is case-sensitive. Defaults to `false`. |
| attribute | yes, if dict | If the input is a dict, this is the name of the attribute to sort by. |
**Example:**
{%- for item in [4,7,1,9,3,4,7,2,8,4,5,6,7,9]|sort -%}
{{item}}
{%- endfor -%}
## split
Splits the input string into a list on the given separator.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | The string to split |
**Parameters:**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | no | The separator to split on. Defaults to a single space. (`' '`) |
| number | no | The splitting stops after this many occurrences, the remaining items become the last item in the resulting list. |
**Example:**
{% set string_to_split = "Stephen; David; Cait; Nancy; Mike; Joe; Niall; Tim; Amanda" %}
{% set names = string_to_split|split(';', 4) %}
<ul>
{%- for name in names -%}
<li>{{ name }}</li>
{%- endfor -%}
</ul>
## string
Returns the string value of an object.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| value | yes | The value to return as a string |
**Example:**
{% set number_to_string = 45 %}
{{ number_to_string|string }}
## striptags
Strips SGML/XML tags and replaces adjacent whitespace by one space.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | String to strip tags from |
**Example:**
{% set some_html = "<div><strong>Some text</strong> </div>" %}
{{ some_html|striptags }}
## strtotime
Transforms a string into a datetime object that can be processed with other filters, for example [`unixtimestamp`](#unixtimestamp) or [`datetimeformat`](#datetimeformat)
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | String to transform into a datetime object. |
**Parameters**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | Information about the format of the input. |
**Example:**
In this example, a US-format date is converted into datetime object.
{% set date = "2025-24-08T14:31:30+0130"|strtotime("yyyy-dd-MM'T'HH:mm:ssZ") %}
{{date}}
{# returns the following object:
2025-08-12 14:31:30
#}
Note that the timezone is not displayed, but it's saved as part of the object. To ensure that the timezone matches the one you want to display, declare it when formatting the time:
{% set date = "2025-24-08T14:31:30+0130"|strtotime("yyyy-dd-MM'T'HH:mm:ssZ") %}
{{ date|datetimeformat('%H:%M:%S','-01:00') }}
{# returns the string:
12:01:30
#}
For more details on formatting, see [`datetimeformat`](#datetimeformat).
## sum
Returns the sum of a sequence of numbers plus the value of the `start` parameter (which defaults to 0). When the sequence is empty, it returns `start`.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| iterable | yes | A sequence or dict of values to sum |
**Parameters:**
| Type | Required | Description |
| :--- | :--- | :--- |
| number | no | The `start` parameter. Defaults to `0` |
| attribute | no | If the input is a dict, you can sum the values of an attribute. |
**Example:**
{% set sum_this = [1, 2, 3, 4, 5] %}
{{ sum_this|sum }}
Sum up only certain attributes.
Total: {{ items|sum(attribute='price') }}
## timestamp_to_time
Converts a Unix timestamp (seconds or miliseconds) to a datetime object, which should be further formatted with [`datetimeformat`](#datetimeformat).
**Input**
| Type | Required | Description |
| :--- | :--- | :--- |
| integer* | no** | The UNIX timestamp to transform. Timestamps are, by definition, in UTC. Don't recalculate them into other timezones when in the UNIX format, as this may cause problems in systems which treat it correctly as UTC. |
*The engine attempts parsing if you provide a string or a float, but this is not recommended.
**An empty string applies the current time.
**Example**
{{ 1740042390|timestamp_to_time }}
{# returns the following object:
2025-02-20 09:06:30
#}
## title
Returns a titlecased version of the value. Words will start with uppercase letters, all remaining characters are lowercase.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | The string to transform |
**Example:**
{{ "My title should be titlecase"|title }}
## tojson
Serializes data into a JSON string.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| various | yes | The data to transform into JSON |
**Examples:**
{% set val = "b" %}
{% set x = {"dataX":val} %}
{{ x|tojson }}
Output:
{"dataX":"b"}
{% set object = {
"field1": "value",
"field2": {
"subfield1": 1,
"subfield2": [
{
"nestedObjectField1": "value",
"nestedObjectField2": 1
},
{
"nestedObjectField1": "value",
"nestedObjectField2": 2
},
{
"nestedObjectField1": "value",
"nestedObjectField3": 3
}
]
}
} %}
{% set x = object|tojson %}
{{ x }}
Output:
{"field1":"value",
"field2":{
"subfield1":1,
"subfield2":[{"nestedObjectField1":"value","nestedObjectField2":1},
{"nestedObjectField1":"value","nestedObjectField2":2},
{"nestedObjectField1":"value","nestedObjectField3":3}]
}}
{% set qwe=[] %}
{% do qwe.append("123") %}
{% do qwe.append("456") %}
{{ qwe|tojson }}
Output:
["123","456"]
## trim
Strips leading and trailing whitespace.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | The string to transform |
**Example:**
{{ " remove whitespace "|trim }}
## truncate
Returns a truncated copy of the string. The length is specified with the first parameter, which defaults to `255`. If the second parameter is `true`, the filter will cut the text exactly at the specified length. Otherwise, it will cut after the last complete word. If the text is actually truncated, the filter appends an ellipsis ("..."). If you want to replace the ellipsis with another string, provide that string as the third parameter.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | The string to transform |
**Parameters:**
| Type | Required | Description |
| :--- | :--- | :--- |
| number | no | The number of characters to truncate after. Defaults to 255. |
| boolean | no | If `true`, the string is truncated exactly after the specified number of characters. Otherwise, the text is truncated after the last complete word. Defaults to `false`. |
| string | no | The string to append in the place where the text was truncated. Defaults to `'...'` |
**Example:**
{{ "I only want to show the first sentence. Not the second."|truncate(48, True) }}
{# I only want to show the first sentence. Not t... #}
{{ "I only want to show the first sentence. Not the second."|truncate(48, False) }}
{# I only want to show the first sentence. Not... #}
{{ "I only want to show the first sentence. Not the second."|truncate(35, True, '[...]') }}
{# I only want to show the first [...] #}
## truncatehtml
Truncates a given string, respecting HTML markup (properly closes all nested tags).
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | The string to transform |
**Parameters:**
| Type | Required | Description |
| :--- | :--- | :--- |
| number | no | The number of characters to truncate after. Defaults to 255. |
| string | no | The string to append in the place where the text was truncated. Defaults to `'...'` |
| boolean | no | If `true`, the string is truncated exactly after the specified number of characters. Otherwise, the text is truncated after the last complete word. Defaults to `false`. |
**Example:**
{{ "<p>I want to truncate this text without breaking my HTML<p>"|truncatehtml(20, '..', false) }}
## unique
Extracts a unique set from a sequence of objects.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| sequence | yes | The sequence to filter |
**Parameters:**
| Type | Required | Description |
| :--- | :--- | :--- |
| attr | no | If the input is a dict, you can use an attribute as the unique identifier. |
**Example:**
Filter duplicated strings from a sequence of strings.
{{ ['foo', 'bar', 'foo', 'other']|unique|join(', ') }}
{# foo, bar, other #}
Filter out items with the same attribute.
{% set contents = [
{'post_list_summary_featured_image': 'img0.jpg', 'title': 'Post 2'},
{'post_list_summary_featured_image': 'img1.jpg', 'title': 'Post 1'},
{'post_list_summary_featured_image': '', 'title': 'Post 2'}
] %}
{%- for content in contents|unique(attr='title') -%}
{{ content }} </br>
{%- endfor -%}
Output:
{post_list_summary_featured_image=img0.jpg, title=Post 2}
{post_list_summary_featured_image=img1.jpg, title=Post 1}
## unixtimestamp
Gets the UNIX timestamp value (in milliseconds) of a datetime object.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| object | yes | The datetime object to convert |
**Example:**
{% set date = "2025-08-24T14:31:30+0130"|strtotime("yyyy-MM-dd'T'HH:mm:ssZ") %}
{{ date|unixtimestamp }}
Output:
1756040490000
## upper
Converts a value to uppercase.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | The string to convert into uppercase |
**Example:**
{{ "text to make uppercase"|upper }}
## urlencode
Escapes strings for use in URLs (uses UTF-8 encoding). It accepts both dictionaries and regular strings, as well as pairwise iterables.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | The URL to escape |
**Example:**
{{ "Escape & URL encode this string"|urlencode }}
## urlize
Converts URLs in plain text into clickable links.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | String URL to convert into anchor |
**Parameters:**
| Type | Required | Description |
| :--- | :--- | :--- |
| number | no | Sets a character limit |
| boolean | no | If `true`, adds nofollow to the generated link. Defaults to `false`. |
| target | no | Adds a `target` attribute to the generated `` tag. |
**Example:**
Links are shortened to 40 chars and defined with rel="nofollow".
{{ "https://synerise.com"|urlize(40) }}
If target is specified, the target attribute will be added to the `` tag
{{ "https://synerise.com"|urlize(10, true, target='_blank') }}
## wordcount
Counts the words in the given string.
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | The string to process |
**Example:**
{% set count_words = "Count the number of words in this variable" %}
{{ count_words|wordcount }}
## wordwrap
Returns a copy of the string passed to the filter wrapped after a number of characters (79 by default).
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | The string to process |
**Parameters:**
| Type | Required | Description |
| :--- | :--- | :--- |
| number | no | The number of characters to wrap after. Defaults to 79. |
| boolean | no | If `true`, long words will be broken when wrapped. Defaults to `true`. |
**Example:**
<pre>
{{ "Lorem ipsum dolor sit amet, consectetur adipiscing elit"|wordwrap(10) }}
</pre>
Output:
```plaintext
Lorem
ipsum
dolor sit
amet, cons
ectetur
adipiscing
elit
```
## xmlattr
Creates an HTML/XML attribute string based on the items in a dict.
Input:
_(value = "dict", type = "dict", desc = "Dict to filter", required = true)_
Params:
_(value = "autospace", type = "boolean", defaultValue = "True", desc = "Automatically prepend a space in front of the item")_
**Input:**
| Type | Required | Description |
| :--- | :--- | :--- |
| dict | yes | The dict to process |
**Parameters:**
| Type | Required | Description |
| :--- | :--- | :--- |
| boolean | no | If `true`, automatically appends a space before the item. Defaults to `true`. |
**Example:**
{% set html_attributes = {'class': 'bold', 'id': 'sidebar'} %}
<div{{ html_attributes|xmlattr(False) }}></div>
{# <divclass="bold" id="sidebar"></div> #}
<div{{ html_attributes|xmlattr }}></div>
{# <div class="bold" id="sidebar"></div> #}
# Jinjava tags
Tags are jinjava-based functions. They enable easier access to some jinjava expressions, with additional or alternative logic tailored to the needs of our clients.
{% set b = 'I remove the whitespace' %}
{%- if b -%}
{{b}}
End of IF
{%- endif -%}
Data sent to the browser:
"I remove the whitespace\nEnd of IF"
{% set a = 'I keep the whitespace' %}
{% if a %}
{{a}}
End of IF
{% endif %}
Data sent to the browser:
"\n\nI keep the whitespace\nEnd of IF\n"
{% do listname.append('string')}
**Example:**
This example uses `do.append` and [`loop.index`](#loop-variables) to iterate over a list of items and pull corresponding values from another list to create an array of objects with values from both lists.
{# List of items: #}
{% set itemsArray = ['item1','item2','item3'] %}
{# List of prices for the items: #}
{% set pricesArray = ['item1_price','item2_price','item3_price'] %}
{# Empty array to fill with objects: #}
{% set arrayWithItemsAndPrices = [] %}
{# Start iterating over itemsArray #}
{%- for item in itemsArray -%}
{# Set variable to store index of the current iteration: #}
{% set index=loop.index0 %}
{# Append object to the array #}
{% do arrayWithItemsAndPrices.append({
item: item,
price: pricesArray[index],
index: index
})
%}
{%- endfor -%}
In the object:
- `item` is the current item from `itemsArray`,
- `price` is pulled from the corresponding index from `pricesArray`,
- `index` is the current iteration
**Result:**
The `arrayWithItemsAndPrices` array is the following:
[
{item=item1, price=item1_price, index=0},
{item=item2, price=item2_price, index=1},
{item=item3, price=item3_price, index=2}
]
{%- autoescape -%}
{# Code to escape #}
{%- endautoescape -%}
## Call
In some cases, it can be useful to pass a [macro](/developers/inserts/tag#macro) to another macro. For this purpose, you can use the special call block.
This is a simple dialog rendered by using a macro and a call block:
{%- macro dump_users(users) -%}
<ul>
{%- for user in users -%}
<li>
<p>{{ user.username|e }}</p>
{{ caller(user) }}
</li>
{%- endfor -%}
</ul>
{%- endmacro -%}
{%- call(user) dump_users(list_of_user) -%}
<dl>
<dl>Realname</dl>
<dd>{{ user.realname|e }}</dd>
<dl>Description</dl>
<dd>{{ user.description }}</dd>
</dl>
{%- endcall -%}
## Cycle
The cycle tag can be used within a for loop to cycle through a series of string values and print them with each iteration.
**Parameters:**
| Type | Required | Description |
| :--- | :--- | :--- |
| list | yes | A comma-separated list of strings to print with each iteration. The list will repeat if there are more iterations than string parameter values. |
In the example below, the classes `odd` and `even` are applied to posts in a listing:
{%- set contents = ['content 1', 'conent 2', 'content 3', 'content 4'] -%}
{%- for content in contents -%}
<div class="post-item {% cycle 'odd','even' %}">
Blog post content
</div>
{%- endfor -%}
Output:
<div class="post-item odd">
Blog post content
</div><div class="post-item even">
Blog post content
</div><div class="post-item odd">
Blog post content
</div><div class="post-item even">
Blog post content
</div>
## If, else if, else
Outputs inner content if expression evaluates to true, otherwise evaluates elif blocks, finally outputting the content of the else block present (if no elif block evaluated to true).
{%- if number <= 2 -%}
Variable named number is less than or equal to 2.
{%- elif number <= 4 -%}
Variable named number is less than or equal to 4.
{%- elif number <= 6 -%}
Variable named number is less than or equal to 6.
{%- else -%}
Variable named number is greater than 6.
{%- endif -%}
### Combining conditions
You can combine conditions with the following operators:
- `and` / `&&`
- `or` / `||`
- `not` / `!`
If a condition uses functions and includes spaces (such as in [tests](/developers/inserts/exptest)), it may be evaluated incorrectly or stop the rendering. For best results, we recommend using brackets with all conditions.
**Examples**:
{%- if (2 == 2) and (3 == 3) -%}
{# recommended #}
{%- endif -%}
{%- if (5 is divisibleby 5) and (2 == 2) -%}
{# correct, recommended #}
{%- endif -%}
{% if (not(5 is divisibleby 4)) and (2 == 2) %}
{# correct, recommended #}
{% endif %}
{%- if 5 is divisibleby 5 and 2 == 2 -%}
{# INCORRECT #}
{%- endif -%}
{%- if 2 == 2 and 3 == 3 -%}
{# NOT recommended #}
{%- endif -%}
## For
Outputs the inner content for each item in the given iterable.
**Examples**:
{% set names = ["John", "Kate", "Bob"] %}
{%- for item in names -%}
Hello, {{ item }}!
{%- endfor -%}
{%- set exampleProduct = {'size': 12, 'title': 'Item', 'color': 'blue'} -%}
{%- for key, value in exampleProduct.items() -%}
{{ value }}{% if not loop.last %} {% endif %}
{%- endfor -%}
Output:
12 Item blue
{% set exampleProduct = {'size':12,'title':'Item', 'color': ['red','blue','yellow']} %}
{%- for key, value in exampleProduct.items() -%}
{{ key }} : {{ value }}<br>
{%- endfor -%}
Output:
size : 12
title : Item
color : [red, blue, yellow]
{%- set array = ["q","w","e","r","t"] -%}
{%- for item in array -%}
Item: {{ item }}
<br>
Index: {{ loop.index }}
<br>
Revindex: {{ loop.revindex }}
<br>
Cycle: {{ loop.cycle('foo','bar','baz') }}
<br>
{%- endfor -%}
**Output:**
Item: q
Index: 1
Revindex: 5
Cycle: foo
Item: w
Index: 2
Revindex: 4
Cycle: bar
Item: e
Index: 3
Revindex: 3
Cycle: baz
Item: r
Index: 4
Revindex: 2
Cycle: foo
Item: t
Index: 5
Revindex: 1
Cycle: bar
## Get
See ["Object properties" in "Insert usage"](/developers/inserts/insert-usage#object-properties).
## Ifchanged
Outputs the tag contents if the given variable has changed since a prior invocation of this tag.
{%- ifchanged variable -%}
{# Code to execute if the variable has changed #}
{%- endifchanged -%}
## Intersect
Returns the common element of two arrays.
**Example**:
{%- set array1 = ["apple", "banana", "cherry","kiwis"] -%}
{%- set array2 = ["pear", "banana", "kiwi"] -%}
{%- set common = array1|intersect(array2) -%}
{{common}}
Output:
['banana']
## Macro
Macros allow you to print multiple statements with a dynamic value or values.
Basic macro syntax:
{# Defining the macro #}
{%- macro name_of_macro(argument_name, argument_name2) -%}
{{ argument_name }}
{{ argument_name2 }}
{%- endmacro -%}
{# Calling the macro #}
{{ name_of_macro("value to pass to argument 1", "value to pass to argument 2") }}
Example of a macro used to print CSS3 properties with the various vendor prefixes.
{%- macro trans(value) -%}
-webkit-transition: {{value}};
-moz-transition: {{value}};
-o-transition: {{value}};
-ms-transition: {{value}};
transition: {{value}};
{%- endmacro -%}
The macro can then be called like a function. The macro is printed for anchor tags in CSS.
a { {{ trans("all .2s ease-in-out") }} }
## Print
Echoes the result of the expression.
**Examples:**
{% set string_to_echo = "Print me" %}
{% print string_to_echo %}
{% print -65|abs %}
## Range
Generates an array of integers. The array can't be longer than 1000 items.
range(start,stop,step)
| Parameter | Required | Default | Description |
| --- | --- | --- | --- |
| start | no | `0` | The first value in the array. |
| stop | yes | n/a | The limit at which the array ends. The value of the limit is excluded from the array. |
| step | no | `1` | The increment between items. Can be negative. |
**Examples**:
Default start and step:
{% set foo=range(5) %}
{{ foo }}
OUTPUT:
[0, 1, 2, 3, 4]
Start defined, step default:
{% set foo=range(2,10) %}
{{foo}}
OUTPUT:
[2, 3, 4, 5, 6, 7, 8, 9]
Defined start and step. The value of stop isn't included in the array.
{% set foo=range(2,10,2) %}
{{foo}}
OUTPUT:
[2, 4, 6, 8]
Negative increment. The value of stop isn't included in the array. In this case, start must be higher than stop!
{% set foo=range(10,2,-2) %}
{{foo}}
OUTPUT:
[10, 8, 6, 4]
## Raw
Processes all inner expressions as plain text.
{% raw %}
The personalization token for a contact's first name is {{ contact.firstname }}
{% endraw %}
## Set
Assigns the value or result of a statement to a variable.
**Basic syntax:**
{% set variableName = variableValue %}
The value can be a string, a number, a boolean, or a sequence.
**Example:**
Set a variable and print the variable in an expression:
{% set primaryColor = "#F7761F" %}
{{ primaryColor }}
You can combine multiple values or variables into a sequence variable.
{% set var_one = "String 1" %}
{% set var_two = "String 2" %}
{% set sequence = [var_one, var_two] %}
## Try/catch
The try/catch syntax can be used to create a fallback mechanism for Jinjava that can't be processed, such as referencing an attribute that doesn't exist.
You can only include one catch statement, but you can nest another try/catch blocks inside it (see examples below).
{% try %}
{{ thisVariableDoesntExist }}
{% catch %}
I didn't find the variable!
{% endtry %}
OUTPUT:
```plaintext
I didn't find the variable!
```
{% try %}
{% customer thisParamDoesntExist %}
{% catch %}
{% try %}
{{ someVariableThatDoesntExist }}
{% catch %}
I didn't find the other variable either!
{% endtry %}
{% endtry %}
OUTPUT:
```plaintext
I didn't find the other variable either!
```
{% try %}
{{ foo }
{% catch %}
...
{% endtry %}
{%- unless x < 0 -%}
x is greater than zero
{%- endunless -%}
## Update
Creates or updates the properties of an object.
**Example**:
{% set product = {'category':'sneakers'} %}
Initial object: {{product}}
<br>
{% set colorData = {'color':'red','size': 8} %}
{% do product.update(colorData) %}
Added color and size: {{product}}
<br>
{% set newColorData = {'color':'blue'} %}
{% do product.update(newColorData) %}
Updated color: {{product}}
Output:
Initial object: {category=sneakers}
<br>
Added color and size: {category=sneakers, color=red, size=8}
<br>
Updated color: {category=sneakers, color=blue, size=8}
# Inserting recommendations
You can show a set of recommendations to the customer. They are calculated by the AI engine. The profile context is retrieved automatically from the data of the profile who requested the resource that included the insert.
{% recommendations3 campaignId=campaign-hash %} {# replace campaign-hash with the campaign ID #}
{# logic of processing the result #}
{# the result is stored in a 'recommended_products3' variable #}
{% endrecommendations3 %}
- The items are stored as objects in the `recommended_products3` list.
You can use this list in all types of recommendations. For example, in [section recommendations](#section-recommendations) or [recommendations with slots](#recommendation-slots), `recommended_products3` lists the items without any information about slots or rows.
- The available item attributes depend on the item feed.
### Example
The following code is an example of showing recommendations on a website. The insert loops through recommendations generated for a campaign (the number of recommendations depends on the settings) and produces an HTML list of recommended items.
#### Input
<div class="snrs-AI--banner" style="height: auto;">
<div class="snrs-AI--slider">
<div class="snrs-AI--products-slider">
<ul>
{% recommendations3 campaignId=campaign-hash %}
{%- for p in recommended_products3 -%}
<li data-snr-ai-product-id="{{p.itemId}}">
<a class="snrs-AI--item-link" href="{{p.link}}" title="{{p.title}}">
<img src="{{ p.imageLink }}"
class="products-slider__item-image snrAI-product-image snrAI-product-image-{{p.itemId}}"
width="90" alt="{{p.title}}" id="snrAI-image-{{p.itemId}}">
<h3 class="snrs-AI-product--product-name">
<span class="snrs-AI-product--name-first">{{p.title}}</span>
</h3>
<span class="snrs-AI-product--series">{{p.attributes.series}}</span>
</a>
</li>
{%- endfor -%}
{% endrecommendations3 %}
</ul>
</div>
</div>
</div>
<div class="snrs-AI--banner" style="height: auto;">
<div class="snrs-AI--slider">
<div class="snrs-AI--products-slider">
<ul>
<li data-snr-ai-product-id="000097">
<a class="snrs-AI--item-link"
href="https://example.com/accessories-for-shaver/cleaner-contribution-to-shavers-brand-DDR2,id-2369"
title="Cleaning insert for shavers BRAND DDR22">
<img src="https://example.com/temp/thumbs-new/2/other/cd1c73e35b1db186e79e8a0039b27293_250x200w50.jpg"
class="products-slider__item-image snrAI-product-image snrAI-product-image-000097"
width="90" alt="Cleaning insert for shavers BRAND DDR2" id="snrAI-image-000097">
<h3 class="snrs-AI-product--product-name">
<span class="snrs-AI-product--name-first">Cleaning insert for shavers BRAND DDR2</span>
</h3>
<span class="snrs-AI-product--series">DDR2 8983</span>
</a>
</li>
<li>...</li>
<li>...</li>
<li>...</li>
<li>...</li>
</ul>
</div>
</div>
</div>
## Recommendations as JSON
This insert can be used to add recommendations only in Screen Views and Documents.
{% recommendations_json3 campaignId=COhsCCOdu8Cg %} {% endrecommendations_json3 %}
If your campaign type is [External](/docs/ai-hub/recommendations-v2/abx-test-with-external-model), you need to provide the IDs of the items from the external model.
- The IDs must be an array of strings.
- They must be declared with `{% set %}` and used as a variable.
Example:
{% set externalItems = ['sku1','sku2'] %}
{% recommendations_json3 campaignId=COhsCCOdu8Cg externalItemsIds=externalItems %}
{% endrecommendations_json3 %}
#### Example
A document has the following content.
"{% recommendations_json3 campaignId=FcP8UtRgrype %} {% endrecommendations_json3 %}"
The recommendation type of the requested campaign is "Top items". It's configured to return one item in a slot.
The output of the generated document is the following:
{
"campaignId": "FcP8UtRgrype",
"campaignHash": "0cfa5c65-a62a-47d6-93f5-fa98eb346d6b",
"recommended": {
"data": [
{
"category": "Synerise Hub > Use cases",
"itemId": "21baa503-9c26-42a4-aebe-1e04adb0bf2e",
"link": "https://synerise.com/use-cases/?snrai_campaign=FcP8UtRgrype&snrai_id=0cfa5c65-a62a-47d6-93f5-fa98eb346d6b",
"title": "Use cases"
}
],
"extras": {
"contextItems": null,
"correlationId": "0cfa5c65-a62a-47d6-93f5-fa98eb346d6b",
"slots": [
{
"id": 0,
"itemIds": [
"21baa503-9c26-42a4-aebe-1e04adb0bf2e"
],
"name": "Unnamed slot"
}
]
}
}
}
## Recommendations with an item context
Some types of recommendations require an item context. If the metadata (OG tags) of the website where the recommendation is displayed include the `product:retailer_part_no` parameter, that context is read automatically.
In other situations you need to specify the context.
This can be done in two ways:
- [By using an aggregate](#ai-cart-recommendations)
- [By declaring the item IDs as a variable](#declaring-a-specific-item-context)
### Item context from an aggregate (example: cart recommendation) {#ai-cart-recommendations}
You can use an aggregate to provide the item context. The example below shows how to do it when displaying a cart recommendation. The cart page doesn't contain the item identifiers in the metadata, so an aggregate must be used to retrieve the items currently in the cart, based on `cart.status` events.

{% set itemContext = [] %}
{% aggregate aggregate-hash %}
{%- for r in aggregate_result|reverse -%}
{% set _noop = itemContext.append(r.sku) %}
{%- endfor -%}
{% endaggregate %}
{% recommendations3 campaignId=campaign-hash itemsIds=itemContext %}
{# logic of processing the result #}
{# the result is stored in a 'recommended_products3' variable #}
{% endrecommendations3 %}
where:
- line 1 creates an `itemContext` variable (array) for storing the context items.
- line 2 opens the aggregate insert.
- lines 3-5 are a loop that iterates over the results of the aggregate and add their `sku`s to `itemContext`
Cart recommendations are the only recommendation type that allows multiple items in the context. In other recommendations, only line 4 should be used (adding one item without a loop), unless the aggregate is configured to return a single value.
- line 6 closes the aggregate insert.
- line 8 opens the recommendations3 insert with the context added to the `itemsIds` parameter of the insert (this parameter must be named `itemsIds`).
You can now iterate through the results of the recommendation, as shown in the [first example in this article](#example) or below.
#### Example
The following code is an example of adding complementary item recommendations to a cart page.
**Input:**
<div class="snrs-AI--banner" style="height: auto;">
<div class="snrs-AI--slider">
<div class="snrs-AI--products-slider">
<ul>
{% set itemContext = [] %}
{% aggregate 4d08sdfe-4kof-3db5-mknj-7725f0283533 %}
{%- for r in aggregate_result|reverse -%}
{% set _noop = itemContext.append(r.sku) %}
{%- endfor -%}
{% endaggregate %}
{% recommendations3 campaignId=T5gNrNlMFC57 itemsIds=itemContext %}
{%- for p in recommended_products3 -%}
<li data-snr-ai-product-id="{{p.itemId}}">
<a class="snrs-AI--item-link" href="{{p.link}}" title="{{p.title}}">
<img src="{{ p.imageLink }}" class="products-slider__item-image snrAI-product-image snrAI-product-image-{{p.itemId}}" width="90" alt="{{p.title}}" id="snrAI-image-{{p.itemId}}">
<h3 class="snrs-AI-product--product-name">
<span class="snrs-AI-product--name-first">{{p.title}}</span>
</h3>
</a>
</li>
{%- endfor -%}
{% endrecommendations3 %}
</ul>
</div>
</div>
</div>
<div class="snrs-AI--banner" style="height: auto;">
<div class="snrs-AI--slider">
<div class="snrs-AI--products-slider">
<ul>
<li data-snr-ai-product-id="000097">
<a class="snrs-AI--item-link"
href="https://example.com/accessories-for-shaver/cleaner-contribution-to-shavers-braun-CCR2,id-2369"
title="Cleaning insert for shavers BRAUN CCR2">
<img src="https://example.com/temp/thumbs-new/2/other/cd1c73e35b1db186e79e8a0039b27293_250x200w50.jpg"
class="products-slider__item-image snrAI-product-image snrAI-product-image-000097"
width="90" alt="Cleaning insert for shavers BRAUN CCR2" id="snrAI-image-000097">
<h3 class="snrs-AI-product--product-name">
<span class="snrs-AI-product--name-first">Cleaning insert for shavers BRAUN CCR2</span>
</h3>
</a>
</li>
<li>...</li>
<li>...</li>
<li>...</li>
<li>...</li>
</ul>
</div>
</div>
</div>
### Declaring a specific item context
Instead of using an aggregate, you can insert the item IDs directly into a variable.
{% set itemContext = [] %}
{% set _noop = itemContext.append(item-id) %} {# replace item-id with the value you need #}
{% recommendations3 campaignId=campaign-hash itemsIds=itemContext %}
{# logic of processing the result #}
{# the result is stored in a 'recommended_products3' variable #}
{% endrecommendations3 %}
where:
- line 1 creates an `itemContext` variable (array) for storing the context items.
- line 2 adds an item ID to `itemContext`.
In cart recommendations, you can repeat this line to add more items.
- line 3 opens the recommendations3 insert with the context added to the `itemsIds` parameter of the insert (this parameter must be named `itemsIds`).
You can now iterate through the results of the recommendation, as shown in the [first example in this article](#example).
## Recommendation slots
When you use slots in recommendations, they are returned in a `slots_products3` list.
You can iterate over the items in the slot.
**Example:**
{% recommendations3 campaignId=DkhvrZoTKthD %}
{%- for slot in slots_products3 -%}
{{ slot.name }}
{%- for item in slot.items -%}
{{ item.title }}
{{ item.price.value }}
{% endfor %}
{% endfor %}
{% endrecommendations3 %}
### Selecting a particular slot
If you want to process data from a selection of slots instead of all slots in the response, you can use an IF statement and select a slot or slots by name.
In the following example, only the `foo` and `bar` slots will be displayed (if such slots exist):
{% recommendations3 campaignId=DkhvrZoTKthD %}
{%- for slot in slots_products3 -%}
{%- if (slot.name == "foo") or (slot.name == "bar") -%} {# choose slots by name #}
{# rest of the logic for displaying items from a slot #}
{%- endif -%}
{%- endfor -%}
{% endrecommendations3 %}
{% recommendations3 campaignId=1k2AxH0s00E9 %}
{# iterate over slots: #}
{%- for slot in slots_products3 -%}
{# iterate over rows in the slots: #}
{%- for row in slot.rows -%}
{# access row attributes and metadata: #}
{{ row.attributeValue }}
{{ row.metadata.imageLink }}
{# iterate over items in the row: #}
{%- for item in row.items -%}
{# access item attributes: #}
{{ item.itemId }}
{{ item.title }}
{% endfor %}
{% endfor %}
{% endfor %}
{% endrecommendations3 %}
## External recommendations
[External recommendations](/docs/ai-hub/recommendations-v2/abx-test-with-external-model) let you add a third-party recommendation result into A/B/X tests.
In this type of campaign, you need to provide the IDs of items selected by an external model.
- The IDs must be an array of strings.
- They must be declared with `{% set %}` and used as a variable.
Example:
{% set externalItems = ['sku1','sku2'] %}
{% recommendations3 campaignId=COhsCCOdu8Cg externalItemsIds=externalItems %}
{# logic of processing the result #}
{# the result is stored in a 'recommended_products3' variable #}
{% endrecommendations3 %}
## Filters
You can combine filters and elastic filters from the campaign with your own, or replace the campaign's filters completely.
First, define the filters to apply by using the following syntax:
{% set filters = 'param1=="value"ANDparam2!="value2"' %}
where:
- `param1=="value"` is a filter that includes (`==`) the `value` of `param1`
- `param2!="value2"` is a filter that excludes (`!=`) the `value2` of `param2`
- AND combines the two filters
- `set filters` saves the entire definition to the `filter` variable.
Now, `filters` can be added to the campaign's filters or elastic filters by using the following attributes of the recommendation insert:
- `additionalFilters`/`additionalElasticFilters` store your filters.
- `filtersJoiner`/`elasticFiltersJoiner` set the logic:
- `REPLACE` replaces the campaign's filters with your filters.
- `AND` matches if both your filters and the campaign filters are met.
- `OR` matches if at least one of the filters is met.
### Example: add to filters
This example adds the filters defined by `set filters` to the campaign's filters:
{% set filters = 'param=="value"' %}
{% recommendations3 campaignId=campaign-hash additionalFilters=filters filtersJoiner=AND %}
{{ recommended_products3 }}
{% endrecommendations3 %}
{% set filters = 'param=="value"' %}
{% recommendations3 campaignId=campaign-hash additionalElasticFilters=filters elasticFiltersJoiner=AND %}
{{ recommended_products3 }}
{% endrecommendations3 %}
{% set filters = 'category=="Women>Dresses"' %}
{% recommendations3 campaignId=T5gNrNlMFC57 additionalFilters=filters filtersJoiner=REPLACE %}
{%- for p in recommended_products3 -%}
<li data-snr-ai-product-id="{{p.itemId}}">
<a class="snrs-AI--item-link" href="{{p.link}}" title="{{p.title}}">
<img src="{{ p.imageLink }}" class="products-slider__item-image snrAI-product-image snrAI-product-image-{{p.itemId}}" width="90" alt="{{p.title}}" id="snrAI-image-{{p.itemId}}">
<h3 class="snrs-AI-product--product-name">
<span class="snrs-AI-product--name-first">{{p.title}}</span>
</h3>
<span class="snrs-AI-product--season">{{p.attributes.season}}</span>
</a>
</li>
{%- endfor -%}
{% endrecommendations3 %}
<div class="snrs-AI--banner" style="height: auto;">
<div class="snrs-AI--slider">
<div class="snrs-AI--products-slider">
<ul>
<li data-snr-ai-product-id="000097">
<a class="snrs-AI--item-link"
href="https://example.com/dresses/dress-alla"
title="Dresse Alla">
<img src="https://example.com/dresses/dress-alla_250x200w50.jpg"
class="products-slider__item-image snrAI-product-image snrAI-product-image-000097"
width="90" alt="Dresse Alla" id="snrAI-image-000097">
<h3 class="snrs-AI-product--product-name">
<span class="snrs-AI-product--name-first">Dresse Alla</span>
</h3>
<span class="snrs-AI-product--season">SUMMER</span>
</a>
</li>
<li>...</li>
<li>...</li>
<li>...</li>
<li>...</li>
</ul>
</div>
</div>
</div>
## Open Graph meta tags in filters
You can insert the value of an OG tag into your filters.
### Syntax
{% set additionalParam = metric_additional_params["property_name"] %} {# stores value of OG tag #}
{% set filters = 'param=="' + additionalParam +'"' %} {# adds value of OG tag to your filter #}
### Example
The following example of a recommendation on a category page [replaces the campaign's filter](#filters) with a filter based on OG tags.
#### Input
{% set season = metric_additional_params["product:season"] %}
{% set filters = 'attributes.season=="' + season +'"' %}
{% recommendations3 campaignId=T5gNrNlMFC57 additionalFilters=filters filtersJoiner=REPLACE %}
{%- for p in recommended_products3 -%}
<li data-snr-ai-product-id="{{p.itemId}}">
<a class="snrs-AI--item-link" href="{{p.link}}" title="{{p.title}}">
<img src="{{ p.imageLink }}" class="products-slider__item-image snrAI-product-image snrAI-product-image-{{p.itemId}}" width="90" alt="{{p.title}}" id="snrAI-image-{{p.itemId}}">
<h3 class="snrs-AI-product--product-name">
<span class="snrs-AI-product--name-first">{{p.title}}</span>
</h3>
<span class="snrs-AI-product--season">{{p.attributes.season}}</span>
</a>
</li>
{%- endfor -%}
{% endrecommendations3 %}
<div class="snrs-AI--banner" style="height: auto;">
<div class="snrs-AI--slider">
<div class="snrs-AI--products-slider">
<ul>
<li data-snr-ai-product-id="000097">
<a class="snrs-AI--item-link"
href="https://example.com/dresses/dress-alla"
title="Dresse Alla">
<img src="https://example.com/dresses/dress-alla_250x200w50.jpg"
class="products-slider__item-image snrAI-product-image snrAI-product-image-000097"
width="90" alt="Dresse Alla" id="snrAI-image-000097">
<h3 class="snrs-AI-product--product-name">
<span class="snrs-AI-product--name-first">Dresse Alla</span>
</h3>
<span class="snrs-AI-product--season">SUMMER</span>
</a>
</li>
<li>...</li>
<li>...</li>
<li>...</li>
<li>...</li>
</ul>
</div>
</div>
</div>
# Inserts
In Synerise, you can create various types of analytics, such as [aggregates](/docs/crm/aggregates/creating-profile-aggregates) and [expressions](/docs/crm/expressions), that calculate customer actions within a workspace. You can work with [metrics](/docs/analytics/metrics), which allow you to analyze the events; and with AI-powered [recommendations](/docs/ai-hub/recommendations-v2/recommendation-types#personalized), to offer your customers exactly what they want.
Some Jinjava code can also be easily added with the [snippet widget](/docs/assets/snippets). More functionalities will be added to it in the future.
In conjunction with Jinjava engine templates, you can design complex conditions or convert the content of inserts into communication with customers.
{% recommendations_json3 campaignId=COhsCCOdu8Cg %} {% endrecommendations_json3 %}
If your campaign type is [External](/docs/ai-hub/recommendations-v2/abx-test-with-external-model), you need to provide the IDs of the items from the external model.
- The IDs must be an array of strings.
- They must be declared with `{% set %}` and used as a variable.
Example:
{% set externalItems = ['sku1','sku2'] %}
{% recommendations_json3 campaignId=COhsCCOdu8Cg externalItemsIds=externalItems %}
{% endrecommendations_json3 %}
#### Example
A document has the following content.
"{% recommendations_json3 campaignId=FcP8UtRgrype %} {% endrecommendations_json3 %}"
The recommendation type of the requested campaign is "Top items". It's configured to return one item in a slot.
The output of the generated document is the following:
{
"campaignId": "FcP8UtRgrype",
"campaignHash": "0cfa5c65-a62a-47d6-93f5-fa98eb346d6b",
"recommended": {
"data": [
{
"category": "Synerise Hub > Use cases",
"itemId": "21baa503-9c26-42a4-aebe-1e04adb0bf2e",
"link": "https://synerise.com/use-cases/?snrai_campaign=FcP8UtRgrype&snrai_id=0cfa5c65-a62a-47d6-93f5-fa98eb346d6b",
"title": "Use cases"
}
],
"extras": {
"contextItems": null,
"correlationId": "0cfa5c65-a62a-47d6-93f5-fa98eb346d6b",
"slots": [
{
"id": 0,
"itemIds": [
"21baa503-9c26-42a4-aebe-1e04adb0bf2e"
],
"name": "Unnamed slot"
}
]
}
}
}
## Documents
You can refer to a document in the following way:
{% document SLUG %}
In this case, you can't pass variables to the document you refer to.
## Screen view collection
The `{% screenviewcollection %}` insert is added to a Screen View automatically when you create it in the Synerise Portal.
It inserts all the documents you added in the **Documents to display** section when configuring the Screen View.
## Handling variables when displaying screen views/documents
Screen views and documents may include variables. These variables may be profile attributes (including analytics such as expressions) or variables that are not part of a profile.
If the non-profile variables aren't declared in the screen view or document, they can be injected when making the request.
curl --location 'https://api.synerise.com/schema-service/v2/documents/example-1/generate' \
--header 'Authorization: Bearer PROFILE_JWT' \
--header 'Content-Type: application/json' \
--data '{
"foo": 12
}'
**Output**:
{
"uuid": "98ed0cef-ed81-4fc7-83e8-638f2009174d",
"slug": "example-1",
"schema": "examples",
"content": {
"exampleCustomParameter": "12.0",
"exampleExpression": "segment2",
"exampleProfileAttribute": "example@synerise.com"
}
}
API reference: [/schema-service/v2/documents/{slug}/generate](https://hub.synerise.com/api-reference/asset-management#tag/Documents/operation/generateDocumentBySlug)
Other endpoints with the same behavior:
- [/schema-service/v2/documents/{documentId}/generate](https://hub.synerise.com/api-reference/asset-management#tag/Documents/operation/generateDocumentByIdPost)
- [/schema-service/v3/screen-views/{feedSlug}/generate](https://hub.synerise.com/api-reference/asset-management#tag/Screen-views/operation/generateScreenViewByFeedPostV2)
curl --location 'https://api.synerise.com/schema-service/v2/documents/example-1/generate/by/id' \
--header 'Authorization: Bearer WORKSPACE_TOKEN' \
--header 'Content-Type: application/json' \
--data-raw '{
"identifierValue": "8701078606",
"params": {
"foo": 12
}
}'
**Output**:
{
"uuid": "98ed0cef-ed81-4fc7-83e8-638f2009174d",
"slug": "example-1",
"schema": "examples",
"content": {
"exampleCustomParameter": "12.0",
"exampleExpression": "segment2",
"exampleProfileAttribute": "example@synerise.com"
}
}
API reference: [/schema-service/v2/documents/{documentIdentifier}/generate/by/{identifierType}](https://hub.synerise.com/api-reference/asset-management#tag/Documents/operation/generateDocumentWithProfileContextPost)
Other endpoints with the same behavior:
- [/schema-service/v2/screen-views/{feedSlug}/generate/by/{identifierType}](https://hub.synerise.com/api-reference/asset-management#tag/Screen-views/operation/generateScreenViewByIdentifierPostV2)
curl --location 'https://api.synerise.com/schema-service/v2/documents/example-1/generate' \
--header 'Authorization: Bearer WORKSPACE_TOKEN' \
--header 'Content-Type: application/json' \
--data-raw '{
"foo": 12,
"customer.email": "example@synerise.com"
}'
**Output**:
{
"uuid": "98ed0cef-ed81-4fc7-83e8-638f2009174d",
"slug": "example-1",
"schema": "examples",
"content": {
"exampleCustomParameter": "12.0",
"exampleExpression": "N/A",
"exampleProfileAttribute": "example@synerise.com"
}
}
API reference: [/schema-service/v2/documents/{slug}/generate](https://hub.synerise.com/api-reference/asset-management#tag/Documents/operation/generateDocumentBySlug)
Other endpoints with the same behavior:
- [/schema-service/v2/documents/{documentId}/generate](https://hub.synerise.com/api-reference/asset-management#tag/Documents/operation/generateDocumentByIdPost)
- [/schema-service/v3/screen-views/{feedSlug}/generate](https://hub.synerise.com/api-reference/asset-management#tag/Screen-views/operation/generateScreenViewByFeedPostV2)


{
"createDate": 1695989087498,
"action": "product.addToCart",
"params": {
"source": "MOBILE",
"finalUnitPrice": "3.25",
"brand": "exampleBrand",
"revenue": 9.75,
"eventCreateTime": "2023-09-29T12:04:47.498322032Z",
"ip": "13.93.68.194",
"quantity": 3,
"sku": "189784563455",
"currency": "USD"
}
}
Examples of output:
- `{{ automationPathSteps['Node123'].event.params.brand }}` outputs `"exampleBrand"`
- `{{ automationPathSteps['Node123'].event.params.sku }}` outputs `"189784563455"`
### Context
1. The context, defined through the [Trigger](/docs/automation/triggers) or [Event Filter](/docs/automation/conditions/client-event-filter-node) node, remains consistent and does not change with the [Action nodes](/docs/automation/actions) (**Outgoing Webhook**, **Send Event**, **Send Email**, and so on).
3. At the beginning of the workflow, `
{% set foo = event.params.example %}
## Data context
The tag allows referencing the context of data retrieved through nodes that fetch data (e.g., Get Statistics, SFTP - Get File), and then using this data in:
- [Integration nodes](/docs/automation/integration) which don't require a data input file
- [SMS Alert](/docs/automation/actions/sms-alert-node) nodes
- [Email Alert](/docs/automation/actions/send-email-alert-node) nodes
The data is accessed as rows. You can retrieve up to 10000 rows.
{% datareference node='nodeName' maxRows=10000 %}
{{ datareference_result}}
{% enddatareference %}
where:
- `node` is the name of the node whose data you want to access.


[ {%- datareference node='Campaigns sent yesterday' maxRows=10 -%}
{%- for r in datareference_result -%}
["{{ r.campaignHash }}", "{{ r.campaignTitle }}", "{{ r.campaignType }}", "{{ r.clickCount }}", "{{ r.clickRate }}", "{{ r.openCount }}", "{{ r.openRate }}", "{{ r.sendCount }}", "{{ r.sendingTime }}", "{{ r.uniqueCappingCount }}", "{{ r.uniqueSendCount }}", "{{ r.utm.campaign }}", "{{ r.utm.content }}", "{{ r.utm.medium }}", "{{ r.utm.source }}", "{{ r.utm.term }}"] {%- if not(loop.last) -%},{%- endif -%}
{%- endfor -%}
{%- enddatareference -%} ]
The `{%- if not(loop.last) -%},{%- endif -%}` condition prevents adding a comma after the last row.
{ "body": { "customer_email": "example@example.com", "order_number": "111111111", "products": [ { "name": "Earwax", "category": "Hygiene", "id": "abcdefgh", "image_url": "http://exampleimage.url", "product_url": "http://exampleproduct.url", "group_id": "groupid" } ] } "endpointId": "XXXX-XXXX-XXXX-XXXX-XXXXXXXXXX", "eventId": "XXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", "headers": { "X-Request-ID": "XXXXXXXXXXXXXXXXXXX", "X-Forwarded-Host": "example host", }, "time": 1583206296408 }{ "action": "goal.achieve", "label": "goal.achieve", "client":{ "email": "{{request.body.customer_email}}" }, "params":{ "created_at": "2021-04-28T14:09:27.000Z", "group_id": "{{request.body.group_id}}", "image_url": "{{request.body.image_url}}", "name": "{{request.body.name}}", "product_url": "{{request.body.product_url}}", "X-Request-ID": "{{request.headers["X-Request-ID"]}}", "X-Forwarded-Host": "{{request.headers["X-Forwarded-Host"]}}" } }

fieldIds are external-id and customer-name (not shown in the screenshot).

{% set arr = [] %}{% do arr.append('6678347477') %}{% do arr.append('4551874894')%}{{ arr | join('","') }}
It's the only case when `"` is allowed
## Encrypting and decrypting AES keys
To use this tag, you must first [create an encryption key in Synerise](/docs/settings/data-exchange-encryption#adding-an-encryption-key).
You can retrieve the value for key name from the **Name** column on the list of encryption keys in **Settings > Data encryption**.
### Encrypt
For an AES key, it will return the input data encrypted with the AES-GCM algorithm using the secret encryption key.
The output is: `base64encode([IV] + [Encrypted Text] + [Authentication Tag])`
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | The name of the encryption key |
**Example:**
{{ variable | encrypt('aes-web-key-1') }}
### Decrypt
For an AES key, it expects input in the form returned by the [encrypt filter](#encrypt) and performs decryption on the data. The filter returns text data.
| Type | Required | Description |
| :--- | :--- | :--- |
| string | yes | The name of the decryption key |
**Example:**
{{ encryptedData | decrypt('aes-web-key-1') }}
## Encrypting and decrypting data
To use this tag, you must first [create an encryption key in Synerise](/docs/settings/data-exchange-encryption#adding-an-encryption-key).
You can retrieve the value for key name from the **Name** column on the list of encryption keys in **Settings > Data encryption**.
### Encrypt data
The following example takes the following value: `data-to-encrypt` and encrypts it with the following encryption key: `encryptionKey1`.
{% encryptdata keyName=encryptionKey1 %}data-to-encrypt{% endencryptdata %}
### Decrypt data
{% decryptdata keyName=encryptionKey1 %}dadadaweer23==2323{% enddecryptdata %}
# Connection inserts
You can use Jinjava in [connections](/docs/settings/tool/connections) to provide context or work with parameters.

Bearer {{ authResponseBody | fromjson | attr("token") }}
It takes the `JSON` response body stored in `authResponseBody`, parses it into a usable structure, extracts the value of the `token` field. Outputs a string like: `Bearer "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."`
# Brickworks inserts
## Brickworks
To learn:
- about tags exclusive for use in Brickworks content, see [Brickworks Jinjava inserts](/docs/assets/brickworks/brickworks-jinjava-inserts).
- about using Jinjava to display Brickworks, see ["Generating objects"](/docs/assets/brickworks/generating-objects#jinjava-tags).
# Data transformation inserts
This article presents inserts that can be used while creating [transformation rules](/docs/automation/data-transformation-and-imports/creating-data-transformation).
root['columnName']
### Change current value
The following snippet replaces the value of `paymentInfo`:
- if the value is `cash`, it is replaced with `POS`
- any other value is replaced with `WEB_DESKTOP`
{%- if root['paymentInfo'] == 'cash' -%}POS{%- else -%}WEB_DESKTOP{%- endif -%}
### Conditionally keep current value
The following snippet keeps `cash` as the value of `paymentInfo`, but replaces any other value with `WEB_DESKTOP`
{%- if root['paymentInfo'] == 'cash' -%}{{root['paymentInfo']}}{%- else -%}WEB_DESKTOP{%- endif -%}
### Combine conditions
The following snippet replaces the value of `paymentInfo`:
- `cash` is replaced with `POS`
- `online` is replaced with `WEB_DESKTOP`
- any other value is replaced with `UNKNOWN`
{%- if root['paymentInfo'] == 'cash' -%}POS{%- elif root['paymentInfo'] == 'online' -%}WEB_DESKTOP{%- else -%}UNKNOWN{%- endif -%}
### Replace string
The following snippet takes the value of `g:sale_price` and replaces " USD" with an empty string, for example "256 USD" becomes "256".
{{ root["g:sale_price"]|replace(" USD", "") }}
## Fill in empty values
If a cell has no value (is empty), you can insert a value.
The following snippet replaces a missing value of `paymentInfo` with `foo`
{%- if not root['paymentInfo'] -%}foo{%- else -%}{{root['paymentInfo']}}{%- endif -%}
## Event salt
The event salt is a UUID generated on the basis of unique combination of at least two parameters. This allows you to avoid duplicating an event entry in the database if it is imported more than once.
1. Select two or more parameters whose combination is unique.
For example, you can use `orderID` and `eventTimestamp`. Even if one of them repeats for some reason, the chances of both being identical between two events are practically zero.
2. Add an `eventSalt` column.
3. In the `eventSalt` column, add the following insert (example according to step 1):
{{root.orderId}}{{root.eventTimestamp}}
where `orderId` and `eventTimestamp` are column names.
**Result:**
When the import is processed, the value combination in the `eventSalt` column is calculated into a UUID that is always the same. When other imports are performed and that UUID already exists in the database, the event is not imported as a duplicate.
## Calculate revenue
If the file does not have a column that calculates the total value of an imported transaction, add a `revenue.amount` and `value.amount` column and use Jinjava to perform that calculation.

{% set line_sums = [0] %}
{%- for prod in root.products -%}
{%- if line_sums.append(prod["productQuantity"]|int*prod["finalUnitPriceAmount"]|replace(",", ".")|float) -%}
{%- endif -%}
{%- endfor -%}
{{ line_sums|sum }}
# In-app message inserts

{{ metric_additional_params["product:PARAM_NAME"] }}
// Get the unique ID from meta tags:
{% set key = metric_additional_params['product:retailer_part_no'] %}
// Use the part number to retrieve the value of the 'title' column:
{% catalog.catalogName(key).title %}
You can use this mechanism to retrieve data such as the name, price, or brand of an item from a catalog. Thanks to this, the catalog can become a single source of data for multiple websites that present the same item.
In this example, the insert is used in a dynamic content communication created for the article you are reading now.

Replace this text
**The original HTML code, before dynamic content is downloaded, is the following:**
```html
Replace this text
```
## Social proof
A social proof insert lets you retrieve a value of the [metric](/docs/analytics/metrics).
- The metric must contain only one [dynamic key](/docs/analytics/i_events-parameter-value#dynamic-key).
- In the configuration of the metric, we recommend using the **Equal** operator instead of the **Contain** operator. The **Contain** operator in the social proof insert will work only if there is an exact match between the two compared elements (for example, when comparing `abc` to `abcd`, `abc` won't be considered a match for `abcd`).
{% socialproof %} metric-hash {% endsocialproof %}
**Example:**
The number of times the product was added to cart during the last 30 days.
<div class="snrs-wrapper">
<div id="snrsCornerMessage" class="snrs-corner-message-wrap">
<div class="snrs-corner-message">
<div class="snrs-corner-main">
<div class="snrs-corner-message-text">
This product has been added to the cart {% socialproof %} 537165da-9d8c-4460-a3a2-6294f1f7aef9 {% endsocialproof %} times in the last 30 days!
</div>
</div>
</div>
</div>
</div>
Output (metric result is "235"):
<div class="snrs-wrapper">
<div id="snrsCornerMessage" class="snrs-corner-message-wrap">
<div class="snrs-corner-message">
<div class="snrs-corner-main">
<div class="snrs-corner-message-text">
This product has been added to the cart 235 times in the last 30 days!
</div>
</div>
</div>
</div>
</div>
## Validation
Whenever you use Jinjava in dynamic content, verify that it displays correctly for a few different test customers to make sure that the logic you applied covers all scenarios. If Jinjava fails to render, the communication is not sent to a customer at all.
# SMS inserts
## Common tags used in text messages
You can use all tags from [Insert usage](/developers/inserts/insert-usage).
## Adding UTM and tracking parameters to link
If the message includes links, you can automatically add parameters (such as UTM) and track click events by using `{% preparelink %}{% endpreparelink %}`. This will generate a redirect URL based on the hosting environment of your workspace:
If your workspace is hosted on:
- Microsoft Azure EU, the default domain redirect URL is `link.snrs.it`,
- Microsoft Azure USA, the default domain redirect URL is `link.azu.snrs.it`
- Google Cloud, the default domain redirect URL is `link.geb.snrs.it`.
{% preparelink %}YOUR_URL{% endpreparelink %}
Example of a parsed link:
```plaintext
/?snrs_medium=email&snrs_action=newsletter.click&snrs_test=false&snrs_var=4715029&snrs_cp=6b716f86-a14d-4b8c-8795-872f7432a046&snrs_cl=b5d8c721-c2b7-42ac-9cd5-7714dedf73bf&snrs_category=client._DEVICE_.browser.mail&snrs_he=1940871749&snrs_redir=1
```
## Short links
If you send links in text messages, you can use a Jinjava code to shorten the URL addresses to make the text message look professional and the link more reliable.
- The default domain of the shortened links is `snrs.it`. If you want to use your own domain, see [Custom subdomain for shortened links](/docs/campaign/SMS/custom-shortener-domain).
- The shortened links don't require HTTPS. If you include a link with `http://` in the message, it will be redirected to HTTPS when opened.
- You can combine short link insert with [prepare link](/developers/inserts/sms#adding-utm-and-tracking-parameters-to-link) to track URL's parameters (such as UTM) and click events from a message.
{% shorturl %}YOUR_URL{% endshorturl %} | The URL is shortened, however, the clicks aren't collected. |
| {% shorturl %}{% preparelink %}YOUR_URL{% endpreparelink %}{% endshorturl %} | The URL is shortened and the clicks in the link are collected, so this event can be used in analyses. |
#### Example
{% shorturl %}{% preparelink %}https://example.com/season-discounts/?utm_source=examplecom&utm_medium=slider&utm_content=examplecom&utm_term=discount-amazon-perf-2_W3&utm_campaign=Campaign-OnGoing{% endpreparelink %}{% endshorturl %}
# Email inserts
## Common tags available in email communication
You can use all tags from [Insert usage](/developers/inserts/insert-usage).
{{ synerise-open-in-browser }}
The URL is generated as plain text. If you want it to display as a hyperlink, add HTML, for example:
<a href="{{ synerise-open-in-browser }}">Click to open the message in a browser</a>
## Adding a resignation link
You can generate a URL that revokes the customer's email communication agreement.
{{ synerise-resign-link }}
The URL is generated as plain text. If you want it to display as a hyperlink, add HTML, for example:
<a href="{{ synerise-resign-link }}">Unsubscribe</a>
## Adding UTM and tracking parameters to links
If the message includes links, you automatically add parameters (such as UTM) and track click events by using `{% preparelink %}{% endpreparelink %}`. This will generate a redirect URL based on the hosting environment of your workspace:
If your workspace is hosted on:
- Microsoft Azure EU, the default domain redirect URL is `link.snrs.it`,
- Microsoft Azure USA, the default domain redirect URL is `link.azu.snrs.it`
- Google Cloud, the default domain redirect URL is `link.geb.snrs.it`.
{% set a = "/" %}
<a href="{% preparelink %}{{a}}{% endpreparelink %}">Link text</a>
- If the link is defined in the template as plain HTML, the parameters and tracking are added automatically when parsing the HTML. You don't need to use the insert:
<a href="">Link text</a>
- Mobile push and SMS:
-
{% preparelink %}YOUR_URL{% endpreparelink %}
Example of a parsed link:
```plaintext
/?snrs_medium=email&snrs_action=newsletter.click&snrs_test=false&snrs_var=4715029&snrs_cp=6b716f86-a14d-4b8c-8795-872f7432a046&snrs_cl=b5d8c721-c2b7-42ac-9cd5-7714dedf73bf&snrs_category=client._DEVICE_.browser.mail&snrs_he=1940871749&snrs_redir=1
```
### WhatsApp Partner integration: skipDomain variant
The WhatsApp Partner integration requires a special variant of the tag:
{% preparelink skipDomain=true %} YOUR_URL {% endpreparelink %}
The `skipDomain=true` parameter instructs Synerise to skip prepending the redirect domain to the link. This is necessary because in the WhatsApp Partner integration, the redirect domain is configured directly in Meta — Synerise only appends the tracking parameters to the URL you provide. Without this flag, the default redirect domain would be added, which would break the link.
{
"action": "message.notSent",
"eventUUID": "e0096c9d-8abc-4c4e-b75f-efa3c56934b0",
"createDate": 1620912890658,
"label": "dfbbb5f6-abf6-4c79-87db-f893359ffa5d",
"params": {
"clientId": 1382495929,
"auth.internal": false,
"info": "rendering failed",
"testDelivery": true,
"id": "dfbbb5f6-abf6-4c79-87db-f893359ffa5d",
"campaignName": "Test",
"extra": "Missing synerise-open-in-broser value",
"time": 1620912890658,
"title": "Test"
}
}
{% set a = "/" %}
<a href="{% preparelink %}{{a}}{% endpreparelink %}">Link text</a>
- If the link is defined in the template as plain HTML, the parameters and tracking are added automatically when parsing the HTML. You don't need to use the insert:
<a href="">Link text</a>
- Mobile push and SMS:
-
{% preparelink %}YOUR_URL{% endpreparelink %}
Example of a parsed link:
```plaintext
/?snrs_medium=email&snrs_action=newsletter.click&snrs_test=false&snrs_var=4715029&snrs_cp=6b716f86-a14d-4b8c-8795-872f7432a046&snrs_cl=b5d8c721-c2b7-42ac-9cd5-7714dedf73bf&snrs_category=client._DEVICE_.browser.mail&snrs_he=1940871749&snrs_redir=1
```
### WhatsApp Partner integration: skipDomain variant
The WhatsApp Partner integration requires a special variant of the tag:
{% preparelink skipDomain=true %} YOUR_URL {% endpreparelink %}
The `skipDomain=true` parameter instructs Synerise to skip prepending the redirect domain to the link. This is necessary because in the WhatsApp Partner integration, the redirect domain is configured directly in Meta — Synerise only appends the tracking parameters to the URL you provide. Without this flag, the default redirect domain would be added, which would break the link.
{% set a = "/" %}
<a href="{% preparelink %}{{a}}{% endpreparelink %}">Link text</a>
- If the link is defined in the template as plain HTML, the parameters and tracking are added automatically when parsing the HTML. You don't need to use the insert:
<a href="">Link text</a>
- Mobile push and SMS:
-
{% preparelink %}YOUR_URL{% endpreparelink %}
Example of a parsed link:
```plaintext
/?snrs_medium=email&snrs_action=newsletter.click&snrs_test=false&snrs_var=4715029&snrs_cp=6b716f86-a14d-4b8c-8795-872f7432a046&snrs_cl=b5d8c721-c2b7-42ac-9cd5-7714dedf73bf&snrs_category=client._DEVICE_.browser.mail&snrs_he=1940871749&snrs_redir=1
```
### WhatsApp Partner integration: skipDomain variant
The WhatsApp Partner integration requires a special variant of the tag:
{% preparelink skipDomain=true %} YOUR_URL {% endpreparelink %}
The `skipDomain=true` parameter instructs Synerise to skip prepending the redirect domain to the link. This is necessary because in the WhatsApp Partner integration, the redirect domain is configured directly in Meta — Synerise only appends the tracking parameters to the URL you provide. Without this flag, the default redirect domain would be added, which would break the link.
