Braze integration
This guide walks you through connecting Braze to Better Email, exporting your campaigns to Braze as email templates, and optionally syncing custom attributes for merge tags and segmentation.
Before you start
To connect Braze, you will need:
- A Braze account with access to create REST API keys
- An admin user in Better Email who can create and edit integrations
1. Create a REST API key in Braze
- In Braze, go to Settings → API and Identifiers
- Select the API Keys tab
- Click Create API key
- Fill in the form:
- API key name:
Better Email integration - Allowlist IPs: Leave blank
- Permissions: Expand Email and Templates and select all permissions within each. If you want performance data available in Better Email, also expand User Data and select the relevant permissions.
- API key name:
- Click Create API key
2. Copy your credentials into Better Email
On the API key detail page, Braze shows both values you need:
- Next to REST Endpoint, click the copy icon and paste the value into the Instance URL field in Better Email
- Next to your API key, click the copy icon and paste the value into the API Key field in Better Email
Note: The Instance URL should be a hostname only — do not include
https://. If the copied value includes it, remove it before saving.
3. Save and enable the integration in Better Email
- Go to Integrations in Better Email
- Create a new integration or open an existing one
- Choose Braze as the type
- Paste in the Instance URL and API Key from the previous step
- Check Enabled
- Click Save
The integration is now active and ready to use.
4. Export to Braze
Once the integration is active, you can export campaigns directly to Braze from the export dialog.
- Better Email stores the Braze template ID after the first export
- Re-exporting the same campaign updates the existing template instead of creating a new one
- Merge tags and segmentation are rendered using Braze-compatible syntax
5. Optional: sync recipient fields from Braze
To use Braze custom attributes as merge tags and segmentation in Better Email:
- Open the Braze integration
- Check Sync recipient fields
- Click Save
- Go to Recipient Fields
- Click Sync from [integration name]
Better Email will read the available Braze custom attributes and map them into recipient fields.
6. Using Braze Liquid together with Better Email Liquid
Better Email and Braze both use Liquid, and they render in sequence: Better Email renders the campaign when you export it, and Braze renders the resulting template again for every recipient at send time.
So any Liquid meant for Braze has to survive Better Email's render. Wrap it in {% raw %}...{% endraw %} — Better Email outputs the contents as literal text, and Braze receives the tags intact:
{% raw %}{% catalog_items products 1234 %}{{ items[0].title }}{% endraw %}
Without the raw tags, Better Email evaluates the code itself: {{ items[0].title }} renders as empty, and {% catalog_items %} is not a tag Better Email knows, so the render fails with a Liquid error.
You do not need raw for merge tags. Recipient fields inserted in the Campaign Editor are already exported as {{custom_attribute.${…}}} — Better Email writes that syntax at export. raw is for Braze Liquid you write by hand in the template base or module code.
Injecting Better Email values into Braze Liquid
Nothing inside a raw block is evaluated, including your own settings. To put a Better Email value inside a Braze tag, close the block, output the value, and open a new one:
{% raw %}{% catalog_items products {% endraw %}{{ product_id }}{% raw %} %}{% endraw %}
If product_id is a module setting holding 1234, the exported template reads {% catalog_items products 1234 %} — a Braze tag with the marketer's item id baked in.
Limit it to Braze exports
If the same design system exports to more than one ESP, guard the Braze-specific branch on the integration:
{% if context.integration.type == "BrazeIntegration" %}
{% raw %}…Braze Liquid…{% endraw %}
{% endif %}
See the render context for the rest of what context exposes.
7. Example: a product recommendation module
Braze catalogs hold product data that Braze looks up at send time, and BrazeAI item recommendations decide which item each recipient should see. Combine that with context.isPreview and you get a module that shows a readable placeholder in the Campaign Editor and a per-recipient product in the delivered email — with nothing for the marketer to fill in.
Create the recommendation in Braze first, then reference it by name:
{% if context.isPreview %}
{% comment %} Placeholder so the marketer can see the layout {% endcomment %}
<table role="presentation" width="280" cellpadding="0" cellspacing="0" border="0" style="font-family: sans-serif;">
<tr>
<td height="180" style="background:#eeeeee; text-align:center; font-size:12px; color:#888888;">Recommended product image</td>
</tr>
<tr><td style="padding-top:12px; font-size:16px; font-weight:bold;">Recommended product name</td></tr>
<tr><td style="padding-top:4px; font-size:14px;">$0.00</td></tr>
<tr><td style="padding-top:12px; font-size:14px;"><a href="#">Shop now</a></td></tr>
</table>
{% else %}
{% raw %}
{% assign items = {{product_recommendation.${homepage_recs}}} %}
{% if items.size > 0 %}
{% assign product = items[0] %}
<table role="presentation" width="280" cellpadding="0" cellspacing="0" border="0" style="font-family: sans-serif;">
<tr>
<td>
<a href="{{ product.url }}"><img src="{{ product.image_url }}" width="280" alt="{{ product.title }}" style="display:block; width:100%; max-width:280px;" /></a>
</td>
</tr>
<tr><td style="padding-top:12px; font-size:16px; font-weight:bold;">{{ product.title }}</td></tr>
<tr><td style="padding-top:4px; font-size:14px;">{{ product.price }}</td></tr>
<tr><td style="padding-top:12px; font-size:14px;"><a href="{{ product.url }}">Shop now</a></td></tr>
</table>
{% endif %}
{% endraw %}
{% endif %}
What is doing what:
- The whole
elsebranch belongs to Braze, so one{% raw %}wrapper covers it — no seam needed. Note the{{ … }}nested inside{% assign %}: that is valid Braze Liquid, but Better Email cannot parse it, so therawwrapper is what makes it work at all. homepage_recsis the name of the recommendation you set up in Braze. Braze resolves it per recipient at send time, so the marketer never picks a product.title,price,image_url, andurlare column names in your Braze catalog. Use whatever your catalog actually defines.{% if items.size > 0 %}runs in Braze at send time, so a recipient with no recommendation gets nothing rather than a broken card. Add a fallback there if you want one.- The preview branch is all the marketer ever sees in the editor. Without it, they would be looking at raw Braze tags instead of a product card.
Other ways to choose the item
The rest of the module stays the same — only the line that produces items changes:
{% raw %}{% catalog_selection_items products best_sellers %}{% endraw %}— Braze filters the catalog per recipient using a selection you define on the catalog's columns.{% raw %}{% catalog_items products {{custom_attribute.${last_viewed_product_id}}} %}{% endraw %}— the item id comes from a custom attribute stored on the Braze user.{% raw %}{% catalog_items products {% endraw %}{{ product_id }}{% raw %} %}{% endraw %}— the marketer picks the product in a Better Email setting, injected through the seam from section 6.
Troubleshooting
| Symptom | Fix |
|---|---|
Failed to open TCP connection to https:443 | The Instance URL contains https:// — remove the protocol prefix and enter the hostname only |
Name or service not known | The Instance URL is incorrect — copy it again from the REST Endpoint field on your API key page in Braze |
| Export fails | Verify that the integration is enabled and that the API key has Email and Templates permissions |
| API key rejected | The key may have been deleted in Braze — create a new one and update the integration |