Controlling the Embed
Dynamically update template content, switch templates, and navigate pages via postMessage
Control the embed from your parent page using postMessage. You can switch templates, switch pages, and update layer content (text, images) without reloading the iframe.
Controlling the embed requires Enable Events to be turned on in your
embed settings, and embed control via postMessage is available on supported
plans only. If either requirement isn't met, the embed replies with an
orshot:error event explaining why. See Requirements.
| Event | Description |
|---|---|
| Setting Layer Modifications | Update text, image, and other layer values dynamically |
| Switching Templates | Switch to a different template within the embed |
| Switching Pages | Navigate to a specific page by index or ID |
| Switch Template + Set Modifications | Load a template with pre-filled values in one call |
| Controlling Custom Buttons | Change labels or show/hide custom buttons at runtime |
Setting Layer Modifications#
Update text and image layers dynamically:
const iframe = document.querySelector("iframe");
iframe.contentWindow.postMessage(
{
type: "orshot:embed:control",
modifications: {
text: "Hello World",
image: "https://example.com/photo.jpg",
},
},
"*",
);The modifications object uses layer parameter names as keys. These match the parameter names you've defined in your template.
Switching Templates#
Switch to a different template within the same embed:
iframe.contentWindow.postMessage(
{
type: "orshot:embed:control",
templateId: "481",
},
"*",
);Switching Pages#
For multi-page templates, switch to a specific page by index (1-based) or page ID:
// By page index (1-based)
iframe.contentWindow.postMessage(
{
type: "orshot:embed:control",
pageIndex: 1,
},
"*",
);
// By page ID
iframe.contentWindow.postMessage(
{
type: "orshot:embed:control",
pageId: "abc-123-uuid",
},
"*",
);You can combine page switching with modifications to switch to a page and update its content:
iframe.contentWindow.postMessage(
{
type: "orshot:embed:control",
pageIndex: 2,
modifications: {
headline: "Updated Slide 2",
},
},
"*",
);If both pageIndex and pageId are provided, pageId takes priority.
Switch Template + Set Modifications#
Combine both to load a specific template with pre-filled values:
iframe.contentWindow.postMessage(
{
type: "orshot:embed:control",
templateId: "481",
modifications: {
title: "My Custom Title",
subtitle: "Product description here",
image: "https://example.com/product.jpg",
},
},
"*",
);The embed will:
- Switch to the specified template
- Wait for it to finish loading
- Apply the layer modifications
If the template is already loaded, modifications apply immediately. You can
also listen for the orshot:embed:ready
event to know when a template has finished loading.
Waiting for the Embed to be Ready#
The embed emits orshot:embed:ready each time a template finishes loading.
Use it to know when the editor is safe to control, or to detect a
misconfigured embed:
window.addEventListener("message", (event) => {
if (!event.origin.includes("orshot.com")) return;
if (event.data.type === "orshot:embed:ready") {
const { templateId, eventsEnabled } = event.data.data;
if (!eventsEnabled) {
console.warn(
"Enable Events is turned off for this embed — modifications and control messages will be ignored",
);
return;
}
// Safe to send control messages now
iframe.contentWindow.postMessage(
{
type: "orshot:embed:control",
modifications: { title: "Hello" },
},
"*",
);
}
});| Field | Type | Description |
|---|---|---|
templateId | number | null | The template that finished loading |
eventsEnabled | boolean | Whether Enable Events is turned on for this embed |
orshot:embed:ready is sent even when Enable Events is turned off (with
eventsEnabled: false) so you can detect the misconfiguration instead of
debugging a silent failure.
Controlling Custom Buttons#
Change the label or toggle visibility of custom buttons at runtime. Use the button ID shown in your embed settings (click to copy).
iframe.contentWindow.postMessage(
{
type: "orshot:embed:control",
customButtons: {
"custom-btn-1716384000000": { label: "Save to CRM", visible: false },
"custom-btn-1716384060000": { visible: true, label: "Export" },
},
},
"*",
);Each key is a button ID. Only the fields you include are overridden — omitted fields keep their configured defaults.
| Field | Type | Description |
|---|---|---|
label | string | Override the button's display text |
visible | boolean | Show (true) or hide (false) the button |
Overrides are session-scoped — they persist for the lifetime of the iframe and reset when the embed is reloaded.
You can combine customButtons with other control commands (modifications, template switching, etc.) in a single message.
Requirements: Custom buttons must be enabled on your plan and configured in your embed settings.
URL Parameters vs postMessage#
You can also set initial values via URL parameters:
<iframe
src="https://orshot.com/embeds/abc?templateId=481&title=Hello&image=https://..."
title="Orshot Embed"
allow="clipboard-write"
></iframe>| Method | Use Case |
|---|---|
| URL params | Initial load with pre-filled values |
| postMessage | Dynamic updates without reload |
URL parameter modifications also require Enable Events to be turned on in your embed settings (available on supported plans). When it's off, the values are ignored and the editor shows the template's original content.
Complete Example#
class EmbedController {
constructor(iframe) {
this.iframe = iframe;
}
// Update layer values
setModifications(modifications) {
this.iframe.contentWindow.postMessage(
{
type: "orshot:embed:control",
modifications,
},
"*",
);
}
// Switch to a different template
switchTemplate(templateId) {
this.iframe.contentWindow.postMessage(
{
type: "orshot:embed:control",
templateId,
},
"*",
);
}
// Switch template and set values
loadTemplate(templateId, modifications) {
this.iframe.contentWindow.postMessage(
{
type: "orshot:embed:control",
templateId,
modifications,
},
"*",
);
}
// Switch to a page by index (1-based)
switchPage(pageIndex) {
this.iframe.contentWindow.postMessage(
{
type: "orshot:embed:control",
pageIndex,
},
"*",
);
}
// Switch to a page by ID
switchPageById(pageId) {
this.iframe.contentWindow.postMessage(
{
type: "orshot:embed:control",
pageId,
},
"*",
);
}
// Update custom button labels or visibility
updateCustomButtons(overrides) {
this.iframe.contentWindow.postMessage(
{
type: "orshot:embed:control",
customButtons: overrides,
},
"*",
);
}
}
// Usage
const controller = new EmbedController(document.querySelector("iframe"));
// Update current template
controller.setModifications({
headline: "New Headline",
background: "https://example.com/bg.jpg",
});
// Switch to template 481 with custom values
controller.loadTemplate("481", {
title: "Product Launch",
price: "$99",
image: "https://example.com/product.jpg",
});
// Switch to page 2
controller.switchPage(2);
// Hide a button and relabel another
controller.updateCustomButtons({
"custom-btn-1716384000000": { visible: false },
"custom-btn-1716384060000": { label: "Send to CRM" },
});React Example#
import { useRef, useCallback } from "react";
function useEmbedController() {
const iframeRef = useRef(null);
const setModifications = useCallback((modifications) => {
iframeRef.current?.contentWindow?.postMessage(
{
type: "orshot:embed:control",
modifications,
},
"*",
);
}, []);
const loadTemplate = useCallback((templateId, modifications = {}) => {
iframeRef.current?.contentWindow?.postMessage(
{
type: "orshot:embed:control",
templateId,
modifications,
},
"*",
);
}, []);
const switchPage = useCallback((pageIndex) => {
iframeRef.current?.contentWindow?.postMessage(
{
type: "orshot:embed:control",
pageIndex, // 1-based
},
"*",
);
}, []);
const updateCustomButtons = useCallback((overrides) => {
iframeRef.current?.contentWindow?.postMessage(
{
type: "orshot:embed:control",
customButtons: overrides,
},
"*",
);
}, []);
return { iframeRef, setModifications, loadTemplate, switchPage, updateCustomButtons };
}
// Usage
function Editor() {
const { iframeRef, setModifications, loadTemplate, switchPage, updateCustomButtons } =
useEmbedController();
return (
<div>
<iframe
ref={iframeRef}
src="https://orshot.com/embeds/abc123?templateId=481"
title="Orshot Embed"
allow="clipboard-write"
/>
<button onClick={() => setModifications({ title: "Updated!" })}>
Update Title
</button>
<button onClick={() => loadTemplate("500", { title: "New Template" })}>
Switch Template
</button>
<button onClick={() => switchPage(2)}>Go to Page 2</button>
<button onClick={() => updateCustomButtons({
"custom-btn-1716384000000": { visible: false }
})}>
Hide Button
</button>
</div>
);
}Requirements#
- Enable Events must be turned on in your embed settings — this applies to both URL parameter modifications and postMessage control
- Embed control via postMessage is available only on supported plans; URL parameter modifications work on any plan with Enable Events available
- Your domain must be in the embed's allowed domains list
- Layer parameter names in
modificationsmust match your template's defined parameters templateIdmust reference a template that exists in the embed's workspace
If a control message is rejected (Enable Events off, or plan not supported),
the embed replies with an orshot:error event describing the reason, and logs
a warning to the browser console.
Ready to automate?
Start rendering images, PDFs and videos from your templates in under 2 minutes. Free plan, no credit card.
Get your API key- Image, PDF and video generation via API
- Visual editor with AI and smart layouts
- Zapier, Make, MCP and 50+ integrations
- White-label embed for your own app
- 30 free credits — no credit card required