Render video and images from JSON, inside n8n.
Shotstack renders video and images from a JSON edit and returns a hosted URL. This node puts that in your n8n workflows.
Installation · Credentials · Your first render · Operations · Waiting for a render · Use with AI agents · Resources
Install @shotstack/n8n-nodes-shotstack from
Settings → Community Nodes.
n8n Cloud installs verified community nodes only. Verification is a separate n8n review that starts once the package is on npm. Install this node on self-hosted n8n today.
You need a Shotstack API key from the dashboard. Sandbox and Production have separate keys.
The credential's Environment switch defaults to Sandbox, so you can build
before you spend anything. It stores which environment you picked, not an API
version, so the node keeps working when Shotstack changes one. The node sends
your key to api.shotstack.io and to no other host.
One credential holds one key and one environment. Because the two environments have different keys, create a second credential when you are ready for Production, and switch the node to it. If the key and the switch disagree, Shotstack answers 403 and names the environment it expected, so Test on the credential catches it before any workflow runs.
Three Shotstack nodes in a row. Each one reads the previous step, so only the first needs anything typed into it.
- Render → Render Asset. Paste an edit into the Edit field. The placeholder shown in the field is a working one to start from.
- Asset → Get Asset by Render ID. Returns the permanent CDN URL. Render ID already defaults to the id from step 1. This step waits for the render and for Shotstack to publish the file, up to two minutes, so do not add a Wait node. Most renders finish well inside that.
- Render → Get Render Status, only for a render longer than two minutes. Turn on Wait for the Render To Finish and put this before step 2.
Most nodes that post, email or upload take a URL, so step 2 is usually the last Shotstack step. If a node needs the bytes, put n8n's own HTTP Request node after step 2 with the URL from it and the response format set to file.
Keep the credential on Sandbox while you build. Renders are free there, and the output carries a watermark.
For long or bulk renders, replace steps 2 and 3 with a callback — see Waiting for a render.
Operation names and stored values come from
Shotstack's OpenAPI spec. The display name is
the operation summary and the value is the operationId, so the node's dropdown
and the API reference read the same way.
| Resource → Operation | API |
|---|---|
| Render → Render Asset | POST /render · postRender |
| Render → Render Template | POST /templates/render · postTemplateRender |
| Render → Get Render Status | GET /render/{id} · getRender |
| Asset → Get Asset by Render ID | GET /assets/render/{id} · getAssetByRenderId (Serve API) |
Every operation has an entry in the spec. The node adds none of its own.
Renders a video or image from a Shotstack edit. It accepts any number of clips, every asset type and the generative assets. Point an AI agent at this operation.
| Field | Notes |
|---|---|
| Edit | The edit: a timeline of tracks and clips, plus output settings. Paste one from the docs or Studio. |
| Callback URL | Optional. Shotstack posts the finished render here — see Waiting for a render. |
An edit can also generate its own media, which a template cannot do on its own. See Generative AI assets. Shotstack bills each generated asset in Sandbox and in Production. All other Sandbox renders are free.
Keep the Edit field in fixed mode. In expression mode, n8n evaluates
Shotstack merge placeholders such as {{ HEADLINE }} and removes them.
Renders a template saved in your Shotstack account, filling in its placeholders.
| Field | Notes |
|---|---|
| Template | Pick one from the list, or paste an ID. Templates are made in Shotstack Studio. |
| Merge Fields Source | Fields for find/replace pairs, or JSON to supply the whole list at once. |
| Merge Fields | The find value is the placeholder name without braces. See Merging data. |
Returns the render id. This operation takes no Callback URL: the Edit API
accepts one on POST /templates/render and does not act on it. Use
Wait for the Render To Finish, or render the template's edit with
Render Asset, which does support a callback.
Checks a render and returns its status.
| Field | Notes |
|---|---|
| Render ID | The id returned by either render operation. The default reads it from the previous step. |
| Wait for the Render To Finish | Off by default. On, the step keeps checking until the render is done — see Waiting for a render. |
| Give Up After (Minutes) | Only shown when waiting. 5 by default, 10 at most. Giving up does not stop the render. |
| Include Submitted Edit | Off by default, so polling responses stay small. |
| Simplify | On by default. Returns id, status, url, poster, thumbnail, duration, renderTime, error and data. |
Branch on failed as well as done — see the wait loop below. The
API reference lists every status value.
The url from this operation is a temporary storage link. For a URL you intend
to keep, use Asset → Get Asset by Render ID.
Returns the permanent CDN URL for a finished render.
| Field | Notes |
|---|---|
| Render ID | The id returned by either render operation. The default reads it from the previous step. |
| Main File Only | On by default. Off returns every asset the render produced, one item each. |
| Simplify | On by default. Returns assetId, renderId, url, filename and status. The render is renderId here, because assetId is the hosted file. |
Use this for any URL you store, email, publish or hand to another system.
A finished render is not yet a published file. Shotstack renders the file, then publishes it, as two steps. The Serve API answers 404 until the second step completes. The publish time varies, so a fixed Wait node does not fit. This operation waits for you, up to two minutes, and names the cause if the file does not appear. Do not add a Wait node after the render finishes.
This node unwraps Shotstack's response envelope, so read {{$json.id}}, not
{{$json.response.id}}.
One operation is different. Get Asset by Render ID returns a hosted file,
not a render, so it names the render renderId and the file assetId. Read
{{$json.renderId}} after that step. Both Render ID fields already do.
Rendering is asynchronous, so the render operations return an id, not a video. See how long a render takes. There are four ways to get the finished file. Start at the top.
Shotstack (Render Asset) → Shotstack (Get Asset by Render ID) → next step
Get Asset by Render ID waits by itself, for up to two minutes. It covers both the render and the separate step where Shotstack publishes the file to the CDN, so most workflows need nothing else. No Wait node, no Switch, no loop.
Turn on Wait for the Render To Finish in Render → Get Render Status, and put it before Get Asset by Render ID:
Shotstack (Render Asset) → Shotstack (Get Render Status, waiting) → Shotstack (Get Asset by Render ID) → next step
A failed render stops the step and reports the reason Shotstack gave, rather than looping.
It holds the n8n execution open while it waits. Give Up After bounds that, and it allows up to 10 minutes. Nine in ten renders finish inside a minute.
Two things to plan for. Your n8n can stop an execution before Give Up After
runs out: check
EXECUTIONS_TIMEOUT
on a self-hosted instance, and note that n8n's own EXECUTIONS_TIMEOUT_MAX
defaults to one hour. And every input item waits, so a batch of render IDs can
use up that hour inside a single execution. Batch them, or use a callback.
Giving up does not stop the render. Shotstack finishes it and bills it either way, so a long render belongs on a callback rather than a longer wait.
- Add a Webhook node and copy its URL.
- Paste that URL into Callback URL on Render → Render Asset.
Shotstack posts the finished render to that URL and the workflow continues from the Webhook node. Nothing polls and nothing waits, so this suits a long render, a generative render, or many at once. The URL must be publicly reachable — see Webhooks.
A self-hosted n8n behind a home router or a company firewall cannot receive it. In that case use the wait above, or the wait loop below.
Use this when neither of the above fits: a render longer than the 10 minute ceiling on Give Up After, and an n8n that Shotstack cannot reach with a callback.
Render Asset → Wait (20s) → Get Render Status → Switch on {{$json.status}}
↑ ├─ done → Get Asset by Render ID → next step
│ ├─ failed → stop, report {{$json.error}}
└────────── anything else ─────┘
Branch on failed, not just done. A Switch that only routes done back
into the Wait node loops forever on a failed render, consuming your
rate limit
and holding an n8n execution open. Cap the number of passes as well.
The node is exposed as a tool, so an AI Agent node can call it directly.
Point an agent at Render Asset, or at Render Template. Render Template is the safer of the two: an agent fills a handful of merge fields reliably, and a forty-line timeline much less so. Save a template, then let the agent supply the values. Set Merge Fields Source to JSON so it can hand over the whole list at once.
Give the agent the writing rules, and this node for the render. Shotstack publishes what a model needs to write a valid edit: the full documentation as one text file, and the agent skill. Link to either from the Agent node's system message, or let the agent read it with an HTTP Request tool. Both stay current on their own, which a copy inside this node would not.
The defaults that read the previous step do not apply in tool mode. Render
ID defaults to {{ $json.renderId || $json.id }}. On the canvas that reads the
previous node. When an AI Agent calls the node, $json is the agent's own
arguments, so the default finds nothing. Set each field the agent must supply to
{{ $fromAI('renderId') }} or similar, so n8n asks the model for it by name.
Merge every field, or send none. A partial merge replaces the template's stored list. It does not add to it. A field the agent leaves out is not filled in from the template. Text then renders as a raw placeholder, and an image or video placeholder fails the render. Fill any gaps from the template's own defaults before you send. See Templates.
See the n8n template library. Those templates use the plain HTTP Request node, because n8n's template library accepts built-in nodes only. The API calls are identical. This node removes the wiring.
Tested against n8n 2.35. Requires Node.js 20.19 or later; n8n 2.x itself asks for 22.22 or later.
- Shotstack documentation
- Edit API reference
- Generative AI assets
- Serve API
- Shotstack CLI
- n8n community nodes
Found a bug? Open an issue and include the render ID. It lets Shotstack look up the exact job instead of guessing from a description.
Do not open a public issue for a problem that could expose an API key or someone's rendered files. Use private vulnerability reporting on the repository Security tab, or email support@shotstack.io.