This n8n workflow automates Cloudinary image-to-video generation from a tagged source image and a prompt. It gives media teams a repeatable no-code process that creates, tracks, and stores the finished video beside its source.
The upload: a 728×546 WebP, 26 KB.
The sentence: Slow cinematic push-in with subtle parallax and slight lateral drift.
The result: the subjects and framing are preserved; the camera does the work.
Watch the real MP4 in the Cloudinary Video Player
Eleven n8n nodes, with no code. The generation call is one HTTP request. The workflow defines which uploads qualify, where the prompt lives, how the asynchronous job is tracked, and how to find the video later.
What you'll build
- Trigger Cloudinary image-to-video generation from an upload.
- Control eligibility with tags and metadata.
- Poll an asynchronous generation job safely.
- Tag the source image and return an embeddable video URL.
- Import and adapt the n8n workflow.
What decides that an upload becomes a video
Every rule below is a choice this example made, not a requirement of the API. All three live in a single Eligible? IF node, so swap them for whatever your own pipeline keys off: a folder path, an upload preset, a structured metadata field, a public ID prefix, or the uploading user. What matters is that the check happens once, in one place, and that everything failing it stops there.
| Field | Condition | Why |
|---|---|---|
resource_type |
is image
|
Video uploads land in the same notification stream and would otherwise loop. |
tags |
contains video_gen
|
This is the opt-in. |
context.custom.prompt |
is not empty | This is the direction for the shot. |
So the interface here is a tag plus a text field. Contextual metadata is editable in the Media Library, in the Upload API, and through the Admin API, so the prompt can come from a human, a spreadsheet, or another workflow. Nobody has to open n8n. If your prompts are house style rather than per-image direction, drop the context condition and hard-code the sentence in the next node instead.
The full prompt value on the image above, second sentence included:
Slow cinematic push-in with subtle parallax and slight lateral drift. Preserve the image exactly—no new objects or altered details.
Everything else is set once, in one node
The remaining parameters are fixed in the request body, so changing the house look for every future video is a single edit. resolution takes 720p or 1080p, duration takes 4, 6, or 8 seconds, and aspect_ratio takes auto, 16:9, or 9:16. The image-to-video API reference has the rest.
{
"prompt": $json.context.custom.prompt,
"image_asset_id": $json.asset_id,
"duration": 4,
"resolution": "720p",
"aspect_ratio": "auto",
"generate_audio": false,
"enhance_prompt": true
}
How the n8n Cloudinary image-to-video workflow works
The poll loop is the long connector running back from Give Up? to Wait 15s. Everything above that line is the happy path.
Eleven nodes, front to back:
- Webhook: Cloudinary POSTs here on every upload. Register the production URL as your notification endpoint once and forget it.
-
Get Asset: Fetches the full asset record by
asset_id. The notification payload is thin; tags and context are read from here. - Eligible?: The three conditions above, combined with AND. The false branch is deliberately unwired; most uploads stop here.
-
Start Generation: POSTs the JSON above to the image-to-video endpoint and gets back a
job_id. Generation is asynchronous. - Wait 15s: n8n suspends the execution rather than holding a worker open.
-
Poll Job: GETs the job by ID and reads
data.status. -
Completed?: On
completed, go forward. Anything else goes to the give-up check. -
Give Up?: Errors out on
failed, or when$runIndex >= 20. Otherwise it loops back to Wait 15s. - Stop and Error: Fails the execution with the job ID and last-seen status, so the n8n execution log tells you which asset to retry.
-
Tag Source Image: Appends
video_gen_doneto the source image. This is the idempotency marker and the audit trail. - Video Player URL: Builds a Cloudinary Video Player embed URL for the finished asset, muted, looping, and fluid, ready to paste into a CMS.
Watch this line.
$runIndex >= 20in Give Up? is the only thing between you and an infinite poll loop. Twenty polls at 15 seconds is a five-minute ceiling. Raise it for longer clips; do not remove it.
Delivering the result
The generated MP4 is 1.25 MB at source. Adding f_auto and q_auto as the last two components of the delivery URL takes it to 436 KB and lets the CDN pick the codec per browser: AV1 or VP9 where supported, H.264 everywhere else.
# video
https://<cloud>.cloudinary.com/video/upload/c_limit,w_1280/f_auto/q_auto/v1787656854/image-to-video/i2v_9f3d....mp4
# source image
https://<cloud>.cloudinary.com/image/upload/c_limit,w_800/f_auto/q_auto/v1787656781/n8n-demo/couple-meme.webp
# poster frame, pulled from the video at t=0
https://<cloud>.cloudinary.com/video/upload/c_limit,w_1280/so_0/f_auto/q_auto/v1787656854/image-to-video/i2v_9f3d....jpg
| MP4 at source | 1.25 MB (1280×720, 4s) |
With q_auto
|
436 KB, 65% smaller |
| Poll ceiling | 5 min (20 × 15s) |
| Nodes | 11, zero code nodes |
c_limit caps the width without ever upscaling, so an asset smaller than the requested width is delivered untouched. Keep f_auto out of named and incoming transformations: format selection has to resolve per request, at the edge.
Or skip the URL building entirely
The last node returns a Video Player embed URL, with the playback options already folded in as query parameters. It is a page you can open, link, or drop straight into a CMS embed field; no <video> element or player script is needed.
https://player.cloudinary.com/embed/?cloud_name=<cloud>&public_id=image-to-video%2Fi2v_9f3d...&player[loop]=true&player[muted]=true&player[fluid]=true
The player[…] keys map one-to-one onto the node's playback and layout fields, so the muted, looping, fluid-width behaviour is configured in n8n rather than in your front end.
Import the n8n Cloudinary image-to-video workflow
- Download the workflow JSON and import it through Workflows → Import from File.
- Install the Cloudinary node for n8n: in a new n8n flow, search the nodes panel for Cloudinary, select the integration, and click Install node.
- Create two credentials and re-select them on the nodes marked
REPLACE_ME: a Cloudinary API credential for the three Cloudinary nodes, and an HTTP Basic Auth credential for the two HTTP Request nodes. Its username is your API key and its password is your API secret. - Replace
YOUR_CLOUD_NAMEin the URLs on Start Generation and Poll Job. - Open Eligible? and set the conditions to your own rules: the tag name, the metadata field, or whatever else decides that an upload should become a video.
- Copy the production webhook URL and add it in the Cloudinary Console under Settings → Upload → Notification URL.
- Press Cmd/Ctrl+S to save, then activate the workflow. An unsaved workflow will not fire.
- Upload an image with the
video_gentag and apromptcontext value.
Where to take it
-
Aspect-ratio presets by tag. Branch on
video_gen_9x16orvideo_gen_1x1and setaspect_ratioper branch, so social formats come out of the same upload. - Write the result back. Add a node that stores the video's public ID in the source image's context. The pairing then survives outside n8n's execution log.
- Structured metadata instead of context. A structured metadata field gives the prompt validation and a proper label in the Media Library UI.
-
Backfill. Point the Search API at
tags=video_gen AND -tags=video_gen_doneand feed the results into the same chain to catch everything tagged before the workflow existed. - Tell someone. A Slack node after Video Player URL posts the player link to the channel that asked for the video.
Get a cloud to run it on
Everything here works on a free account. Sign up, then find the cloud name, API key, and secret on your dashboard. If an agent is doing the setup, it can provision its own environment instead:
npx @cloudinary/cloud
The command writes working credentials to .env with no signup. Delivery is locked to the IP the command ran from, and the cloud expires in 24 hours unless someone claims it with an email address. At that point the same credentials become permanent. The agent quickstart covers the claim step and the IP flags.
Resources
- Workflow JSON: Cloudinary — Image to Video (tag: video_gen), import-ready, credentials stripped.
- n8n integration: Cloudinary node for n8n: installation, credentials, and supported operations.
- API reference: Image-to-video API: every parameter the Start Generation node sends.
- Docs: Video optimization · Upload notifications · Video Player embed
- Free account: cloudinary.com/users/register_free
-
For agents: Claimable clouds:
npx @cloudinary/cloud, no signup.
| Cloudinary ❤️ developers |
|---|
| Ready to level up your media workflow? Start using Cloudinary for free and build better visual experiences today. |
| 👉 Create your free account |



Top comments (1)
the demo tho. LOL