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.


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.

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.

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).

{
  "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).

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 (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, gif. Defaults to png.
typestringHow content is returned: url, base64, or binary.
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.

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.

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:

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

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

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):

{
  "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://…" }
    ]
  }
}

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:

// 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 print controls (margins, DPI, color mode, page range).

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

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

Render as a video#

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

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", "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.

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, 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)

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