Widgets
An integration can provide widgets: reusable blocks that users drop into their emails, popups or "smart content".
Nothing to host on your side
A widget is a declaration (JSON) stored in your integration. ShopiMind renders it itself, server-side, per recipient. You expose no render route and no iframe, and no partner code is ever executed.
Widgets are declared in your integration's widgets field (an array of declarations). Each declaration has a key, a localized name/description, targets (email_template | popup | smart_content), a render_type, and a config_schema.
The three render types
| Form | Fields | Rendering |
|---|---|---|
render_type: "image" | image_url_template | ShopiMind builds the <img> from your URL. |
render_type: "html" + render_mode: "static" | html_template (+ css_template) | Your HTML/CSS, validated and sanitized (no JS), resolved per recipient. Email-safe. |
render_type: "html" + render_mode: "dynamic" | renderer_key | Reuses an existing ShopiMind renderer (e.g. spm_countdown). Email → GIF, web → live JS. |
Image widget
{
"key": "promo_banner",
"name": { "fr": "Bannière promo", "en": "Promo banner" },
"targets": ["email_template", "popup"],
"render_type": "image",
"image_url_template": "https://your-service/img?promo={widget.code}&u={var=contact.email}"
}Static HTML widget (render_mode: "static")
Your html_template + css_template are stored, then sanitized and resolved per recipient (no <script>, email-safe).
{
"key": "info_card",
"name": { "fr": "Carte info", "en": "Info card" },
"targets": ["email_template", "popup", "smart_content"],
"render_type": "html",
"render_mode": "static",
"html_template": "<table ...><td>{widget.title}<a href=\"{widget.cta_url}\">{widget.cta_label}</a></td></table>",
"css_template": ".spm-card{background:{widget.bg};color:{widget.fg}}",
"config_schema": {
"fields": [
{ "key": "title", "type": "text", "default": "Hello {var=contact.first_name}", "supports_variables": true },
{ "key": "cta_url", "type": "text", "default": "{var=shop.url}", "supports_variables": true },
{ "key": "bg", "type": "color", "default": "#3CB4A4" },
{ "key": "fg", "type": "color", "default": "#FFFFFF" }
]
}
}Dynamic HTML widget (render_mode: "dynamic")
You reuse an existing ShopiMind renderer via renderer_key. The renderer code lives at ShopiMind (co-designed with you) — you send no script.
{
"key": "deadline_countdown",
"name": { "fr": "Compte à rebours", "en": "Countdown" },
"targets": ["email_template", "popup", "smart_content"],
"render_type": "html",
"render_mode": "dynamic",
"renderer_key": "spm_countdown",
"config_schema": {
"fields": [
{ "key": "endDate", "type": "datetime" },
{ "key": "timezone", "type": "text", "default": "Europe/Paris" },
{ "key": "digitBgColor", "type": "color", "default": "#1a1a1a", "strip_hash": true }
]
}
}Render placeholders
Three families, all resolved server-side:
| Placeholder | Source | Resolved |
|---|---|---|
{var=…} | Per-recipient ShopiMind data — e.g. {var=contact.first_name}, {var=shop.url}, {var=custom_data.<schema>.<field>} | At send, per recipient |
{widget.<field>} | The widget's user-chosen config (its config_schema) | At render |
{integration.<field>} | The integration's non-sensitive config values | At render |
A secret never flows into an image URL / rendered HTML (only non-sensitive values feed {integration.*}).
Integrator-set config
A config_schema field declared owner: "integrator" is hidden from the merchant: the integrator sets its value per shop (via the API — see Integrator config). It resolves here as {integration.<key>}, with the declared default as fallback. Handy for a tracking URL, an account id, etc.
A widget's config_schema
A widget declares a config_schema (same types as the integration config) — user-chosen values resolve via {widget.<field>}:
- Field types:
text·number·color·select·checkbox·datetime. - Layout:
fields(flat) orgroups(each group = a tab). - Useful flags:
default,options(forselect),label,supports_variables(allow a{var=…}in the field),strip_hash(color without the#, for some image URLs).