@polotno/node-red-polotno-studio 0.1.0
Node-RED nodes for Polotno Studio — render images and videos from templates.
@polotno/node-red-polotno-studio
Node-RED nodes for rendering images and videos from Polotno Studio templates, listing templates, and reacting to render events with webhooks.
Installation
In the Node-RED editor, open the menu and choose Manage palette → Install, then search for @polotno/node-red-polotno-studio and click Install.
You can also install it from the command line inside your Node-RED user directory (usually ~/.node-red):
npm install @polotno/node-red-polotno-studio
Restart Node-RED afterwards if you installed from the command line.
Credentials
All Polotno nodes share a Polotno Studio config node that holds your connection settings:
- API Key — required. In Polotno Studio, open the project selector and choose Manage projects, then copy the project's key (it starts with
key_live_…). Each key is bound to a single project. The key is stored in Node-RED's encrypted credentials store, not in the flow JSON, so it is not included when you export or share a flow. - Base URL — defaults to
https://api.studio.polotno.comand rarely needs changing. - Public URL — optional, and only used by the polotno webhook node (see Webhooks below). Leave it blank if you don't use that node.
Click Verify connection on the config node to confirm the key works. On success it shows project name (live) or project name (test) depending on the key's mode; on failure it shows the error returned by the API.
Nodes
Polotno Studio (config node)
Holds the API key, base URL, and public URL described above. Every other node references one of these.
polotno render
Renders an image or video from a template.
Node settings: the Connection (config node), Render kind (Image or Video), a Template (populated from your project once a connection is chosen), the template's Fields (rendered dynamically based on the template's dynamic fields), output Format (png/jpeg/pdf for images, mp4/gif for video), image-only Pixel ratio and Transparent background, video-only FPS and Duration (s), an optional Text overflow override (shrink/grow/truncate), optional JSON Metadata, and a Wait for the render to finish toggle with a Max wait (s) budget.
Inputs — all optional, and each overrides the corresponding node setting:
msg.payload.templateId(string) — use a different template than the one selected on the node.msg.payload.fields(object) — field values keyed by flat key (e.g.fields__headline__text); merged over the node's own field values, taking precedence.msg.payload.idempotencyKey(string) — sent as theIdempotency-Keyheader. Replaying the same key within 24 hours returns the original result instead of rendering again.
Outputs — this node has two outputs:
- Completed (or submitted, when Wait is off) —
msg.payloadis the render object, withimage_urlorvideo_urlset once it has completed. - Failed or timed out —
msg.payloadis the last known render, andmsg.payload.statusexplains why.msg.polotno.timedOutistruewhen the wait budget ran out rather than the render actually failing — see Waiting for renders.
polotno get render
Fetches a single render by id — useful for checking on a render later, e.g. after a timeout.
Node settings: Connection and Type (Image or Video — must match the kind of id you're looking up).
Input: msg.payload.id, the render id (img_… or vid_…). A bare string payload is also accepted.
Output: msg.payload is the render object. Check msg.payload.status — it may still be pending or processing if the render hasn't finished yet.
Rendered assets expire after 7 days; the render object's expires_at field carries the deadline.
polotno templates
Reads templates. Templates are read-only through the API — create and edit them in the Polotno Studio editor.
Node settings: Connection and an Operation:
- List templates — also exposes a Name filter (matches templates by name; this is separate from the node's own display Name field at the top of the settings), Tag, Created after (only templates created after this ISO 8601 timestamp), Limit, Return all (follow pagination cursors), Max pages, Include archived only, and Omit design JSON (leaves out each template's design payload so list responses stay small; on by default).
- Get template and Get dynamic fields — both use a Template ID, which
msg.payload.templateIdoverrides.
Output: msg.payload is an array of templates for List, an array of field definitions for Get dynamic fields, or a single template object for Get.
Return all follows pagination cursors until they run out, but stops at Max pages and logs a warning if more results remain, so a large template library never gets silently truncated.
polotno webhook
Emits a message whenever a render (or template) event happens, instead of polling. See Webhooks for setup details.
Node settings: Connection, a Path (default polotno-events) that combines with the config node's Public URL, and a set of Events to subscribe to (defaults to image.completed and video.completed; also available: image.failed, video.failed, template.created, template.updated).
Output, one message per event:
msg.payload— the render (or template) the event is about, in the same shape the polotno get render node returns.msg.polotno.eventType— e.g.image.completedorvideo.failed.msg.polotno.eventId— the event id; use it to de-duplicate redeliveries.
Waiting for renders
With Wait for the render to finish enabled, image renders first attempt a fast synchronous path (up to about 30 seconds); if that doesn't finish in time, the node falls back to polling. Video renders are always asynchronous and are polled from the start.
With Wait disabled, output 1 fires immediately with whatever status the API returns (usually pending) — that's the expected fire-and-forget result, not a failure.
A timeout is not the same as a failure: when msg.polotno.timedOut is true on output 2, the render is very likely still running server-side. Feed its id into a polotno get render node later to check on it, or use a polotno webhook node to be notified as soon as it finishes.
Webhooks
The polotno webhook node lets Polotno Studio push events to your flow instead of you polling for them. Because Node-RED cannot discover its own external address, you must set Public URL on the config node to the HTTPS address this Node-RED instance is reachable at from the internet; Polotno Studio will POST to that URL plus the node's Path.
On deploy, the node automatically creates a webhook subscription with Polotno Studio for the selected events; when the node is deleted or the flow is redeployed, it removes that subscription again.
Every delivery is verified against the subscription's signing secret and rejected — with the details logged as a node warning — if the signature is missing, invalid, or older than five minutes. Polotno Studio also retries a failed delivery up to seven times over 24 hours, which means deliveries can arrive more than once; de-duplicate on msg.polotno.eventId if that matters to your flow.
Credits and limits
Renders consume Polotno Studio credits:
- An image costs 1 credit, or 3 for PDF output, or for any image whose output size (after pixel ratio) exceeds 3000×3000.
- A video costs 1 credit per second of duration, rounded up. Frame rate does not affect the cost.
- A failed render is free, and renders made with a test-mode API key are free.
Rendered assets expire after 7 days — the URLs in image_url/video_url are not permanent, so download or re-host anything you need to keep.
API rate limits are per project and depend on your plan (for example, 60 requests/minute on the free tier, rising on paid plans). These nodes automatically respect the API's Retry-After header and retry rate-limited requests, so you generally don't need to handle 429s yourself.
Development
To run these nodes against a local Node-RED, see LOCAL.md.
Compatibility
Requires Node-RED >=3.0.0 and Node.js >=18.
License
MIT — see LICENSE.