> 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))
If you use Visual Studio Code as your editor, you can use code snippets to speed up working with inserts. You can find the snippets in our Github repository: [https://github.com/Synerise/jinja-code-snippet](https://github.com/Synerise/jinja-code-snippet)
### Operators Operators let you compare and manipulate values or add more complex logic. #### Logic operators See ["If, else if, else: Combining conditions"](/developers/inserts/tag#combining-conditions). #### Math operators | Operator | Description | Example | | --- | --- | --- | | `+` | Adds numbers, lists, objects, or strings.1 | `{{ 1 + 2 }}` = 3| | `-` | Subtracts numbers. | `{{ 2 - 1 }}` = 1| | `/` | Divides numbers, returns a floating point number. | `{{ 5 / 2 }}` = 2.5 | | `//` | Divides numbers, rounds to an integer. | `{{ 5 // 2 }}` = 2 | | `%` | Returns the remainder of a division. | `{{ 5 % 2 }}` = 1 | | `*` | Multiplies numbers. | `{{ 3 * 2 }}` = 6 | | `**` | Raises to a power. | `{{ 2 ** 3 }}` = 8 | | `()` | Groups formulas. | `{{ (2 + 2) * 2 }}` = 8| 1 The recommended way to concatenate strings is the `~` operator (see ["Other"](#other-operators)). #### Comparison operators | Operator | Description | Example | | --- | --- | --- | | `==`1 | L(eft) is equal to R(ight) | `{{ 2 == 2 }}` = true | | `!=`1 | L is not equal to R| `{{ 2 != 3 }}` = true | | `>` | L is greater than R | `{{ 2 > 1 }}` = true | | `>=` | L is greater than or equal to R | `{{ 3 >= 3 }}` = true | | `<` | L is lower than R | `{{ 1 < 2 }}` = true | | `<=` | L is lower than or equal to R | `{{ 3 <= 3 }}` = true | 1Can be used to compare strings, objects, and lists. #### Other operators | Operator | Description | Example | | --- | --- | --- | | `in` | Checks if a value is in a list. | `{{ 2 in [1,2,3] }}` = true | | `is` | Performs a [test](/developers/inserts/exptest). | `{{ 4 is divisibleby 2 }}` = true | | `~` | Converts L and R into strings and concatenates them. |
{%- 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).
If an aggregate has dynamic elements (such as values from another aggregate or expression), then instead of using the `aggregate` tag: 1. Create an expression that includes the aggregate with dynamic values. 2. Insert this expression by using the [`expression` tag](#expressions).
**Syntax:**
{% aggregate aggregate-hash %}
  {{ aggregate_result[0] }}
{% endaggregate %}
The aggregate result is always returned as a list. To use the data, use [loops](/developers/inserts/tag#for) or access a [specific index](/developers/inserts/insert-usage#arrays) in the result.
**Example:** An aggregate that holds a list of categories that have recently been added to the cart.
{% 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>
Troubleshooting common problems: - If your template fails to render, verify that all referenced aggregates exist. - If the output is empty, use [try/catch](/developers/inserts/tag#trycatch) to handle empty aggregate results.
### Promotions
Synerise Communication - inserting promotions into templates
--- You can use an insert to retrieve promotions assigned to a profile, including anonymous profiles.
This tag is currently only available in Experience and Automation Hubs.
**Syntax:**
{%- 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.
Available fields
- the `fields` argument (required, non-empty) uses the `getFields` variable in the function. This is the only way of using an array-type argument in a function. - `optional arguments` can be used to filter the results. See ["Optional arguments"](#optional-arguments). - `promotions_result` is an object with all promotions assigned to a profile. You can retrieve up to 100 promotions. This can be changed by contacting Synerise Support. **Example:**
{%- 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>
#### Optional arguments You can manipulate the results of the `{% promotions %}` insert with the following optional arguments: | Name | Type | Default | Description | | ----------------- | ---------------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `limit` | Integer | 20 | The maximum number of promotions to retrieve. | | `status` | String | No filtering | Filter results by status: `ACTIVE`, `ASSIGNED`, `REDEEMED`. | | `sort` | Array of strings | See description | Sort results by field, choose direction with `asc` and `desc`, for example: `priority,desc`. You can also use fields that aren't declared in the `fields` argument.
If not defined, the promotions are sorted by our AI. If the AI model isn't trained, they are sorted by creation date, ascending.
This argument must be declared with `{% set %}` and used as a variable - the variable is an array with one string that consists of the field name and direction (see example below the table). | | `tagNames` | Array of strings | No filtering | Filter results to promotions with certain tags. Must be declared with `{% set %}` and used as a variable. | | `presentOnly` | Boolean | No filtering | When `true`, only promotions with `startAt later than now` and `expireAt earlier than now` are retrieved. | | `displayableOnly` | Boolean | No filtering | When `true`, only promotions with `displayFrom later than now` and `displayTo earlier than now` are retrieved. | | `uuids` | Array of strings | No filtering | Filter results to promotions with certain UUIDs. Must be declared with `{% set %}` and used as a variable. | **Example:** Retrieve promotions that are currently displayable, filter by tags, and sort by creation date:
{%- 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
Product Update - Personalized promotions
This insert can only be used in Experience and Automation Hubs.
The `handbills` insert assigns [personalized promotions](/docs/ai-hub/personalized-promotions) to a profile and returns a list of promotions assigned to the profile, including promotions with type other than `HANDBILL`. By default, the insert returns up to 20 promotions of all types, with any status. You can change this with optional parameters. **Syntax**:
{%- 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).
See example raw output

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}}]`

**Example**: You can iterate over the returned promotions and retrieve only the parameters that you need.
{%- 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>
#### Optional arguments {#optional-arguments-2} You can filter the results of the `{% handbills %}` insert with these optional arguments: - `type`: a list of promotion types. Must be declared as a variable. The allowed values are: `GENERAL`, `CUSTOM`, `MEMBERS_ONLY`, `HANDBILL` - `status`: a list of promotion statuses. Must be declared as a variable. The allowed values are: `ACTIVE`, `ASSIGNED`, `REDEEMED` - `limit`: the maximum number of results to retrieve. If not defined, 20 results are returned. By default, you can't set the limit to more than 100. To change this, contact Synerise Support. **Example** Retrieve 5 handbill-type promotions that are active or assigned.
{%- 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
This insert can't be used in Screen Views and Documents.
This insert can be used to retrieve recommendations in HTML. If you need an insert that can be used in JSON requests (for example, generating a document), see [Screen views and Documents inserts](/developers/inserts/screen-views-documents#recommendations).
{% 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.
`itemKey` must always be entered as a variable.
CORRECT:
{% set myitemKey = "1234" %}
    {% catalog.catalogName(myitemKey).columnName %}
WRONG:
{% catalog.catalogName("1234").columnName %}
**Example:**
<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:
Screenshot of a catalog with one column that stores a string and one column that stores an object
Example of a catalog with one column that stores a string and one column that stores an object
To extract more values, add more `object.get()` statements. ##### Handling non-existing items in catalogs By default, when a requested item does not exist in the catalog, the `catalogitemv2` insert is not executed at all (communication is not sent). You can change this behavior by setting the optional `allowEmpty` parameter to `True`. With this setting, the insert returns nulls as the values of the item's parameters. You should always verify if property exists before accessing it in order to avoid errors. The following code returns the string `No item` if the requested `itemKey` does not exist in the catalog and the requested `name` parameter is empty:
{% 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!`
You can also use the [try/catch](/developers/inserts/tag#trycatch) tag and the [default value](/developers/inserts/filter#default) filter.
##### Advanced use You can check if a customer has an attribute set and act accordingly. For example, this can be used to set up a single campaign for customers who have an attribute and those who don't. Without the check, you would need to create two separate campaigns. **Example 1:** Check if a customer belongs to a loyalty club and what kind of membership they have:
{%- 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.
If your code pool is limited, testing email or dynamic content templates (including as a preview in the creator) consumes codes from the pool in the same way as when the communication is sent out to customers. You should use a separate pool for testing.
#### Assigning a code to a profile **Syntax:**
{% 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 %}
This insert used to be known as `kill` and `killit`. They are now deprecated and may be removed in the future.
### Brickworks Use Brickworks content in templates across the Synerise platform with dedicated JinJava tags. JinJava tags work consistently across all Synerise modules that support JinJava rendering, creating a unified content experience throughout your platform: - **Experience Hub channels** – Email campaigns, SMS messaging, mobile push notifications, and web push notifications with dynamic, personalized content - **Automation Hub workflows** – Sophisticated automation sequences with content that adapts based on customer actions and behavioral triggers - **Screen views and Documents** – Interactive displays, personalized mobile applications content - **In-App Messaging**– Contextual experiences that respond to customer behavior in real-time #### Generate 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 `brickworksgenerate` tag generates a an object from a record with all references resolved and Jinja templates rendered:
{% 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.
You can collect the filters in an object and provide that object as an argument in the tag. Example:
{% set parametersVar = {
    search: "string",
    filters: "status==PUBLISHED",
    slugs: ["string","string"],
    ids: ["uuid","uuid"]
} %}
{% brickworksrecordsvar
    schemaId=string
    filteringParams=parametersVar %}
{{ brickworks_result }}
{% endbrickworksrecordsvar %}
You can enter the filters as arguments of the tag. Some of them must first be declared as variables with `set`, as shown in the example:
{% 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 %}
# Jinjava tests Tests allow you to return true/false values depending on the tested value.
If you use Visual Studio Code as your editor, you can use code snippets to speed up working with inserts. You can find the snippets in our Github repository: [https://github.com/Synerise/jinja-code-snippet](https://github.com/Synerise/jinja-code-snippet)
## IsContainingAll Returns `true` if a list contains all the values from another list. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | list | yes | If this list contains all the items from the list provided in the params, the test returns `true`. | **Parameters:** | Type | Required | Description | | :--- | :--- | :--- | | list | yes | The list that must be contained in the list provided as input | **Example:**
{{ [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).
`is iterable` is an alias for [`is sequence`](#issequence) — both run the same check and always return the same result. This means values that Jinjava can still loop over with `{% for %}`, such as a dictionary, return `false` for `is iterable`. Don't rely on this test to confirm whether a value can be looped over; check the value's actual type instead.
**Input:** | Type | Required | Description | | :--- | :--- | :--- | | object | yes | The object to check | **Example:**
{%- 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 |
The [`|bool` filter](/developers/inserts/filter#bool) uses stricter conversion rules and can return a different result from `is truthy` for the same input. For example, `'string' is truthy` returns `true`, but `'string'|bool` returns `false`.
**Input:** | Type | Required | Description | | :--- | :--- | :--- | | value | yes | The value to check | **Example:**
{%- if foo is truthy -%}
    {# code to render if foo is truthy #}
{%- endif -%}
For strict type-and-value equality without any boolean conversion, use the [`sameas` test](/developers/inserts/exptest#issameas). Unlike `is truthy`, `sameas` checks that two values are identical without type coercion. For example, `"1" == true` returns `true` due to boolean conversion, but `"1" is sameas true` returns `false` because the types differ.
## IsUndefined Returns `true` if an object is undefined. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | object | yes | The object to check | **Example:**
{%- 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.
If you use Visual Studio Code as your editor, you can use code snippets to speed up working with inserts. You can find the snippets in our Github repository: [https://github.com/Synerise/jinja-code-snippet](https://github.com/Synerise/jinja-code-snippet)
## abs Returns the absolute value of the argument. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | number | yes | The number to calculate the absolute value from | **Example:**
{% 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 |
The `|bool` filter uses **stricter rules** than implicit boolean conversion, which is used in comparisons (`==`, `!=`), `{% if %}` conditions, and the `is truthy` test. The two approaches can return different results for the same input value — see the [example below](#bool-conversion-example).
**`|bool` conversion rules:** | Input type | Returns `true` | Returns `false` | | :--- | :--- | :--- | | Boolean | `true` | `false` | | Integer | `1` | All other integers, including `0` | | Float | Never | Always, including `1.0` | | String | `"true"` or `"1"` | All other strings | | null | Never | Always | **Implicit conversion rules** (used in `==`, `!=`, `{% if %}`, `is truthy`): | 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 | #### Bool conversion example This example converts a string to a boolean using the `|bool` filter:
{%- 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 %}
For strict type-and-value equality without any boolean conversion, use the [`sameas` test](/developers/inserts/exptest#issameas). Unlike `|bool`, `sameas` checks that two values are identical objects without type coercion. For example, `"1" is sameas "true"` returns `false`, because `"1"` and `"true"` are different strings.
## capitalize Capitalizes a value. The first character will be uppercase, all others lowercase. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | The string where the first character will be capitalized | **Example:**
{% 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:**


<pre>
    {% set var = "string to center" %}

    {{ var|center(80) }}
</pre>
## count Returns the number of items in a sequence or mapping. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | value | yes | The sequence/mapping to count | **Example:**
{% set services = ['Web design', 'SEO', 'Inbound Marketing', 'PPC'] %}

{{ services|count }}
## 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 my_string = "Hello world." %}

{{ my_string|cut(' world') }}
## 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)
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.
**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:**
{% 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" #}
{{ 1721894790|timestamp_to_time|datetimeformat('%b %d, %Y; %H:%M') }}

{# outputs "Jul 25, 2024; 08:06" #}
### 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:**
// 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') }}
If you want to use default with variables that evaluate to false you have to set the second parameter to true.
{{ ''|default('the string was empty', true) }}
## 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.
{%- set contact = {
    'name': 'Alice',
    'email': 'alice@example.com',
    'phone': '123456789'
} -%}
{%- for item in contact|dictsort(false, 'value') -%}
    {{item}} </br>
{%- endfor -%}
Output:
email=alice@example.com
name=Alice
phone=123456789
## 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:**
{% set my_number = 106 %}

{{ my_number|divide(2) }}
## 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 num = 10 %}

{%- if num|divisible(2) -%}
    The number is divisible by 2
{%- endif -%}
## 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 escape_string = "<div>This markup is printed as text</div>" %}

{{ escape_string|escape }}
## 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 = "{{This markup is printed as text}}" %}

{{ escape_string|escape_jinjava }}
## 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 string can safely be inserted into JavaScript" %}

{{ escape_string|escapejs }}
## 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 = "String that contains JavaScript" %}

{{ escape_string|escapejson }}
## 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 bytes = 100000 %}

{{ bytes|filesizeformat }}
## first Returns the first item of a sequence. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | sequence | yes | The sequence to process | **Example:**
{% set my_sequence = ['Item 1', 'Item 2', 'Item 3'] %}

{{ my_sequence|first }}
## 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_text = "25.3" %}

{{ my_text|float }}
## forceescape Enforces HTML escaping.
This may double-escape variables.
**Input:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | The value to escape | **Example:**
{% set escape_string = "<div>This markup is printed as text</div>" %}

{{ escape_string|forceescape }}
## 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`.
{{ "Hi %s %s"|format("Hello", "World!") }}
## 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:**
{%- set y = '{"dataX":"b"}' -%}
{%- set deserialized = y|fromjson -%}
{{ deserialized }}
Output:
{dataX=b}
### 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:
// 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 }}
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 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>
Output:
<ul><li>
male
<ul><li>
    John
</li><li>
    Bob
</li></ul>
</li><li>
    female
    <ul><li>
        Jane
    </li><li>
        Alice
    </li></ul>
</li></ul>
## hash Returns the SHA-256 hash of a string.
{% set foo = "example@synerise.com"|hash("SHA-256") %}

{{ foo }}
{#  returns cab06d7019d42ed33dcb260dba8860f8028d243dd78184f3b5156d7bdae636dd  #}
## 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:**
<pre>
    {% set var = "string to indent" %}

    {{ var|indent(2, true) }}
</pre>
## 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.
{% set my_text = "23" %}

{{ my_text|int }}
## 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**
{{ "2023-01-19T09:15:40+03:00"|iso8601_to_time }}
{# returns the following object:
2023-01-19 09:15:40
#}
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|datetimeformat('%H:%M:%S','-01:00') }}
{# returns the string:
05: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:**
{%- set users = [
    {'username': 'john'},
    {'username': 'jane'},
    {'username': 'bob'}
] -%}

{{ users|join('|', attribute='username') }}
Output:
john|jane|bob
It is also possible to join certain attributes of an object:
{{ users|join('|', attribute='username') }}
## last Returns the last item of a sequence. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | sequence | yes | The sequence to process | **Example:**
{% set my_sequence = ['Item 1', 'Item 2', 'Item 3'] %}

{{ my_sequence|last }}
## length Returns the number of items in a sequence or mapping. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | sequence | yes | The sequence to process | **Example:**
{% set services = ['Web design', 'SEO', 'Inbound Marketing', 'PPC'] %}

{{ services|length }}
## 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 one = 1 %}
{% set two = 2 %}
{% set three = 3 %}
{% set list_num = one|list + two|list + three|list %}

{{ list_num|list }}
## lower Converts a value to lowercase. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | string | yes | The string to convert into lowercase | **Example:**
{{ "Text to MAKE Lowercase"|lower }}
## 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.
{%- set users = [
    {'username': 'john'},
    {'username': 'jane'},
    {'username': 'bob'}
] -%}
Users on this page: {{ users|map(attribute='username')|join(', ') }}
Output:
Users on this page: john, jane, bob
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.
{% set seq = ['item1', 'item2', 'item3'] %}

{{ seq|map('upper') }}
## md5 Calculates the MD5 hash of the given object. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | value | yes | Value for MD5 hash calculation | **Example:**
{% set content = {'absolute_url': 'https://example.com/page1'} %}
{{ content.absolute_url | md5 }}
Output:
d22158c78143eeca7fa617577d741866
## 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:**
{% set n = 20 %}

{{ n|multiply(3) }}
## prettyprint Pretty print a variable. Useful for debugging. **Input:** | Type | Required | Description | | :--- | :--- | :--- | | value | yes | Object to pretty print | **Example:**
{% set this_var = "Variable that I want to debug" %}

{{ this_var|pprint }}
## 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:
{% recommendations3 campaignId=CAMPAIGN_ID %}
    {% set randomItem = recommended_products3|random %}
    {{ randomItem.name }}
{% endrecommendations3 %}
## 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:**
{%- set some_numbers = [10, 12, 13, 3, 5, 17, 22] -%}

{{ some_numbers | reject('even') }}
Output:
[13, 3, 5, 17]
## 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.
{%- 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 -%}
Output:
Post 2
Post 3
## 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:**
{{ "Hello World"|replace("Hello", "Goodbye") }}
{{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
## 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:**
{% set nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] %}

{%- for num in nums|reverse -%}
    {{ num }}
{%- endfor -%}
## 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:**
Even if rounded to 0 precision, a float is returned. The fraction of that float is `.0`
{{ 42.55|round }}
{{ 42.55|round(1, 'floor') }}
If you need a real integer, pipe it through int.
{{ 42.55|round|int }}
## 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:**
{% set some_numbers = [10, 12, 13, 3, 5, 17, 22] %}

{{ some_numbers|select('even') }}
## 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 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 -%}
Output:
Post 1
## 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.
{%- for content in ['a','b','c','d','e']|shuffle -%}
    {{content}}
{%- endfor -%}
## 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 `