Display templates for contact integrations
Customise how external data appears
Display Templates allow you to transform raw JSON data from external APIs into beautiful, structured UI components in the ContactProfileSheet. Instead of showing raw JSON, you can create custom layouts with badges, status indicators, formatted currency, and more.
Table of Contents
- Overview
- Template Structure
- Section Types
- Field Types
- Variable System
- Conditional Display
- Repeating Sections
- Template Examples
- Best Practices
- Security
Overview
Display Templates use a JSON-based configuration system that defines how external data should be rendered. The template editor provides a visual interface for building these templates, complete with live preview.
Key Features
- Visual Template Builder: Drag-and-drop interface with live preview
- Multiple Layout Types: Cards, tables, key-value lists, and text sections
- Dynamic Data Binding: Use
{{variable}}syntax to bind API data - Conditional Logic: Show/hide sections based on data values
- Type Formatting: Automatic formatting for currency, dates, status badges
- Security: Built-in XSS protection and template validation
Template Structure
Every template has this basic structure:
{
"type": "card",
"title": "Customer Information",
"description": "Account details and subscription status",
"sections": [
{
"type": "key-value-list",
"title": "Account Details",
"items": [
{
"label": "Plan",
"value": "{{subscription.plan}}",
"type": "badge"
}
]
}
]
}
Root Properties
- type:
"card"or"simple"- Layout wrapper type - title: Optional title for the template
- description: Optional description
- sections: Array of content sections
Section Types
1. Key-Value List
Displays data as labeled key-value pairs:
{
"type": "key-value-list",
"title": "Account Information",
"items": [
{
"label": "Customer ID",
"value": "{{customer_id}}",
"type": "text"
},
{
"label": "Plan",
"value": "{{subscription.plan}}",
"type": "badge"
},
{
"label": "Status",
"value": "{{subscription.status}}",
"type": "status"
}
]
}
Renders as:
Customer ID 12345
Plan [Premium]
Status [Active]
2. Table
Displays data in a structured table format:
{
"type": "table",
"title": "Financial Summary",
"items": [
{
"label": "Lifetime Value",
"value": "{{lifetime_value}}",
"type": "currency"
},
{
"label": "Last Purchase",
"value": "{{last_purchase}}",
"type": "date"
}
]
}
Renders as:
┌──────────────┬──────────────┐
│ Lifetime Value │ $2,850.00 │
│ Last Purchase │ Jan 15, 2024 │
└──────────────┴──────────────┘
3. Text
Custom text with variable interpolation:
{
"type": "text",
"content": "Customer {{customer_name}} has been a {{subscription.plan}} member since {{join_date}}."
}
4. Separator
Visual separator between sections:
{
"type": "separator"
}
Field Types
Text
Default display type for plain text values.
{
"label": "Customer ID",
"value": "{{customer_id}}",
"type": "text"
}
Badge
Displays value in a colored badge/pill.
{
"label": "Plan",
"value": "{{subscription.plan}}",
"type": "badge"
}
Status
Colored status indicators with predefined color schemes.
{
"label": "Status",
"value": "{{subscription.status}}",
"type": "status"
}
Status Colors:
active→ Greenpending→ Yellowinactive→ Grayfailed→ Redsuccess→ Greenerror→ Red
Currency
Formats numbers as currency (USD by default).
{
"label": "Lifetime Value",
"value": "{{lifetime_value}}",
"type": "currency"
}
Example: 2850.00 → $2,850.00
Date
Formats date strings in readable format.
{
"label": "Last Purchase",
"value": "{{last_purchase}}",
"type": "date"
}
Example: 2024-01-15T10:30:00Z → Jan 15, 2024
Link
Creates clickable links.
{
"label": "Profile",
"value": "{{profile_url}}",
"type": "link"
}
Variable System
Use {{variable}} syntax to reference data from your API response:
Simple Variables
{{customer_id}} → 12345
{{email}} → [email protected]
Nested Variables
{{subscription.plan}} → Premium
{{billing.address.city}} → New York
Array Access
{{tags.0}} → First tag
{{orders.0.total}} → First order total
Conditional Display
Show/hide sections or items based on data values:
Simple Existence Check
{
"type": "key-value-list",
"condition": "{{subscription}}",
"items": [...]
}
Equality Check
{
"type": "text",
"condition": "{{status}} === 'active'",
"content": "This customer has an active subscription."
}
Inequality Check
{
"type": "key-value-list",
"condition": "{{subscription.status}} !== 'cancelled'",
"items": [...]
}
Repeating Sections
Repeating sections allow you to display array data (like orders, transactions, or tickets) with configurable templates for each item.
Configuration
{
"type": "repeating-section",
"title": "Order History",
"array_path": "orders",
"item_template": {
"sections": [
{
"type": "key-value-list",
"items": [
{
"label": "Order ID",
"value": "{{id}}",
"type": "text"
},
{
"label": "Status",
"value": "{{status}}",
"type": "status"
},
{
"label": "Amount",
"value": "{{amount}}",
"type": "currency"
},
{
"label": "View Order",
"value": "{{order_url}}",
"type": "link"
}
]
}
]
}
}
Properties
- type: Always
"repeating-section" - title: Optional section title
- array_path: Path to the array in your API response (e.g.,
"orders","tickets","transactions") - item_template: Template configuration for each array item
- condition: Optional condition to show/hide the entire section
Array Path Examples
// Simple array path
"array_path": "orders" // Accesses response.orders
// Nested array path
"array_path": "customer.orders" // Accesses response.customer.orders
// Deep nesting
"array_path": "data.customer.order_history" // Accesses response.data.customer.order_history
Item Template Fields
Within repeating sections, you can use these field types:
text- Plain textbadge- Colored badge/pillstatus- Status indicator with predefined colorscurrency- Formatted currencydate- Formatted datelink- Clickable link (opens in new tab)
Note: Buttons are not supported within repeating sections for security reasons.
Example API Response
{
"success": true,
"orders": [
{
"id": 12345,
"status": "completed",
"amount": "$450.00",
"due_date": "2024-02-15",
"payment_status": "paid",
"order_url": "https://orders.example.com/12345"
},
{
"id": 12346,
"status": "in_progress",
"amount": "$750.00",
"due_date": "2024-03-20",
"payment_status": "pending",
"order_url": "https://orders.example.com/12346"
}
]
}
Rendered Output
┌─ Order History ──────────────────────┐
│ │
│ ┌────────────────────────────────────┐ │
│ │ Order ID 12345 │ │
│ │ Status [Completed] │ │
│ │ Amount $450.00 │ │
│ │ View Order [Link] ↗ │ │
│ │ ────────────────────────────────── │ │
│ │ Item 1 of 2 │ │
│ └────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────┐ │
│ │ Order ID 12346 │ │
│ │ Status [In Progress] │ │
│ │ Amount $750.00 │ │
│ │ View Order [Link] ↗ │ │
│ │ ────────────────────────────────── │ │
│ │ Item 2 of 2 │ │
│ └────────────────────────────────────┘ │
└──────────────────────────────────────┘
Empty State
When the array is empty or doesn't exist:
┌─ Order History ──────────────────────┐
│ │
│ No orders found │
│ │
└──────────────────────────────────────┘
Template Examples
Example 1: Customer Overview
API Response:
{
"customer_id": 12345,
"email": "[email protected]",
"subscription": {
"plan": "Premium",
"status": "active",
"renewal_date": "2024-06-15"
},
"support_tier": "Priority",
"lifetime_value": 2850.00
}
Template:
{
"type": "card",
"title": "Customer Overview",
"description": "Key account information",
"sections": [
{
"type": "key-value-list",
"title": "Account Details",
"items": [
{
"label": "Customer ID",
"value": "{{customer_id}}",
"type": "text"
},
{
"label": "Support Tier",
"value": "{{support_tier}}",
"type": "badge"
},
{
"label": "Status",
"value": "{{subscription.status}}",
"type": "status"
}
]
},
{
"type": "separator"
},
{
"type": "table",
"title": "Financial Information",
"items": [
{
"label": "Lifetime Value",
"value": "{{lifetime_value}}",
"type": "currency"
},
{
"label": "Plan",
"value": "{{subscription.plan}}",
"type": "badge"
}
]
}
]
}
Example 2: Support Ticket Summary
API Response:
{
"tickets": {
"total": 15,
"open": 2,
"avg_resolution_time": 4.5
},
"last_contact": "2024-01-10T14:30:00Z",
"satisfaction_score": 4.8
}
Template:
{
"type": "simple",
"sections": [
{
"type": "text",
"content": "Customer has {{tickets.total}} total tickets with {{tickets.open}} currently open."
},
{
"type": "key-value-list",
"items": [
{
"label": "Last Contact",
"value": "{{last_contact}}",
"type": "date"
},
{
"label": "Satisfaction Score",
"value": "{{satisfaction_score}}/5.0",
"type": "text"
},
{
"label": "Avg Resolution",
"value": "{{tickets.avg_resolution_time}} hours",
"type": "text"
}
]
}
]
}
Example 3: E-commerce Order History
API Response:
{
"orders": {
"total_count": 23,
"total_spent": 5280.50
},
"last_order": {
"date": "2024-01-08T12:00:00Z",
"total": 159.99,
"status": "delivered"
},
"loyalty_tier": "Gold",
"is_vip": true
}
Template:
{
"type": "card",
"title": "Order History",
"sections": [
{
"type": "key-value-list",
"condition": "{{is_vip}}",
"title": "VIP Customer",
"items": [
{
"label": "Loyalty Tier",
"value": "{{loyalty_tier}}",
"type": "badge"
}
]
},
{
"type": "table",
"title": "Order Summary",
"items": [
{
"label": "Total Orders",
"value": "{{orders.total_count}}",
"type": "text"
},
{
"label": "Total Spent",
"value": "{{orders.total_spent}}",
"type": "currency"
},
{
"label": "Last Order",
"value": "{{last_order.date}}",
"type": "date"
},
{
"label": "Last Order Status",
"value": "{{last_order.status}}",
"type": "status"
}
]
}
]
}
Best Practices
1. Template Design
- Keep it Simple: Start with basic key-value lists before adding complexity
- Use Appropriate Types: Choose the right field type for better visual hierarchy
- Group Related Data: Use sections to organize related information
- Provide Context: Add section titles and descriptions for clarity
2. Variable Usage
- Test Variables: Use the preview pane to ensure variables resolve correctly
- Handle Missing Data: Variables that don't exist will show as empty
- Use Descriptive Labels: Make labels clear and user-friendly
- Consider Data Types: Match field types to your data (dates, currency, etc.)
3. Performance
- Limit Complexity: Very complex templates may impact rendering performance
- Use Conditions Wisely: Don't overuse conditional sections
- Keep Templates Focused: One template per specific data type/purpose
4. User Experience
- Test with Real Data: Always test templates with actual API responses
- Consider Edge Cases: What happens when data is missing or unexpected?
- Maintain Consistency: Use similar layouts across different integrations
- Get User Feedback: Ask support agents what information they find most useful
Security
Built-in Protection
- XSS Prevention: Script tags and JavaScript URLs are blocked
- Template Validation: Structure is validated on save
- Safe Rendering: Variables are escaped to prevent injection
Security Guidelines
- Validate External Data: Ensure your APIs return safe, expected data
- Limit Template Complexity: Complex templates are harder to secure
- Regular Reviews: Periodically review templates for potential issues
- User Permissions: Only allow trusted users to create/edit templates
Troubleshooting
Common Issues
Variables not showing data:
- Check the variable path matches your API response structure
- Ensure the API is returning the expected data structure
- Use the preview pane to debug variable resolution
Template not displaying:
- Verify the template structure is valid
- Check that
display_enabledis true for the integration - Ensure the integration is active and returning successful responses
Formatting issues:
- Verify field types match your data (don't use
currencytype for text) - Check date format compatibility
- Test with different data values
Performance problems:
- Simplify complex templates
- Reduce the number of conditional sections
- Consider breaking large templates into smaller ones
Getting Help
- Use the Template Editor: The live preview helps identify issues immediately
- Check Browser Console: Look for JavaScript errors that might indicate problems
- Test Integration: Use the test feature in Settings to verify API responses
- Review Logs: Check Laravel logs for template validation errors
This completes the Display Templates documentation. Templates provide a powerful way to transform raw API data into beautiful, actionable insights for your support team!