Jinja in SnapApp
on 02-05-2026 12:00 AM by SnapApp by BlueVector AI
1135
Jinja is a template engine for Python that helps you generate dynamic content inside HTML pages.
Instead of hard-coding values like names, addresses, or IDs, Jinja allows you to insert live data directly into your pages.
In SnapApp, Jinja is used to: - Display dynamic values from objects and records - Add conditions and loops inside pages - Reuse logic using functions and macros - Build flexible and reusable page layouts
This document explains Jinja step by step, starting from the basics and gradually moving to advanced features.
No prior Jinja experience is required.
For full syntax reference, you can also visit the official
Jinja Documentation.
Table of Contents
Delimiters in Jinja
Delimiters tell Jinja what should be processed as logic and what should be printed as output.
Anything outside these delimiters is treated as normal text or HTML.
| Delimiter | What it does | Example |
|---|---|---|
{{ ... }} |
Prints a value to the page | {{ customer['full_name'] }} |
{% ... %} |
Executes logic (no direct output) | {% set x = 42 %} |
{# ... #} |
Adds comments (not shown on page) | {# This is a comment #} |
Think of it this way:
- {{ }} → Show something
- {% %} → Do something
- {# #} → Explain something
Variables in Jinja
Variables are used to store values that can be reused later in the template.
You do not need to define a data type—Jinja automatically understands it.
{% set totalOrders = 150 %}
{{ totalOrders }}
Output: 150
Variables can also be conditionally defined, enabling more tailored content:
{% set displayName = user.first_name | title if user.first_name else "SnapApp Invalid User" %}
This Means :
-
IF
user.first_nameexists → Displayuser.first_namein Title Case -
ELSE → Display a default message
Variable data types
Jinja supports a wide range of data types that are commonly used in modern web applications.
Understanding these data types helps you work confidently with variables, apply conditions correctly, and avoid runtime errors while building SnapApp templates.
Each variable in Jinja automatically assumes a data type based on the value assigned to it—there is no need for explicit type declarations.
| Data Type | What does it represent | Example Values |
|---|---|---|
| None | Represents the absence of any value. Often used when data is missing or undefined. | none or None |
| Integer | Represents whole numbers without decimal points. | 100, 54, 3021 |
| Float | Represents numbers that contain decimal values. | 12.34, 3.75, 42.5, 3.1415, 15.0 |
| String | Represents text or a sequence of characters. | “status”, “SnapappUser”, “SnapApp is Cool” |
| Boolean | Represents logical true or false values. | true or True, false or False |
| List | A mutable, ordered collection of elements enclosed in [ ]. Lists can contain mixed data types. |
[1, ‘string’, [ [ ], [ ] ], { 1: ‘a’ }, none ] |
| Tuple | An immutable, ordered collection of elements enclosed in ( ). Once created, tuples cannot be modified. |
(1, ‘string’, [ [ ], [ ] ], { 1: ‘a’ }, none ) |
| Dictionary | A collection of key-value pairs enclosed in { }. Keys are unique, and values can be any data type. |
{ ‘name’: ‘John’, ‘role’: ‘Admin’ } |
Jinja allows conditional logic to be embedded directly within templates.
This enables dynamic content rendering based on the current state of variables, such as status values, user data, or configuration settings.
{% if project.status == 'pending' %}
{{ "Project is pending." }}
{% elif project.status == 'deal qualified' %}
{{ "Order has qualified the deal." }}
{% else %}
{{ "Order is complete." }}
{% endif %}
In this example:
-
The
ifcondition checks whetheruser.first_nameexists. -
The
elseblock provides a fallback message whenuser.first_nameis not available. -
Only one block is rendered based on whether the condition evaluates to true.
Expressions
Expressions in Jinja allow you to perform calculations, compare values, and manipulate data directly inside templates.
They follow familiar Python-style syntax, making them easy to read and use, even for beginners.
Expressions are commonly used to: - Make decisions (for example, checking a status or condition) - Perform simple math - Combine or evaluate values dynamically - Control what content is rendered in SnapApp templates
a. Math Operators
Math operators are used to perform basic arithmetic operations on numeric values.
- `+` _Addition_
Adds two values together.
- `-` _Subtraction_
Subtracts one value from another.
- `*` _Multiplication_
Multiplies two values.
- `/` _Division_
Divides one value by another and returns a decimal result.
- `//` _Integer division, rounding down._
Divides two values and returns only the whole number part.
Example: `20 // 7` returns `2`.
- `%` _Modulus (remainder of division)._
Returns the remainder after division.
Example: `11 % 7` returns `4`.
b. Comparison Operators
Comparison operators are used to **compare two values** and return a boolean result (`true` or `false`).
- `==` Checks if two values are equal.
- `!=` Checks if two values are not equal.
- `>` Checks if the left value is greater than the right value.
- `>=` Checks if the left value is greater than or equal to the right value.
- `<` Checks if the left value is less than the right value.
- `<=` Checks if the left value is less than or equal to the right value.
c. Logical Operators
Logical operators are used to **combine multiple conditions** or reverse a condition’s result.
- `and`
Returns `true` only if **both** conditions are true.
- `or`
Returns `true` if **at least one** condition is true.
- `not`
Reverses the result of a condition.
d. Other Operators
-
in: Theinoperator checks whether a value exists inside a sequence, such as a list, tuple, or dictionary.
When used with dictionaries, it evaluates against the keys.Jinja {{ 'status' in order }} {# Checks if 'status' key exists in the order dictionary #} -
is: Theisoperator is used to apply tests to a variable.
These tests help validate data by checking conditions such as:- Whether a variable is defined
- Whether it matches a specific data type
- Whether it satisfies a particular rule
Jinja {{ order.total is number }} {# Checks if the total is a number #} -
~:
The~operator (read as tilde) is used to concatenate values into a single string.Before concatenation: - All operands are automatically converted to strings. - This allows numbers, variables, and text to be safely joined together.
Jinja
{{ 'Total: ' ~ order.total }} {# Produces "Total: 500" if order.total is 500 #}
Jinja Data Structures
In SnapApp, Jinja offers several core data structures that allow for flexible and dynamic template creation. Lists, tuples, and dictionaries are key elements, enabling the manipulation and organization of data for rendering dynamic content efficiently.
- Lists : A list is a mutable, ordered collection of items that can hold diverse data types without requiring prior declaration. Lists in Jinja are ideal for managing sequences of objects or values, allowing for flexible additions, removals, and retrieval of data.
##### How to initialize and access items in a list?
To define a list in Jinja, use the following syntax:
jinja
{% set sampleList = [10, 20, 30, 40, 50] %}
This creates a list containing the numbers 10 through 50. An empty list can be initialized as:
Jinja
{% set emptyList = [] %}
Lists are indexed, meaning each item in the list can be accessed by its position. The first element in any list is always at index 0, the second at index 1, and so on. For instance, in the list below:
Jinja
{% set alphaList = ['X', 'Y', 'Z', 'A'] %}
Xis at index 0,Ais at index 3.
To retrieve an item, use the index:
Jinja
{{ alphaList[2] }} {# Returns 'Z' #}
##### Adding and removing items from a list
Lists in Jinja allow for dynamic changes, such as appending or removing elements.
Appending Elements: To add an item to an existing list, use the append method.
Jinja
{% set myList = [2, 4, 6] %}
{% append 8 to myList %}
This adds 8 to the end of myList, resulting in [2, 4, 6, 8].
Removing Elements: Use the pop() method to remove elements from a list. The method can be used with or without an index.
Jinja
{% set temp = myList.pop(1) %} {# Removes the second item in the list #}
Example:
Jinja
{% set myList = [100, 200, 300, 400] %}
{% set temp = myList.pop(2) %} {# Removes 300 from the list #}
{{ myList }} {# Outputs [100, 200, 400] #}
To find an element’s index, use the index() function:
Jinja
{% set myIndex = myList.index(400) %}
- Tuples : Tuples, similar to lists, are ordered collections but are immutable—once created, they cannot be changed. Tuples are often used for fixed data that should remain constant throughout template rendering.
##### How to create and access Tuples
To define a tuple:
Jinja
{% set sampleTuple = ('SnapApp', 'is', 'Cool') %}
Elements within a tuple can be accessed via their index, just like lists:
Jinja
{{ sampleTuple[1] }} {# Returns 'is' #}
A tuple with a single element requires a trailing comma:
Jinja
{% set singleItemTuple = ('SnapApp',) %}
Example:
Jinja
{% set pageData = [] %}
{% append ('home.html', 'Home Page') to pageData %}
{% append ('about.html', 'About SnapApp') to pageData %}
{{ pageData[1][1] }} {# Outputs 'About SnapApp' #}
- Dictionaries : Dictionaries are collections of key-value pairs, where each key is unique and mapped to a corresponding value. In SnapApp, dictionaries are particularly useful for storing structured data such as customer information, settings, or configuration parameters.
##### How to define and access Dictionaries?
To create a dictionary:
jinja
{% set customerInfo = {"Name": "Alex", "Role": "Administrator"} %}
Access values by referencing their keys:
Jinja
{{ customerInfo["Name"] }} {# Outputs 'Alex' #}
Keys in dictionaries can be strings, numbers, or None. Values can be any data type, including other dictionaries, lists, or tuples.
Jinja
{% set productDetails = {"Product": "Laptop", "Price": 1500, "Stock": 30} %}
{{ productDetails["Product"] }} {# Returns 'Laptop' #}
Jinja Filters
In SnapApp, filters are a powerful tool that can be used to modify data output dynamically within templates. Filters are applied to variables, allowing content transformations without modifying the original data source.
- Filter Syntax: Filters are applied by using the pipe (|) symbol, followed by the name of the filter. The filter modifies the variable it is applied to. For instance, to convert a customer’s name to uppercase:
{{ customer["name"] | upper }}
This will convert the customer’s name to uppercase. The pipe symbol is an intuitive way to express “apply this filter to the variable.”
Filters that require additional parameters take arguments within parentheses, as demonstrated below:
{{ "product" | replace('p', 'b') }}
This replaces all occurrences of ‘p’ with ‘b’, resulting in the output broduct.
- Chaining Filters : Multiple filters can be applied to a variable in sequence. Filters are evaluated left to right, provided that the output of one filter is a valid input for the next.
Example
{{ "apple" | upper | replace('P', 'b') }}
Output: AbbLE
{{ "apple" | replace('p', 'b') | upper }}
Output: ABBLE
Global Variables in Jinja
Jinja provides a set of global variables that are automatically available within SnapApp campaigns and projects.
These variables allow you to personalize content dynamically by accessing IDs, names, and related metadata for different entities.
- Project Level
Project-level variables provide information about the current project.
{{ project['id'] }}
Returns the unique identifier of the project.-
{{ project['name'] }}
Returns the name of the project. -
Scenario / Email Campaign
These variables reference the scenario or email campaign in which the template is being used.
{{ scenario['id'] }}
Fetches the unique ID of the scenario or email campaign.-
{{ scenario['name'] }}
Retrieves the name of the scenario or email campaign. -
Scenario Node
Scenario node variables represent the individual action nodes inside a scenario.
{{ action['id'] }}
Gets the unique ID of the action node.-
{{ action['name'] }}
Returns the name of the action node or email campaign. -
Banner
Banner variables provide details about banners and their variants.
{{ banner['id'] }}
Returns the banner ID.{{ banner['name'] }}
Provides the banner name.{{ banner['variant']['id'] }}
Retrieves the ID of the banner variant.-
{{ banner['variant']['name'] }}
Returns the name of the banner variant. -
Experiments
Experiment variables allow access to experiment and variant details.
{{ experiment['id'] }}
Fetches the ID of the experiment.{{ experiment['name'] }}
Returns the name of the experiment.{{ experiment['variant']['id'] }}
Retrieves the variant ID of the experiment.-
{{ experiment['variant']['name'] }}
Provides the name of the experiment variant. -
Tag Manager
Tag-related variables are used to reference tags applied within SnapApp.
{{ tag['id'] }}
Returns the tag ID.{{ tag['name'] }}
Retrieves the name of the tag.
Technical Expressions
The following expressions are more advanced or technical and are typically used in specific scenarios such as formatting timestamps, generating URLs, or creating secure random values.
These expressions are especially useful when working with APIs, public resources, or security-related data in SnapApp templates.
-
sent_timestamp | from_timestamp
Converts a Unix timestamp into a human-readable date and time format. -
api_base_url
Returns the base URL for an API endpoint, useful when constructing API requests dynamically. -
public_base_url
Returns the base URL for public-facing app resources, such as externally accessible pages or assets. -
random_bytes(length) | hexencode
Generates a random byte string of the specified length and encodes it in hexadecimal format.
Commonly used for generating secure tokens or identifiers. -
random_bytes(length) | b64encode
Generates a random byte string of the specified length and encodes it in Base64 format.
Functions on Data Types
Jinja exposes many built-in functions that can be applied to different data types.
These functions allow you to inspect, transform, and manipulate values directly inside templates.
The table below lists commonly available functions, grouped by data type.
| Data Type | Function | Description |
|---|---|---|
| Integer | int.bit_length() |
Returns the number of bits required to represent the integer in binary, excluding the sign and leading zeros. |
| Integer | int.conjugate() |
Returns the conjugate of the number. Since complex numbers are not supported, this returns the integer itself. |
| Float | float.as_integer_ratio() |
Returns a tuple of two integers whose ratio exactly represents the float value. |
| Float | float.is_integer() |
Returns True if the float represents an integer value, otherwise False. |
| Float | float.hex() |
Returns a hexadecimal string representation of the floating-point number. |
| Float | float.fromhex(string) |
Converts a hexadecimal string into a floating-point number. |
| Float | float.conjugate() |
Returns the conjugate of the float. Since complex numbers are not supported, the value remains unchanged. |
| String | str.capitalize() |
Returns a copy of the string with the first character capitalized and the rest in lowercase. |
| String | str.center(width[, fillchar]) |
Centers the string within the specified width, padding with the given character if needed. |
| String | str.count(sub[, start[, end]]) |
Counts the number of non-overlapping occurrences of a substring. |
| String | str.encode(encoding="utf-8", errors="strict") |
Encodes the string into bytes using the specified encoding. |
| String | str.endswith(suffix[, start[, end]]) |
Returns True if the string ends with the specified suffix. |
| String | str.expandtabs(tabsize=8) |
Replaces tab characters with spaces based on the given tab size. |
| String | str.find(sub[, start[, end]]) |
Returns the lowest index of the substring, or -1 if not found. |
| String | str.index(sub[, start[, end]]) |
Similar to find, but raises an error if the substring is not found. |
| String | str.isalnum() |
Returns True if all characters are alphanumeric. |
| String | str.isalpha() |
Returns True if all characters are alphabetic. |
| String | str.isdigit() |
Returns True if all characters are digits. |
| String | str.islower() |
Returns True if all cased characters are lowercase. |
| String | str.isspace() |
Returns True if the string contains only whitespace characters. |
| String | str.istitle() |
Returns True if the string follows title-case formatting. |
| String | str.isupper() |
Returns True if all cased characters are uppercase. |
| String | str.join(iterable) |
Joins elements of an iterable into a single string using the string as a separator. |
| String | str.ljust(width[, fillchar]) |
Left-justifies the string, padding it to the specified width. |
| String | str.lower() |
Converts all cased characters to lowercase. |
| String | str.lstrip([chars]) |
Removes leading characters from the string. |
| String | str.partition(sep) |
Splits the string at the first occurrence of the separator and returns a tuple. |
| String | str.replace(old, new[, count]) |
Replaces occurrences of a substring with another substring. |
| String | str.rfind(sub[, start[, end]]) |
Returns the highest index of the substring, or -1 if not found. |
| String | str.rindex(sub[, start[, end]]) |
Like rfind, but raises an error if the substring is not found. |
| String | str.rjust(width[, fillchar]) |
Right-justifies the string within the specified width. |
| String | str.rpartition(sep) |
Splits the string at the last occurrence of the separator. |
| String | str.rstrip([chars]) |
Removes trailing characters from the string. |
| String | str.split(sep=None, maxsplit=-1) |
Splits the string into a list using the specified separator. |
| String | str.splitlines() |
Splits the string at line boundaries into a list. |
| String | str.startswith(prefix[, start[, end]]) |
Returns True if the string starts with the specified prefix. |
| String | str.strip([chars]) |
Removes both leading and trailing characters from the string. |
| String | str.swapcase() |
Converts uppercase characters to lowercase and vice versa. |
| String | str.title() |
Converts the string to title case. |
| String | str.translate(table) |
Maps characters in the string using a translation table. |
| String | str.upper() |
Converts all cased characters to uppercase. |
| String | str.zfill(width) |
Pads the string on the left with zeros until it reaches the specified width. |
| List | list.count(item) |
Returns the number of occurrences of an item in the list. |
| List | list.index(item[, start[, end]]) |
Returns the index of the first matching item in the list. |
| List | list.pop([index]) |
Removes and returns the item at the given index. |
| Tuple | tuple.count(item) |
Returns the number of occurrences of an item in the tuple. |
| Tuple | tuple.index(item[, start[, end]]) |
Returns the index of the first matching item in the tuple. |
| Dictionary | dict.fromkeys(seq[, value]) |
Creates a new dictionary with keys from a sequence and a shared value. |
| Dictionary | dict.get(key[, default]) |
Returns the value for a key, or a default if the key is missing. |
| Dictionary | dict.items() |
Returns a list of (key, value) pairs from the dictionary. |
Jinja Blocks
Jinja code blocks use the syntax {% blocktype %} ... {% endblocktype %}.
They help organize template logic by grouping conditions, loops, and variable assignments into clear, readable sections.
While Jinja supports multiple block types, template importing is not currently implemented in SnapApp, which makes inheritance-based blocks less useful.
Block Types
- Set / If Blocks
The if block enables conditional rendering based on boolean expressions.
It supports elif (else-if) and else clauses for additional conditions and fallback behavior.
Every if block must end with {% endif %}.
jinja
{# If block number one #}
{% if 1 < 1 %}
One is less than one.
{% elif 1 < 2 %}
One is less than two
{% else %}
one is greater or equal to two
{% endif %}
Output: one is less than two
Because the first condition fails, the second one gets evaluated. It evaluates to true, hence the statements following it gets rendered.
OR
Using an inline conditional expression is useful for compact logic.
jinja
{% set x = 'Project' if 13 is even else 'Task' %}
{{ x }}
Output:
Task
- For Blocks
The for block is used to iterate over items in an iterable (such as lists).
It starts with {% for item in iterable %} and ends with {% endfor %}.
An optional {% else %} block is executed if the iterable is empty.
jinja
{% for x in [] %}
{{ 'Field' }}
{%- else %}
{{ 'Object' }}
{% endfor %}
Output:
Object
jinja
{% for x in [1, 2] %}
{{ x }}
{% else %}
{{ 'Object' }}
{% endfor %}
Output:
1
2
- Recursive For Loop
Jinja supports recursive loops using the recursive flag.
This is useful when working with nested lists or hierarchical data structures.
The loop() function allows the loop to call itself for nested elements.
jinja
{% set x = [11, [21, 22], [[23]]] %}
{% for item in x recursive %}
{% if item is iterable %}
{{ loop(item) }}
{% else %}
{{ item ~ ' says hello from depth: ' ~ loop.depth }}
{% endif %}
{% endfor %}
Output:
11 says hello from depth: 1
21 says hello from depth: 2
22 says hello from depth: 2
23 says hello from depth: 3
- For Loop Filtering
Filters can be applied directly in a for loop.
When using filters with recursion, the recursive keyword must be placed at the end of the loop statement.
jinja
{% for item in ['hello', [42], 13, 'world'] if (item is not string) recursive %}
{{ loop(item) if item is iterable else item ~ ', depth: ' ~ loop.depth }}
{% endfor %}
Output:
42, depth: 2
13, depth: 1
- For Loop Variables
Inside a for loop, a special variable named loop is available.
It provides useful metadata about the current iteration.
| Property | Type | Description |
|---|---|---|
| loop.first | Boolean | True if this is the first iteration |
| loop.last | Boolean | True if this is the last iteration |
| loop.length | Integer | Total number of iterations |
| loop.depth | Integer | Current depth in a recursive loop (starts at 1) |
| loop.depth0 | Integer | Current depth in a recursive loop (starts at 0) |
| loop.index | Integer | Current iteration index starting from 1 |
| loop.index0 | Integer | Current iteration index starting from 0 |
| loop.revindex | Integer | Reverse index starting from 1 |
| loop.revindex0 | Integer | Reverse index starting from 0 |
| loop.cycle(arg1, arg2, …) | Function | Cycles through provided arguments based on the current iteration |
loop.cycle()Helper Function
The loop.cycle() function returns items from a sequence based on the iteration count.
jinja
{% for item in range(3) %}
{{ loop.cycle('hello', 'SnapApp') }}
{{ loop.cycle('hello', 'SnapApp') }}
{% endfor %}
Output:
hello
hello
SnapApp
SnapApp
hello
hello
Macros
Macros in Jinja serve as callable code blocks, analogous to functions. They enhance code clarity and efficiency by encapsulating reusable logic.
Macros are defined using the syntax {% macro macroName(args) %} … {% endmacro %}. Parameters, referred to as arguments, are passed to the macro during invocation. This enables customization and flexibility in macro execution.
{% macro printMood(day, mood='happy') %}
{{ (day | title) ~ ', Weather feels ' ~ mood ~ '!' }}
{% endmacro %}
...
{% set currMood = 'amazing' %}
{% set currDay = 'today' %}
{{ printMood(currDay, currMood) }}
Output:
Today, Weather feels amazing!
Call
The call block, closely related to macros, provides a mechanism for passing content directly to a macro. When a call block is used within a macro invocation, its content is wrapped as a macro and assigned to the ‘caller’ argument. This allows for dynamic content injection and customization within macros.
To access the passed content within the macro, the caller() function is used. This enables the macro to incorporate the provided content into its execution logic, creating more flexible and adaptable templates.
{# This one throws error because argument caller was not declared #}
{% macro errorMacro(arg1) %}
{{ errorMacro.name ~ "'s arg1 is " ~ arg1 }}
{% endmacro %}
...
{% call errorMacro() %}
This is the content of the call block.
{% callend %}
{# This one works because argument caller was declared #}
{% macro workingMacro(arg1='', caller='') %}
{{ workingMacro.name ~ "'s args are " ~ arg1 ~ ' and "' ~ caller() ~ '"' }}
{% endmacro %}
...
{% call workingMacro() %}
This is the content of the call block.
{% endcall %}
Output:
workingMacro's args are and "
This is the content of the call block."
Raw
The raw block treats its content as literal strings, preventing Jinja syntax evaluation. This is particularly useful when you need to display actual Jinja syntax within the template output.
{% raw %}
{% set x = 5 %}
{% endraw %}
Output:
"{% set x = 5 %}"
Jinja in SnapApp
In SnapApp, Jinja templating can be used directly within the Page Builder to render dynamic data. This allows you to combine static content with dynamic values fetched from objects, records, or functions at runtime.
To access the Page Builder and learn more about its usage, refer to the documentation
SnapApp Pages
Using Jinja in Page Builder
Below is an example of Jinja code written inside the Page Builder to dynamically display values such as name and address from an object.

In this example: - Jinja expressions are used to reference object fields - Dynamic values are injected into the page at render time - Static text and dynamic data coexist seamlessly
Rendered Output in Page
The following image shows how the page appears after rendering. The name and address fields are populated dynamically from the object for a specific record ID, while other content remains static.

This demonstrates how Jinja enables: - Dynamic field rendering - Record-specific data display - Clean separation between template logic and data
Pre-conditions
- The record must exist in the object
- The Page must receive a valid record ID
- Field names used in Jinja must match the object schema
If these conditions are not met, the dynamic values will not render correctly.
SnapApp Functions in Jinja
In addition to basic Jinja expressions, SnapApp Functions can also be invoked within Jinja templates in the Page Builder. These functions allow you to execute queries, fetch datasets, and perform custom logic.
To learn how to create SnapApp Functions, see the documentation
SnapApp Functions and Custom Expressions
Example: Using a SnapApp Function
The following example demonstrates a SnapApp Function that retrieves all records from the CONTACTS table.

Once defined, this function can be called inside a Jinja template and its results can be iterated over using a for loop.
Rendering Function Results in Page Builder
The image below shows how the data returned by the SnapApp Function is rendered on the page by iterating over the result set using Jinja.

This approach enables: - Dynamic list rendering - Database-driven page content - Clean integration of backend logic with frontend templates
Summary
- Jinja can be used in SnapApp Page Builder for dynamic rendering
- Object fields can be accessed directly in templates
- SnapApp Functions can be invoked inside Jinja
- Returned datasets can be iterated using
forloops - This combination allows highly dynamic, data-driven pages in SnapApp
Thank you for following these steps to configure your SnapApp components effectively If you have any questions or need further assistance, please don’t hesitate to reach out to our support team. We’re here to help you make the most out of your SnapApp experience.
For support, email us at snapapp@bluevector.ai