Articles on: Embedded Editor

Embedded Editor Events (postMessage)

The Templated embedded editor talks to your page with browser messages (window.postMessage). Your page can:


  • Listen to events from the editor, for example when a template loads, is saved or is downloaded.
  • Send commands to the editor, for example save, download or change the zoom.


This works without a backend. For server-side notifications, use the webhook URL in your embed configuration (see "Webhook Integration"). The create, save and download actions are sent both to your webhook and to your page.


Docs: https://templated.io/docs/embed/webhooks/ and https://templated.io/docs/embed/preview-mode/


Events the editor sends to your page


Event

When

Main fields

EDITOR_READY

The editor started and can receive messages

none (no template ID)

TEMPLATE_LOADED

The template finished loading

template.id, template.name, template.width, template.height

action create

A new template or clone was created (for example with clone=true)

templateId, metadata

action save

The user saved

templateId, metadata

action download

A download finished

templateId, renderId, renderUrl, metadata

TEMPLATE_SAVED_SUCCESS

A save requested with the SAVE message finished

templateId

TEMPLATE_DOWNLOADED_SUCCESS

A download requested with the DOWNLOAD message finished

templateId, renderId, renderUrl, format

TEMPLATE_DOWNLOAD_ERROR

A requested download failed

error

ZOOM_UPDATED

Zoom changed with SET_ZOOM

zoom

LAYER_SELECTED

The user selected a layer

data.name, data.type


Important: there are two message styles.


  • Events with a type field (like EDITOR_READY and TEMPLATE_LOADED) arrive as JavaScript objects.
  • The create, save and download actions arrive as a JSON string with an action field. Parse it with JSON.parse.


Example listener


window.addEventListener('message', (event) => {
if (event.origin !== 'https://app.templated.io') return;

let msg = event.data;
if (typeof msg === 'string') {
try { msg = JSON.parse(msg); } catch (e) { return; }
}

// Events with "type"
switch (msg.type) {
case 'EDITOR_READY':
console.log('Editor ready');
break;
case 'TEMPLATE_LOADED':
console.log('Template ID (clone ID when clone=true):', msg.template.id);
break;
case 'TEMPLATE_DOWNLOADED_SUCCESS':
console.log('Render URL:', msg.renderUrl);
break;
}

// Actions (create / save / download)
switch (msg.action) {
case 'create':
console.log('New template or clone:', msg.templateId, msg.metadata);
break;
case 'save':
console.log('Saved:', msg.templateId);
break;
case 'download':
console.log('Downloaded:', msg.renderId, msg.renderUrl);
break;
}
});


Getting the template or clone ID


  • Use TEMPLATE_LOADED: msg.template.id is the ID of the template that is open. With clone=true or render=..., this is the new clone ID.
  • Or use the create and save actions: msg.templateId.
  • EDITOR_READY does not include any ID. It only tells you the editor is ready for messages.


Add your own data (user ID, order ID) with the metadata URL parameter (base64-encoded JSON). It comes back in create, save and download.


Commands your page can send to the editor


Get the iframe and send a message after EDITOR_READY:


const iframe = document.getElementById('templated-editor');

// Save the template
iframe.contentWindow.postMessage({ type: 'SAVE' }, '*');

// Download using the format selected in the editor
iframe.contentWindow.postMessage({ type: 'DOWNLOAD' }, '*');

// Download with a specific format and pages
iframe.contentWindow.postMessage({
type: 'DOWNLOAD',
format: 'png', // 'jpg', 'png', 'pdf' or 'mp4'
pages: 'all' // 'all' (default), page numbers like '1,3' or a range like '2-4' (first page = 1)
}, '*');

// Change the zoom (10 to 100, 50 = 100% scale)
iframe.contentWindow.postMessage({ type: 'SET_ZOOM', zoom: 60 }, '*');

// Change layer values without reloading
iframe.contentWindow.postMessage({
type: 'UPDATE_LAYERS',
data: { 'title': { text: 'New title' } }
}, '*');

// Open another template without reloading
iframe.contentWindow.postMessage({ type: 'LOAD_TEMPLATE', templateId: 'TEMPLATE_ID', clone: false }, '*');


Notes:


  • SAVE works only when saving is allowed in your embed configuration.
  • DOWNLOAD works only when download is allowed and uses credits from your account, like a download from the button. With your own buttons you can hide the editor's Save button with &hide-save-button=true.
  • The full list of messages (add or remove layers, change permissions, show one page, get layers) is in the Preview Mode docs: https://templated.io/docs/embed/preview-mode/


FAQ


Q: How do I know when the user saved?
A: Listen for the save action (frontend) or use the webhook. Both include templateId.


Q: How do I get the clone ID in my frontend?
A: Listen for TEMPLATE_LOADED and read template.id. With clone=true you also receive a create action with templateId.


Q: EDITOR_READY has no template ID. Is that a bug?
A: No. EDITOR_READY only means the editor is ready. The ID comes in TEMPLATE_LOADED.


Q: My listener gets the save event but event.data.action is undefined. Why?
A: The create, save and download actions are sent as a JSON string. Run JSON.parse(event.data) first.


Q: Can I trigger the download from my own button?
A: Yes. Send { type: 'DOWNLOAD', format: 'png' } to the iframe. You receive TEMPLATE_DOWNLOADED_SUCCESS with the renderUrl.


Q: Can I change the zoom after the editor loads?
A: Yes. Send { type: 'SET_ZOOM', zoom: 60 }.

Updated on: 01/10/2026

Was this article helpful?

Share your feedback

Cancel

Thank you!