Embedding the Customizer
The Customizer is a web app you embed in an iframe. It loads a recipe and lets a shopper edit the graphics on that garment. The garment comes from the recipe: brand, number, size, and color. The recipe has the same shape as a product-image-generator request. Save & Exit shows a signed recipe URL inside the frame and does not notify the parent. The frame listens for parent messages only when parent_origin is set, and then replies only with the result of adding a logo. For a view-only recipe embed, use Embedding the Viewer.
<iframe
src="https://customizer.seddi.app/?api_key=API_KEY&recipe_url=https%3A%2F%2Fstorage.googleapis.com%2Fbucket%2Frecipe.json&logos=true"
title="Seddi Customizer"
style="width: 100%; height: 100%; border: 0;"
allow="clipboard-write"
></iframe>
Give the iframe a real height. The app fills its frame.
api_key is a query parameter, so it is visible in the iframe URL and to anyone who can see that URL.
Recipe URL
recipe_url is the URL-encoded https address of the recipe JSON. Do not combine it with brand, style_number, colorway, or mockup_id.
The URL must be https on port 443, with no username or password, and a public host. localhost and private addresses are rejected. Seddi downloads the file itself and does not send the caller's API key or other credentials to that host.
logos[].transform.rotation is clockwise degrees and is kept on save. The editor does not show a rotation control.
A load calls POST /customizer-scene-generator/v1. The API key must allow that path. Adding or replacing a graphic also calls POST /logos-for-generators/v1, so the key must allow that path too.
Query parameters
| Parameter | Values | Default | Effect |
|---|---|---|---|
api_key | string | — | Required. Sent as x-api-key on every API request from the frame. |
recipe_url | URL-encoded https URL | — | Required. Public https URL of the recipe on port 443, with no userinfo. |
logos | true | hidden | Shows the graphics panel. Any other value leaves the viewer alone. |
units | imperial, metric | imperial | Size labels in the graphics panel. Recipe geometry stays in meters. |
idle | static, rotate | static | rotate turns the garment when the viewer is idle. |
controls_layout | tl, tr, bl, br | tl | Corner for the viewer controls: top-left, top-right, bottom-left, or bottom-right. |
controls_style | URI-encoded JSON | unset | Colors for the viewer controls. Invalid JSON is ignored. |
parent_origin | origin | unset | Opt in to parent messages. Scheme, host, and port only, such as https://shop.example. Without it the frame does not listen. |
controls_style accepts #rgb or #rrggbb for these keys:
| Key | Alias | What it colors |
|---|---|---|
t | textColor | Control text |
bg | backgroundColor | Control background |
bd | borderColor | Control border |
controls_style=%7B%22bg%22%3A%22%23111827%22%2C%22t%22%3A%22%23ffffff%22%2C%22bd%22%3A%22%23334155%22%7D
That value is {"bg":"#111827","t":"#ffffff","bd":"#334155"}.
Parent messages
Set parent_origin to the origin of the page that owns the iframe. The frame registers a message listener only when that value is an origin. A message is applied when event.origin equals parent_origin and the sender is the parent window.
seddi.customizer.setOptions changes viewer chrome without reloading. Omit a field to leave it as it is. Invalid values are ignored. controls_style: null clears a previous style.
iframe.contentWindow.postMessage(
{
type: 'seddi.customizer.setOptions',
units: 'metric',
controls_layout: 'br',
controls_style: { bg: '#111827', t: '#ffffff', bd: '#334155' },
},
'https://customizer.seddi.app',
);
units is imperial or metric. controls_layout is tl, tr, bl, or br. controls_style uses the same color keys as the query parameter.
seddi.customizer.addLogo adds a graphic from a public https URL. The frame processes it with POST /logos-for-generators/v1, places it on the best open region, and selects it. The logo is drawn even when the graphics panel is hidden. Optional requestId is echoed on the reply.
iframe.contentWindow.postMessage(
{
type: 'seddi.customizer.addLogo',
sourceUrl: 'https://cdn.example/art.png',
requestId: 'logo-1',
},
'https://customizer.seddi.app',
);
The frame posts the result to the parent, with parent_origin as the target:
{ type: 'seddi.customizer.addLogoResult', requestId: 'logo-1', ok: true, logoId: '...' }
{ type: 'seddi.customizer.addLogoResult', requestId: 'logo-1', ok: false, error: '...' }
The add fails when the URL is not https, api_key is missing, the style is still loading, no logo region is available, or logo processing fails. In recipe mode, Save & Exit includes the added logo through its sourceUrl.
Enter an API key and an https recipe URL to load the frame. parent_origin is this page's origin. Metric, Imperial, and the corner buttons post seddi.customizer.setOptions and stay marked after a click. Add logo posts seddi.customizer.addLogo and waits for the frame reply, which appears under the buttons.
Graphics, colorways, and save
logos=true opens the graphics panel. Without it, the frame is a viewer only. The shopper can move, resize, align, rotate, reset, set technique, and recolor a graphic, and can add, replace, or remove one.
The panel has a colorways tab. Switching colorways calls POST /customizer-colorway-switch/v1. The key must allow that path. The colorway-switch session lasts 30 minutes by default. A deployment can change that. After it expires, switching colorways fails.
Save & Exit posts the edited recipe to POST /customizer-recipes/v1 and then shows the signed recipeUrl and its expiry in the frame. That URL lasts 30 minutes by default, and a deployment can change that. The frame shows the expiry it received. The shopper copies that URL. Save & Exit does not notify the parent. After a successful save the graphics panel closes for that session.
The key must allow /customizer-recipes/v1 for Save & Exit. Add and Replace ask for an https:// image URL, send it to POST /logos-for-generators/v1, and write that URL into the saved recipe.