Use Liquid in Beefree SDK for Email Personalization
This recipe explains how you can use Liquid in Beefree SDK to support advanced email personalization options for your end users.
This tutorial uses Display Conditions, Content Dialog, and Merge Tags. Display Conditions requires a Core plan or above.
Copy this pre-built prompt to get started faster with AI
# **Beefree SDK + Liquid Templating Integration Guide**
**Purpose:** Demonstrate how to integrate **Liquid templating** with **Beefree SDK** to create advanced email personalization features in React applications.
**Scope:** This guide covers merge tags, display conditions, custom content dialogs, and dynamic content loading for personalized email campaigns.
---
## **1. Project Overview**
This project showcases a complete integration of Beefree SDK with Liquid templating for email personalization, featuring:
- **React-based Beefree SDK integration** using `@beefree.io/sdk`
- **Liquid templating** for dynamic content and personalization
- **Custom content dialogs** for managing display conditions and external content
- **Merge tags** for drag-and-drop personalization fields
- **External content loading** for pre-built row templates
- **Secure proxy server** for authentication
---
## **2. Core Components**
### **2.1 Beefree SDK Configuration with Liquid Features**
```javascript
const beeConfig = {
container: 'beefree-sdk-container',
language: 'en-US',
enabledAdvancedPreview: true,
trackChanges: true,
// Liquid personalization features
mergeTags: [
{ name: 'Customer Name', value: '{{ customer.name }}' },
{ name: 'Customer Email', value: '{{ customer.email }}' },
{ name: 'Order Total', value: '{{ order.total }}' },
{ name: 'Product Name', value: '{{ product.name }}' },
{ name: 'Product Price', value: '{{ product.price }}' },
{ name: 'Store Name', value: '{{ shop.name }}' }
],
// Custom content dialog for Liquid features
contentDialog: {
rowDisplayConditions: {
title: 'Display Conditions',
description: 'Set conditions for when this row should be displayed',
handler: (data, callback) => {
// Custom modal for Liquid conditional logic
showDisplayConditionsModal(data, callback);
}
},
externalContentURLs: {
title: 'Pre-built Rows',
description: 'Load pre-built row templates with Liquid personalization',
handler: (data, callback) => {
// Custom modal for external content selection
showExternalContentModal(data, callback);
}
}
},
// Rows configuration for Liquid templates
rowsConfiguration: {
emptyRows: true,
defaultRows: true,
selectedRowType: 'default',
externalContentURLs: 'https://qa-bee-playground-backend.getbee.io/api/customrows/?ids=1,2,3,4'
},
// Event handlers
onChange: (pageJson) => {
console.log('Content changed:', pageJson);
},
onRemoteChange: (pageJson) => {
console.log('Remote change:', pageJson);
},
onViewChange: (view) => {
console.log('View changed:', view);
},
onError: (error) => {
console.error('Beefree SDK error:', error);
}
};
```
### **2.2 Liquid Templating Examples**
#### **Basic Merge Tags**
```liquid
Hello {{ customer.name }},
Thank you for your order of {{ order.total }}.
Your items will be shipped from {{ shop.name }}.
```
#### **Conditional Display Logic**
```liquid
{% if customer.total_spent > 100 %}
<div class="vip-section">
<h2>VIP Customer Benefits</h2>
<p>You've earned {{ customer.reward_points }} reward points!</p>
</div>
{% endif %}
```
#### **Product Loops**
```liquid
{% for product in products %}
<div class="product-item">
<img src="{{ product.image }}" alt="{{ product.name }}">
<h3>{{ product.name }}</h3>
<p class="price">{{ product.price }}</p>
{% if product.on_sale %}
<span class="sale-badge">SALE!</span>
{% endif %}
</div>
{% endfor %}
```
---
## **3. Custom Content Dialogs**
### **3.1 Display Conditions Modal**
```javascript
const showDisplayConditionsModal = (data, callback) => {
const modal = document.createElement('div');
modal.className = 'liquid-modal';
modal.innerHTML = `
<div class="modal-content">
<div class="modal-header">
<h3>Display Conditions</h3>
<button class="close-btn" onclick="this.parentElement.parentElement.parentElement.remove()">×</button>
</div>
<div class="modal-body">
<p>Set Liquid conditions for when this row should be displayed:</p>
<textarea
id="liquid-condition"
placeholder="{% if customer.total_spent > 100 %}...{% endif %}"
style="width: 100%; height: 100px; font-family: monospace;"
>${data.condition || ''}</textarea>
<div class="button-group">
<button class="btn btn-primary" onclick="applyCondition()">Apply Condition</button>
<button class="btn btn-secondary" onclick="this.parentElement.parentElement.parentElement.remove()">Cancel</button>
</div>
</div>
</div>
`;
document.body.appendChild(modal);
window.applyCondition = () => {
const condition = document.getElementById('liquid-condition').value;
callback({ condition });
modal.remove();
};
};
```
### **3.2 External Content Modal**
```javascript
const showExternalContentModal = (data, callback) => {
const modal = document.createElement('div');
modal.className = 'liquid-modal';
modal.innerHTML = `
<div class="modal-content">
<div class="modal-header">
<h3>Pre-built Rows</h3>
<button class="close-btn" onclick="this.parentElement.parentElement.parentElement.remove()">×</button>
</div>
<div class="modal-body">
<p>Select pre-built row templates with Liquid personalization:</p>
<div class="row-grid">
<div class="row-item" onclick="selectRow('product-showcase')">
<h4>Product Showcase</h4>
<p>Dynamic product display with Liquid loops</p>
</div>
<div class="row-item" onclick="selectRow('customer-greeting')">
<h4>Customer Greeting</h4>
<p>Personalized welcome message</p>
</div>
<div class="row-item" onclick="selectRow('order-summary')">
<h4>Order Summary</h4>
<p>Order details with conditional logic</p>
</div>
</div>
</div>
</div>
`;
document.body.appendChild(modal);
window.selectRow = (rowType) => {
callback({ rowType });
modal.remove();
};
};
```
---
## **4. Advanced Liquid Features**
### **4.1 Dynamic Content Loading**
```javascript
// Load external content with Liquid variables
const loadExternalContent = async (contentId) => {
try {
const response = await fetch(`/api/content/${contentId}`);
const content = await response.json();
// Process Liquid variables in the content
const processedContent = processLiquidVariables(content, {
customer: { name: 'John Doe', email: '[email protected]' },
shop: { name: 'My Store' },
products: [
{ name: 'Product 1', price: '$29.99', on_sale: true },
{ name: 'Product 2', price: '$49.99', on_sale: false }
]
});
return processedContent;
} catch (error) {
console.error('Error loading external content:', error);
}
};
```
### **4.2 Liquid Variable Processing**
```javascript
const processLiquidVariables = (content, variables) => {
let processed = content;
// Replace simple variables
Object.keys(variables).forEach(key => {
if (typeof variables[key] === 'string' || typeof variables[key] === 'number') {
processed = processed.replace(new RegExp(`{{ ${key} }}`, 'g'), variables[key]);
}
});
// Handle nested objects
Object.keys(variables).forEach(key => {
if (typeof variables[key] === 'object' && !Array.isArray(variables[key])) {
Object.keys(variables[key]).forEach(subKey => {
processed = processed.replace(
new RegExp(`{{ ${key}.${subKey} }}`, 'g'),
variables[key][subKey]
);
});
}
});
return processed;
};
```
---
## **5. Implementation Steps**
### **5.1 Setup Requirements**
1. **Install dependencies:**
```bash
npm install @beefree.io/sdk react react-dom
```
2. **Create `.env` file:**
```
BEE_CLIENT_ID=your_client_id
BEE_CLIENT_SECRET=your_client_secret
```
3. **Setup proxy server** for secure authentication
### **5.2 React Component Structure**
```javascript
import { useEffect, useRef, useState } from 'react';
import BeefreeSDK from '@beefree.io/sdk';
export default function BeefreeLiquidEditor() {
const containerRef = useRef(null);
const [beeInstance, setBeeInstance] = useState(null);
const [sdkLoaded, setSdkLoaded] = useState(false);
useEffect(() => {
initializeEditor();
}, []);
const initializeEditor = async () => {
try {
// Get authentication token
const response = await fetch('/proxy/bee-auth', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ uid: 'demo-user' })
});
const { token } = await response.json();
// Initialize Beefree SDK
const bee = new BeefreeSDK(token);
const instance = await bee.start(beeConfig, {});
setBeeInstance(instance);
setSdkLoaded(true);
} catch (error) {
console.error('Initialization error:', error);
}
};
return (
<div>
<div
id="beefree-sdk-container"
ref={containerRef}
style={{
width: '90%',
height: '700px',
margin: '0 auto',
background: '#ffffff'
}}
>
<div style={{ padding: '20px', color: '#000' }}>
{sdkLoaded ? 'Beefree SDK loaded!' : 'Loading Beefree SDK...'}
</div>
</div>
<button onClick={() => beeInstance?.loadRows()}>
Load External Rows
</button>
</div>
);
}
```
---
## **6. Best Practices**
### **6.1 Liquid Syntax Guidelines**
- **Use descriptive variable names:** `{{ customer.first_name }}` instead of `{{ name }}`
- **Implement proper conditionals:** Always include `{% endif %}` and `{% endfor %}`
- **Handle edge cases:** Use `{% if customer.name %}` to check for existence
- **Optimize loops:** Limit product loops to reasonable numbers
### **6.2 Security Considerations**
- **Never expose sensitive data** in Liquid variables
- **Validate user input** before processing Liquid templates
- **Use secure proxy server** for authentication
- **Sanitize dynamic content** to prevent XSS attacks
### **6.3 Performance Optimization**
- **Cache processed templates** for frequently used content
- **Lazy load external content** to improve initial load times
- **Minimize API calls** by batching content requests
- **Use efficient Liquid filters** for data transformation
---
## **7. Troubleshooting**
### **7.1 Common Issues**
- **SDK not loading:** Check authentication token and network connectivity
- **Liquid variables not rendering:** Verify variable names and syntax
- **External content not loading:** Check API endpoints and CORS settings
- **Modal not displaying:** Ensure CSS styles are properly loaded
### **7.2 Debug Tips**
- **Enable console logging** for detailed error messages
- **Test Liquid syntax** in a separate environment first
- **Validate JSON structure** of external content
- **Check browser network tab** for failed requests
---
This integration provides a powerful foundation for creating personalized email campaigns with dynamic content, conditional logic, and a smooth user experience through Beefree SDK's intuitive interface combined with Liquid's templating capabilities.Overview
This project showcases how to configure Beefree SDK's email editor with Liquid templating for dynamic and personalized email content. Built with React and the @beefree.io/sdk npm package, it's designed for developers and teams who need to customize Beefree SDK's email builder for end users who need to create sophisticated and highly personalized email campaigns that include conditional content and product loops.
This project is designed for:
Email Developers who need advanced personalization features
Marketing Teams creating dynamic, data-driven campaigns
Developers integrating advanced email functionality into their applications
Agencies building advanced custom email solutions for clients
Reference the project code in the beefree-liquid-email-personalization GitHub repository.
The video provides a visual example of the demo and how Display Conditions, Content Dialog, and Merge Tags are integrated on the frontend.
Getting Started
This section includes what you need to get started with the project.
Prerequisites
Node.js (v16 or higher)
npm or yarn
Beefree SDK credentials
Installation
Clone the repository:
Install dependencies:
Set up environment variables:
Start the development servers:
Open your browser to
http://localhost:3000
Development
The application uses:
Vite: Fast React development server
React: Modern UI framework
@beefree.io/sdk: Official Beefree SDK npm package
Proxy Server: Backend for authentication and API calls
The React app runs on port 3000 and proxies API calls to the backend server on port 3001.
Configuration
The main configuration is in src/App.jsx. Key areas you can customize:
Merge Tags: Add your custom data fields in the
MERGE_TAGSarrayDisplay Conditions: Create conditional logic for your use cases in
getDisplayUseCases()Custom Rows: Define your pre-built rows in the
rowsConfigurationContent Dialogs: Build custom user interfaces in
makeContentDialog()
Additional Resources
For questions and support:
Check the Beefree SDK documentation
Review the Liquid documentation
What's Included
This section lists what's included within this project.
React Application: Modern React-based email editor
Beefree SDK Integration: Using the official
@beefree.io/sdknpm packageLiquid Templating: Support for dynamic content and personalization
Display Conditions: Conditional content based on customer data
Custom Rows: Pre-built email templates with Liquid integration
Content Dialogs: Custom modals for enhanced user experience
Merge Tags: Drag-and-drop personalization fields
Product Loops: Dynamic product recommendations and abandoned cart items
File Structure
This project has the following file structure.
Liquid Overview
Liquid is a template language created by Shopify that allows you to create dynamic content by embedding simple logic and variables into your templates. It's widely used in email marketing for personalization and conditional content.
Key Liquid Features in this Project
The following list shows a few examples of Liquid used in this project.
Variables:
{{ customer.first_name }}Conditionals:
{% if customer.is_vip %}...{% endif %}Loops:
{% for product in products %}...{% endfor %}Filters:
{{ product.price | money }}Comments:
{% comment %}...{% endcomment %}
Why Liquid for Email?
Liquid is particularly well-suited for email personalization because it:
Supports complex conditional logic
Handles loops for dynamic content (products, recommendations)
Provides built-in filters for formatting
Is language-agnostic and widely supported
Integrates well with CRM and e-commerce platforms
Beefree SDK
Beefree SDK is a JavaScript library that provides a complete email editor experience. It's designed to be embedded into web applications, offering a visual drag-and-drop interface for creating professional email campaigns. This project uses the official @beefree.io/sdk npm package for modern React integration.
Key Capabilities
Visual Editor: Intuitive drag-and-drop interface
Responsive Design: Mobile-first email creation
Template Library: Pre-built templates and components
Custom Content: Support for custom rows and modules
API Integration: Suite of different APIs for extending the builder's functionality
Multi-language: Language-agnostic implementation
Beefree SDK and Liquid
The combination of Beefree SDK and Liquid creates a powerful email personalization platform:
Visual Editing: Users can design emails visually while incorporating dynamic content
Real-time Preview: See how personalization will look with sample data
Flexible Logic: Complex conditional content and loops
Scalable: Handle complex personalization rules
Developer-Friendly: Easy to integrate and customize
Project Implementation
This section outlines and describes the Beefree SDK and Liquid integration.
Beefree SDK Configuration
The beeConfig includes merge tags, display conditions, content dialogs, and custom modals. The following code snippet shows an example of how these features come together in the React implementation:
Merge Tags Integration
Merge tags provide personalization fields that can easily be added to email designs by end users on the frontend:
Display Conditions
Display conditions allow for conditional rules to be wrapped around rows within designs inside of the email builder. The following code snippet displays an example of conditional rules implemented within this project.
Custom Content Dialog
The content dialog provides a custom modal for selecting display conditions:
Customization Guide
This section discusses how you can customize the code within this project to experiement with adding your own dynamic content use cases.
Creating Custom Modals
The following code shows an example custom modal that integrates the Beefree SDK content dialog:
Adding New Merge Tags
To add new merge tags for different data sources:
Custom Display Conditions
Create new display conditions for different use cases:
Frontend Personalization Examples
Reference the following resources to see advanced personalization examples and tutorials for end users of your application.
Product loops using merge tags and display conditions.
Hide or show content using display conditions.
Dynamic content using for loops.
Last updated
Was this helpful?

