# Personalize Message Content

In-Browser Message campaigns support dynamic content personalization using **Profile Variables** and **Liquid template syntax**. Variables are resolved at runtime by RT Personalization 2.0 and rendered by the TD Web SDK before the message is displayed in the browser.

## Variable Sources

Profile variables available in In-Browser Messages come from four sources, all derived from the campaign's linked **Parent Segment**:

| **Source**  | **Prefix**  | **Description**  |
|  --- | --- | --- |
| Batch Attributes | `rt_profile.imported.*` | User profile attributes computed from batch processing and imported into RT 2.0 as External (EXT) attributes — loyalty tier, lifetime value, name, and similar. Accessed via `rt_profile.imported.*` in Liquid syntax (for example, `rt_profile.imported.loyalty_tier`). |
| RT Single Attributes | `rt_profile.single.*` | Scalar values updated in real time based on streaming events — most recent product viewed, current session data, and similar. |
| RT List Attributes | `rt_profile.list.*` | Array values updated in real time — cart items, browsing history, and similar. |
| RT Counter Attributes | `rt_profile.counter.*` | Numeric counters updated in real time — visit count, purchase count, and similar. |


Event fields are not yet supported
Referencing fields from the triggering event (for example, `product_id` from a page view) in Liquid template content is not supported.

## Basic Variable Output

Use double curly braces to output a variable value directly into content:

```html
<p>Welcome back, {{rt_profile.imported.first_name}}!</p>
<p>Your current tier: {{rt_profile.imported.loyalty_tier}}</p>
<p>Most recent product viewed: {{rt_profile.single.most_recent_product}}</p>
```

Variable output is HTML-escaped
All `{{ variable }}` output is automatically HTML-escaped by RT 2.0 before it is delivered to the browser. Characters such as `<`, `>`, `"`, and `&` in attribute values are escaped, so user-controlled fields do not produce XSS even though the Liquid `escape` filter is not supported.

## Liquid Template Syntax

In-Browser Messages support a **limited subset** of Liquid template syntax. Templates are translated by Realtime API into Reactor-compatible JavaScript expressions at configuration time, then evaluated at runtime on each personalization request.

### Supported Constructs

| **Construct**  | **Supported**  | **Notes**  |
|  --- | --- | --- |
| `{% if %} / {% elsif %} / {% else %} / {% endif %}` | ✅ | No nesting depth limit. |
| `{% for item in collection %} / {% endfor %}` | ✅ | Maximum 3 nesting levels overall. |
| `{{ variable }}` output | ✅ | Use `rt_profile.*` prefixes (for example, `rt_profile.imported.*`, `rt_profile.single.*`). |
| `==` , `!=` comparison | ✅ | String and null comparisons. |
| `and` / `or` logical operators | ✅ | Combining multiple conditions. |
| `{% assign %}` variable assignment | ❌ | Not supported. |
| `{{ value \| filter }}` filters | ❌ | `upcase`, `downcase`, `truncate`, etc. are not supported. |
| `{% unless %}` | ❌ | Use `{% if condition == false %}` as a workaround. |
| `{% case %} / {% when %}` | ❌ | Use chained `{% if %} / {% elsif %}` as a workaround. |
| `contains` operator | ❌ | Not supported in `{% if %}` conditions. |
| `forloop.index`, `limit`, `offset` | ❌ | Loop metadata and parameters are not supported. |


### Variable Syntax Reference

| **Liquid Syntax**  | **Attribute Type**  |
|  --- | --- |
| `{{rt_profile.imported.attribute_name}}` | Batch attribute (accessed via `rt_profile.imported.*` in In-Browser Messaging) |
| `{{rt_profile.single.attribute_id}}` | RT single attribute |
| `{{rt_profile.list.attribute_id.sub_attribute}}` | RT list attribute sub-field |
| `{{rt_profile.counter.attribute_id.total}}` | RT counter attribute total |


## Examples

### Conditional Content by Loyalty Tier

```html
{% if rt_profile.imported.tier == "gold" %}
  <p>20% off for Gold members!</p>
{% elsif rt_profile.imported.tier == "silver" %}
  <p>10% off for Silver members!</p>
{% else %}
  <p>Sign up today for exclusive deals!</p>
{% endif %}
```

### Loop Over Cart Items

```html
{% if rt_profile.list.cart_items.item_list != null %}
  <h2>Your Cart</h2>
  <ul>
    {% for item in rt_profile.list.cart_items.item_list %}
      <li>{{ item }}</li>
    {% endfor %}
  </ul>
{% endif %}
```

### Nested Conditional and Loop

```html
{% if rt_profile.single.most_recent_product %}
  <p>You recently viewed <strong>{{ rt_profile.single.most_recent_product }}</strong>.</p>
  {% if rt_profile.list.recommendations.product_ids != null %}
    <ul>
      {% for product in rt_profile.list.recommendations.product_ids %}
        {% if product != rt_profile.single.most_recent_product %}
          <li>{{ product }}</li>
        {% endif %}
      {% endfor %}
    </ul>
  {% endif %}
{% endif %}
```

## Limitations

- **Unsupported Liquid filters**: String manipulation filters (`upcase`, `downcase`, `replace`, `truncate`, `split`, `join`, `date`, etc.) are not available. Pre-process values as batch attributes if transformation is needed.
- **No variable assignment**: `{% assign %}` is not supported. Use the attribute system in Audience Studio to derive computed values.
- **For loop nesting**: `{% for %}` loops support a maximum nesting depth of 3 levels.
- **No `{% unless %}`**: Use `{% if condition == false %}` instead.