Appearance
Platform Elements
Platform Elements are dynamic, platform-specific components that consuming platforms register with EngageHQ and resolve client-side at render time.
Overview
Unlike built-in content sections that EngageHQ renders directly (hero, content block, gallery, etc.), Platform Elements represent UI components that belong to a specific consuming platform. EngageHQ stores the element reference and its configuration, but the actual rendering is handled entirely by the consuming application.
This enables platforms like ecom360, KitchenClick, or AdConnect to inject their own specialized components into EngageHQ-managed content without requiring changes to the EngageHQ content model.
How it works
- Registration -- A platform registers its available elements with EngageHQ via the API or the Retail Success Platform admin UI (e.g., "Popular Sale Items", "Weekly Ad Banner")
- Authoring -- Content editors can insert registered platform elements into pages and homepages through the content builder
- Storage -- EngageHQ stores the element reference (
platform_key+element_key) along with any editor-configured values - Delivery -- The public Content API returns platform element sections alongside built-in sections
- Resolution -- The consuming application matches each platform element to a local component and renders it client-side
Client-Side Resolution
Platform elements are never rendered server-side by EngageHQ. The consuming application is responsible for mapping each platform_key:element_key combination to a concrete component. See the JavaScript, Vue, and React examples for implementation patterns.
Admin UI
Platform elements can also be registered and managed through the Retail Success Platform admin dashboard under Content Studio > Platform Elements, without using the API directly.
Required Permissions
All Platform Element management endpoints require a valid JWT with the appropriate engagehq:platform_elements.* scope:
| Endpoint | Required Scope |
|---|---|
GET list / active / show | engagehq:platform_elements.view |
POST register | engagehq:platform_elements.create |
PUT update | engagehq:platform_elements.update |
DELETE delete | engagehq:platform_elements.delete |
Requests missing the required scope will receive a 403 Forbidden response.
Registration API
Register a new platform element so it becomes available in the content builder.
Required scope: engagehq:platform_elements.create
http
POST /api/v1/content/platform-elementsRequest Body
json
{
"platform_key": "ecom360",
"element_key": "popular-sale-items",
"display_name": "Popular Sale Items",
"description": "Displays a carousel of current popular/sale items",
"icon": "ShoppingBagIcon",
"category": "commerce",
"config_schema": {
"type": "object",
"properties": {
"max_items": {
"type": "integer",
"default": 12,
"minimum": 1,
"maximum": 50
},
"layout": {
"type": "string",
"enum": ["carousel", "grid"],
"default": "carousel"
}
}
},
"default_config": {
"max_items": 12,
"layout": "carousel"
},
"allowed_content_types": ["homepage", "landing"],
"supported_settings": ["padding", "max_width"]
}Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
platform_key | string | Yes | Identifier for the consuming platform (e.g., ecom360, kitchenclick) |
element_key | string | Yes | Unique element identifier within the platform (e.g., popular-sale-items) |
display_name | string | Yes | Human-readable name shown in the content builder |
description | string | No | Description shown to content editors |
icon | string | No | Icon identifier for the content builder UI |
category | string | No | Grouping category (e.g., commerce, navigation, media) |
config_schema | object | No | JSON Schema defining editor-configurable properties |
default_config | object | No | Default values for config properties |
allowed_content_types | array | No | Content types where this element can be used (omit for all types) |
supported_settings | array | No | Which standard section settings to expose in the editor |
Response
json
{
"success": true,
"data": {
"id": "pel_00000k1L2m3N4o5",
"platform_key": "ecom360",
"element_key": "popular-sale-items",
"display_name": "Popular Sale Items",
"description": "Displays a carousel of current popular/sale items",
"icon": "ShoppingBagIcon",
"category": "commerce",
"config_schema": {
"type": "object",
"properties": {
"max_items": {
"type": "integer",
"default": 12,
"minimum": 1,
"maximum": 50
},
"layout": {
"type": "string",
"enum": ["carousel", "grid"],
"default": "carousel"
}
}
},
"default_config": {
"max_items": 12,
"layout": "carousel"
},
"allowed_content_types": ["homepage", "landing"],
"supported_settings": ["padding", "max_width"],
"is_active": true,
"created_at": "2026-03-01T12:00:00+00:00",
"updated_at": "2026-03-01T12:00:00+00:00"
}
}Unique Constraint
The combination of platform_key and element_key must be unique. Attempting to register a duplicate returns a 422 validation error.
Management API
Endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/content/platform-elements | List all platform elements |
| GET | /api/v1/content/platform-elements/active | List active elements (lightweight) |
| POST | /api/v1/content/platform-elements | Register a new element |
| GET | /api/v1/content/platform-elements/{id} | Get a single element |
| PUT | /api/v1/content/platform-elements/{id} | Update an element |
| DELETE | /api/v1/content/platform-elements/{id} | Delete an element |
List Platform Elements
Required scope: engagehq:platform_elements.view
http
GET /api/v1/content/platform-elementsQuery Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
platform_key | string | - | Filter by platform (e.g., ecom360) |
content_type | string | - | Filter by allowed content type (e.g., homepage) |
is_active | boolean | - | Filter by active status |
per_page | integer | 20 | Items per page (1-100) |
page | integer | 1 | Page number |
Example Request
javascript
const response = await fetch(
'https://cdn.engagehq.retailsuccessplatform.com/api/v1/content/platform-elements?platform_key=ecom360',
{
headers: {
'Authorization': `Bearer ${token}`,
'X-Organization-Context': organizationId,
},
}
);Example Response
json
{
"success": true,
"data": [
{
"id": "pel_00000k1L2m3N4o5",
"platform_key": "ecom360",
"element_key": "popular-sale-items",
"display_name": "Popular Sale Items",
"description": "Displays a carousel of current popular/sale items",
"icon": "ShoppingBagIcon",
"category": "commerce",
"config_schema": { "..." : "..." },
"default_config": { "max_items": 12, "layout": "carousel" },
"allowed_content_types": ["homepage", "landing"],
"supported_settings": ["padding", "max_width"],
"is_active": true,
"created_at": "2026-03-01T12:00:00+00:00",
"updated_at": "2026-03-01T12:00:00+00:00"
}
],
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 20,
"total": 1
}
}List Active Elements (Lightweight)
Required scope: engagehq:platform_elements.view
Returns only active elements with minimal fields. Useful for populating the content builder palette without fetching full schemas.
http
GET /api/v1/content/platform-elements/activeShow Platform Element
Required scope: engagehq:platform_elements.view
http
GET /api/v1/content/platform-elements/{id}Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Platform element hashkey (pel_xxxxx) |
Update Platform Element
Required scope: engagehq:platform_elements.update
http
PUT /api/v1/content/platform-elements/{id}Accepts the same fields as the registration endpoint. Only included fields are updated.
Example Request
javascript
const response = await fetch(
`https://cdn.engagehq.retailsuccessplatform.com/api/v1/content/platform-elements/${elementId}`,
{
method: 'PUT',
headers: {
'Authorization': `Bearer ${token}`,
'X-Organization-Context': organizationId,
'Content-Type': 'application/json',
},
body: JSON.stringify({
display_name: 'Top Sale Items',
default_config: { max_items: 8, layout: 'grid' },
}),
}
);Delete Platform Element
Required scope: engagehq:platform_elements.delete
http
DELETE /api/v1/content/platform-elements/{id}Deletion Protection
A platform element cannot be deleted if it is currently referenced by any published content item. The API returns a 409 Conflict response listing the content items that reference the element. You must remove the element from all content before deleting it.
Error Response (In Use)
json
{
"success": false,
"message": "Cannot delete platform element: it is referenced by 3 published content items.",
"errors": {
"references": [
{ "content_id": "con_00000a1B2c3D4e5", "title": "Summer Homepage" },
{ "content_id": "con_00000f6G7h8I9j0", "title": "Fall Landing Page" }
]
}
}Config Schema
The config_schema field accepts a standard JSON Schema object that defines editor-configurable properties for the element. The content builder renders form controls based on this schema.
Zero-Config Element
Elements that require no editor configuration can omit config_schema entirely. The element will appear in the builder with no configuration panel.
json
{
"platform_key": "ecom360",
"element_key": "store-locator-map",
"display_name": "Store Locator Map",
"description": "Embeds the interactive store locator map"
}Configurable Element
Define properties in config_schema to give content editors control over the element's behavior:
json
{
"platform_key": "ecom360",
"element_key": "product-carousel",
"display_name": "Product Carousel",
"config_schema": {
"type": "object",
"properties": {
"category_id": {
"type": "string",
"title": "Category",
"description": "Filter products by category"
},
"max_items": {
"type": "integer",
"title": "Max Items",
"default": 12,
"minimum": 1,
"maximum": 50
},
"layout": {
"type": "string",
"title": "Layout",
"enum": ["carousel", "grid", "list"],
"default": "carousel"
},
"show_prices": {
"type": "boolean",
"title": "Show Prices",
"default": true
}
}
},
"default_config": {
"max_items": 12,
"layout": "carousel",
"show_prices": true
}
}Supported Schema Types
| JSON Schema Type | Editor Control |
|---|---|
string | Text input |
string + enum | Dropdown select |
string + format: "color" | Color picker (swatch + hex input) |
integer / number | Number input (with minimum/maximum) |
boolean | Toggle switch |
object + format: "image" | Media library image picker |
array + items | Repeatable item list (add/remove/reorder) |
Array Fields (Repeatable Items)
Array fields render as a repeatable list with add, remove, and reorder controls. Each item's sub-properties are rendered using the same type rules above.
json
{
"config_schema": {
"type": "object",
"properties": {
"heading": {
"type": "string",
"description": "Section heading displayed above the grid."
},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"image": {
"type": "object",
"format": "image",
"description": "Card image."
},
"title": {
"type": "string",
"description": "Card title."
},
"cta_url": {
"type": "string",
"description": "Button link URL."
},
"background_color": {
"type": "string",
"format": "color",
"description": "Card background color."
}
}
}
}
}
}
}Image Fields
Use "format": "image" on an object type to render the media library picker. The stored value is a media object with URLs, alt text, and dimensions:
json
{
"url": "https://cdn.example.com/image.jpg",
"urls": {
"thumbnail": "https://cdn.example.com/image-thumb.jpg",
"original": "https://cdn.example.com/image.jpg"
},
"alt_text": "Description of the image",
"size": 245760,
"dimensions": { "width": 1200, "height": 800 }
}Color Fields
Use "format": "color" on a string type to render a color picker. The stored value is a hex color string (e.g., #ff6600).
Schema Validation
Config values are validated against config_schema when content is saved. Invalid values are rejected with a 422 validation error.
Allowed Content Types
The allowed_content_types array restricts which content types can use this element. When omitted, the element is available in all section-based content types.
| Content Type | Description |
|---|---|
page | Static pages |
article | Blog posts and articles |
landing | Landing pages |
homepage | Homepages |
json
{
"allowed_content_types": ["homepage", "landing"]
}In this example, the element only appears in the content builder when editing a homepage or landing page.
Supported Settings
The supported_settings array controls which standard section settings are exposed in the content builder when this element is used. This gives editors the same visual controls they have for built-in sections.
Available Settings
| Setting | Description |
|---|---|
padding | Vertical padding (none, small, medium, large) |
background_color | Section background color (hex, rendered as color picker) |
max_width | Content max width (narrow, medium, wide, full) |
anchor_id | HTML anchor ID for in-page navigation |
visibility | Show/hide toggle for the section |
css_class | Additional CSS class names applied to the section wrapper |
margin | Vertical margin (none, small, medium, large) |
json
{
"supported_settings": ["padding", "background_color", "max_width", "anchor_id"]
}When omitted, no standard settings are exposed. The element relies entirely on its own config for customization.
Settings vs Config
Settings are standard visual controls shared with built-in sections (padding, width, etc.). Config is element-specific data defined by config_schema (max items, layout mode, category filter, etc.). Both are stored on the section and delivered via the Content API.
Content Storage Format
When a platform element is added to a content item, it is stored in the content.sections array alongside built-in sections. Platform elements are identified by type: "platform_element" and include a source: "platform" marker.
json
{
"content": {
"sections": [
{
"id": "section_1711234567_xyz789abc",
"type": "hero",
"content": {
"headline": "Welcome to our store"
},
"settings": {
"padding": "large"
}
},
{
"id": "section_1711234567_abc123def",
"type": "platform_element",
"source": "platform",
"platform_key": "ecom360",
"element_key": "popular-sale-items",
"content": {},
"config": {
"max_items": 12,
"layout": "carousel"
},
"settings": {
"anchor_id": "",
"padding": "medium"
}
},
{
"id": "section_1711234567_def456ghi",
"type": "content",
"content": {
"headline": "About Us",
"body": "<p>Learn more about our story...</p>"
},
"settings": {
"padding": "medium"
}
}
]
}
}Platform Element Section Fields
| Field | Type | Description |
|---|---|---|
id | string | Section ID (section_{timestamp}_{random}) |
type | string | Always "platform_element" |
source | string | Always "platform" |
platform_key | string | The platform that owns this element (e.g., ecom360) |
element_key | string | The specific element identifier (e.g., popular-sale-items) |
content | object | Reserved for future use (currently empty {}) |
config | object | Editor-configured values from config_schema |
settings | object | Standard section settings (only those in supported_settings) |
Rendering
Platform elements appear in the sections array in their authored order, interleaved with built-in sections. Your renderer should check section.type and delegate to the appropriate component. See JavaScript, Vue, and React examples.
Changelog
| Date | Change |
|---|---|
| 2026-03-26 | Added array, format: "image", and format: "color" config schema types. Added visibility, css_class, and margin supported settings. |
| 2026-03-24 | Initial publication. |