Render from Studio Template

Render any template you've designed in Orshot Studio by making a POST request — as an image, PDF, or video, at any size, and optionally publish it.

Updated

POST
/v1/studio/render
curl -X POST "https://api.orshot.com/v1/studio/render" \
  -H "Authorization: Bearer <ORSHOT_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": 1,
    "modifications": {},
    "response": {},
    "pdfOptions": {}
  }'

Templates you design in Orshot Studio are Studio Templates — custom layouts whose text, images, and styles you parameterize and then render on demand from the API.

Endpoint
POST https://api.orshot.com/v1/studio/render

Quick start#

The smallest request: a template ID, your dynamic values, and the output you want back.

JavaScript
const res = await fetch("https://api.orshot.com/v1/studio/render", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: "Bearer <ORSHOT_API_KEY>",
  },
  body: JSON.stringify({
    templateId: <TEMPLATE_ID>,
    modifications: {
      title: "Custom Title",
      imageUrl: "https://acme.com/cover.png",
    },
    response: { type: "url", format: "png" },
  }),
});

const { data } = await res.json();
// data.content → the rendered image URL

Everything else on this page is optional and layers on top of this: render at any size, as a PDF or video, or publish it to social.

Response#

data holds your render. Its shape depends on the template — expand the matching tab:

One page → data is an object. Read the render at data.content (a string).

JavaScript
{
  "data": {
    "content": "data:image/png;base64,iVBORw0.....", // URL or base64, per response.type
    "format": "png",
    "type": "base64",
    "responseTime": 325.22
  }
}

The base64 type with a binary response isn't supported (a binary stream returns one file).

Multiple pages → data is an array, one entry per page.

JavaScript
{
  "data": [
    { "page": 1, "pageId": "a1b2c3d4-…", "content": "https://storage.orshot.com/…/page_1.png" },
    { "page": 2, "pageId": "b2c3d4e5-…", "content": "https://storage.orshot.com/…/page_2.png" }
  ],
  "format": "png",
  "type": "url",
  "responseTime": 3166.01,
  "totalPages": 3,
  "renderedPages": 3
}

Each entry has page (1-based number) and pageId (stable UUID). Prefer pageId when referencing a specific page — page numbers shift when pages are reordered, while pageId is stable for the page's lifetime.

When flow text overflows onto extra pages, those pages carry flow metadata so you know where each came from.

JavaScript
{
  "data": [
    { "page": 1, "pageId": "a1b2c3d4-…", "content": "https://…/page_1.png" },
    { "page": 2, "content": "https://…/page_2.png", "sourcePageId": "a1b2c3d4-…", "sourcePageNumber": 1, "flowPage": 1 },
    { "page": 3, "content": "https://…/page_3.png", "sourcePageId": "a1b2c3d4-…", "sourcePageNumber": 1, "flowPage": 2 }
  ],
  "format": "png",
  "type": "url",
  "totalPages": 3,
  "renderedPages": 3,
  "flowTotalPages": 2
}
FieldWhereMeaning
sourcePageIdoverflow pageUUID of the source template page the overflow came from
sourcePageNumberoverflow pageWhich template page the overflow came from
flowPageoverflow pageOverflow index (1 = first overflow page, 2 = second, …)
flowTotalPagestop levelTotal overflow pages generated

See Flowing Content for setup.

Request body#

FieldTypeRequiredDescription
templateIdnumberYesYour template's ID — shown on the template's page and in the playground.
modificationsobjectNoYour dynamic values, keyed by parameter ID. Multi-page templates prefix keys with the page, e.g. page2@title. You can also set style parameters to change layer styles at render time.
responseobjectNoWhat to render and how to return it (format, type, size, …). See below.
pdfOptionsobjectNoPDF-only output controls (document title, margins, DPI, color mode, page range). See Render as a PDF.
videoOptionsobjectNoVideo-only output controls (fps, trim, audio, subtitles, page transitions). See Render as a video.
publishobjectNoPublish the render to connected social accounts. See Publish to social.

The response object#

FieldTypeDescription
formatstringOutput format: png, webp, jpg, avif, pdf, mp4, webm, mov, mkv, gif. Defaults to png.
typestringHow content is returned: url, base64, or binary.
modestringsync (default) waits for the render; async returns a job immediately — built for video and long renders. See Start an Async Render.
scalenumberOutput scale multiplier. 1 = template size, 2 = double, etc.
sizestringReplace the render size — a preset slug (e.g. "instagram-story") or "WIDTHxHEIGHT" (e.g. "1200x630"). See Smart Resize.
width + heightnumberExplicit pixel dimensions instead of size (both required together, 10–5000px).
extraSizesarray | objectAdd the same design at extra sizes in one call. See Render multiple sizes.
includePagesnumber[]Multi-page only — render just these pages, e.g. [1, 3].
fileNamestringCustom output file name (no extension). url/binary types only. Carousel files are suffixed -page-1, -page-2, …; url outputs also get a -[HASH] suffix to stay unique. For PDFs, it also becomes the document's Title metadata unless pdfOptions.title is set.

Smart Resize#

Render a template at a different canvas size without redesigning it — design once, then generate platform-ready outputs for every channel from the same template and modifications. Want to set this up visually first? See Smart Resize in Studio.

The layout adapts deterministically (no AI) — the same template and size always produce the same output:

  • Everything scales uniformly, so proportions and text wrapping are preserved.
  • Backgrounds and full-bleed images stretch to cover the new canvas.
  • Elements re-anchor to the edge/center they were designed against (a top-left logo stays top-left; a footer stays pinned to the bottom).
  • Grouped elements (e.g. a heading + subheading) move together as one unit.
  • A safety guard guarantees the adapted layout never introduces overlapping elements.

Render at a different size#

size replaces the render size; the response shape is unchanged.

JavaScript
response: {
  type: "url",
  format: "png",
  size: "instagram-story", // preset slug, or "1080x1920", or use width + height
}

Available presets — or pass any "WIDTHxHEIGHT" string, or width + height (10–5000px):

instagram-story · instagram-post · instagram-post-portrait · instagram-post-landscape · facebook-post · facebook-story · facebook-cover · twitter-post · twitter-header · linkedin-post · linkedin-banner · youtube-thumbnail · youtube-short · tiktok-video · pinterest-pin · whatsapp-status · og-image · blog-header · email-header · website-banner · presentation-16-9 · a4-document · us-letter · business-card · zoom-background · leaderboard-ad · medium-rectangle-ad

  • response.scale still applies on top of the adapted size — size: "1080x1920" with scale: 2 outputs 2160×3840.
  • Best with moderate aspect-ratio changes; extreme changes (e.g. square → leaderboard-ad) stay safe but elements may look small relative to the canvas.

Render multiple sizes in one call#

Where size replaces the output, extraSizes is purely additive: your normal response is unchanged, and each output gains an extraSizes array nested right beside it.

Pass an array of sizes:

JavaScript
response: { type: "url", format: "png", extraSizes: ["1080x1920", "1080x1080", "1200x630"] }

…or a named object, when you want a label to route on:

JavaScript
response: { type: "url", format: "png", extraSizes: { story: "1080x1920", square: "1080x1080" } }

The extra sizes nest beside your render — single-page on the data object, multi-page on each page (so a size is always self-describing about which page it belongs to):

JavaScript
{
  "data": {
    "content": "https://…",                          // your normal render (native or `size`)
    "extraSizes": [
      { "size": "1080x1920", "width": 1080, "height": 1920, "content": "https://…" },
      { "size": "1080x1080", "width": 1080, "height": 1080, "content": "https://…" }
    ]
  }
}
JavaScript
{
  "data": [
    { "page": 1, "content": "https://…", "extraSizes": [ { "size": "1080x1920", "width": 1080, "height": 1920, "content": "https://…" } ] },
    { "page": 2, "content": "https://…", "extraSizes": [ { "size": "1080x1920", "width": 1080, "height": 1920, "content": "https://…" } ] }
  ]
}

A named size adds a name field to each entry, e.g. { "name": "story", "size": "story", … }.

Combine with sizesize sets the base render, extraSizes add extra copies beside it:

JavaScript
// base rendered at 1200x630, plus a 1080x1920 copy
response: { type: "url", format: "png", size: "1200x630", extraSizes: ["1080x1920"] }

Leave size off and data stays your original render — so extraSizes: ["1080x1920"] gives you the original and the story size.

Reproduce studio-approved sizes#

For pixel-perfect output, open your template in the studio and add sizes from the Smart Resize panel — each gets an instant adaptive preview, can be recomposed with AI, and is saved with the template. A render that requests a saved size reproduces that approved preview exactly, every time; the deterministic adaptation above is only used for sizes you haven't saved.

  • Works with every response format and with multi-page templates (every page is adapted).
  • Saved sizes apply whether the request comes from your own backend or an embed — your customers resize in the embed, you render the saved sizes via the API.

Render as a PDF#

Set response.format to pdf and add an optional pdfOptions object for document metadata and print controls (title, margins, DPI, color mode, image compression, page range).

JavaScript
body: JSON.stringify({
  templateId: <TEMPLATE_ID>,
  modifications: { name: "Sarah Chen", course: "UX Design" },
  response: { type: "url", format: "pdf" },
  pdfOptions: { title: "UX Design Certificate", margin: "0px", dpi: 300, colorMode: "cmyk" },
}),

pdfOptions.title sets the PDF's Title metadata (shown in browser tabs and PDF reader window titles); it falls back to response.fileName when omitted. For accessible PDFs, describe image layers with the .alt parameter, e.g. "hero_image.alt": "123 Main St exterior photo".

Photo-heavy pages can run to tens of MB because the renderer stores scaled or cropped images as raw pixels. Add "imageFormat": "jpeg" to pdfOptions to re-encode them, which typically cuts 80 to 90% of the file size.

See PDF Options for every field (title, margins incl. per-side overrides, DPI, RGB/CMYK, image compression, page ranges) and print recommendations.

Render as a video#

For templates with video elements, set response.format to mp4, webm, mov, mkv, or gif.

JavaScript
body: JSON.stringify({
  templateId: <TEMPLATE_ID>,
  modifications: {
    promoVideo: "https://example.com/clip.mp4", // a video element's parameter ID
    "promoVideo.trimStart": 0,
    "promoVideo.trimEnd": 10,
  },
  response: { type: "url", format: "mp4" }, // or "webm", "mov", "mkv", "gif"
  videoOptions: { fps: 30, muted: true, combinePages: true, pageTransition: "fade" },
}),
  • Per-element controls (custom URL, .trimStart, .trimEnd, .muted, .loop) → see Video Elements.
  • Render-level videoOptions (fps, quality, trim, audio overrides, subtitles + styling, multi-page combine & transitions) → see Video Options.
  • Page-level audio tracks and subtitles set in Studio are included automatically; see Audio & Subtitles.

Publish to social#

Add a publish object to post the render straight to connected social accounts — no extra calls. The response gains a publish array with each account's status.

JavaScript
body: JSON.stringify({
  templateId: <TEMPLATE_ID>,
  modifications: { title: "New post is live!" },
  response: { type: "url", format: "png" },
  publish: {
    accounts: [1, 2],                  // social account IDs from your workspace
    content: "Check out our latest design!",
  },
}),

See Publish from API for the full object — drafts (isDraft), scheduling (schedule.scheduledFor, timezone), per-account platformOptions, TikTok tiktokSettings, statuses, and error handling.

Rate limits#

This endpoint is rate limited based on your plan. Check the response headers:

HeaderDescription
X-RateLimit-LimitMaximum requests per minute for your plan
X-RateLimit-RemainingRemaining requests in the current window
Retry-AfterSeconds to wait (only on 429 responses)
Was this page helpful?

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