n8n + FFmpegAPI
This guide walks you through a minimal but complete n8n workflow:
- Upload a file to FFmpeg API
- Run a processing task (e.g., convert to MP4 or change codec/CRF)
- Download the result and store it (Filesystem, S3, Google Drive, etc.)
No prior experience with FFmpeg or n8n required.
You’ll need an FFmpeg API key. In production, never hardcode secrets; store them in environment variables or n8n Credentials.
What you’ll build
An n8n workflow triggered by a manual run or a Webhook:
-
Get an upload URL from our API
-
Upload the input file bytes to the returned pre‑signed URL
-
Start an FFmpeg processing task
-
Download the result and save it
Overview diagram
API endpoints used
- POST
/file
→ returns{ upload.url, file.file_path }
- PUT
upload.url
→ uploads your bytes - POST
/ffmpeg/process
→ starts a task and returns the result with download URLs
See also: Quick Start, Processing, Examples.
Prepare credentials in n8n
Use n8n’s Credentials to store your API key as FFMPEG_API_KEY
.
- Create a new Environment Variable or Generic Credential in n8n
- Name:
FFMPEG_API_KEY
- Value: your live API key (found in Dashboard)
Build the workflow step by step
1) Trigger node
- Add a Manual Trigger (for tests) or a Webhook node (for automation)
- If using Webhook, set HTTP Method to
POST
and expect a file URL or base64 input in the payload
2) Get upload URL (HTTP Request)
- Add an HTTP Request node named
Get Upload URL
- Method:
POST
- URL:
https://api.ffmpeg-api.com/file
- Headers:
Authorization: Basic {{$env.FFMPEG_API_KEY}}
Content-Type: application/json
- Body: JSON
Body JSON (if you already know the filename):
{
"file_name": "input.mp4"
}
Expected response shape:
{
"file": { "file_path": "<dir>/input.mp4" },
"upload": { "url": "https://...presigned-url..." }
}
3) Upload bytes (Binary upload)
There are two common patterns for getting the input bytes into n8n:
- If you have a public file URL: add an HTTP Request node to
GET
the file withDownload
enabled → a binary property (e.g.,data
) becomes available - If your trigger contains base64: use Move Binary Data to create a binary property from base64
Now add another HTTP Request node named Upload to Presigned URL
:
- Method:
PUT
- URL:
={{$json["upload"]["url"]}}
(use the expression editor to reference the previous node’s output) - Send:
Binary
- Binary Property:
data
(or the property you created) - Do not set Authorization headers; presigned URLs typically do not require them
4) Start processing (HTTP Request)
Add an HTTP Request node named Start Processing
:
- Method:
POST
- URL:
https://api.ffmpeg-api.com/ffmpeg/process
- Headers:
Authorization: Basic {{$env.FFMPEG_API_KEY}}
Content-Type: application/json
- Body: JSON
Minimal body example that re-encodes input to MP4 with a target quality:
{
"task": {
"inputs": [{ "file_path": "={{$json["file"]["file_path"]}}" }],
"outputs": [
{ "file": "output.mp4", "options": ["-c:v", "libx264", "-crf", "23"] }
]
}
}
Response contains the completed result with download URLs.
5) Download the result
Use the first result’s download_url
from the previous step:
- Add HTTP Request node named
Download Result
- Method:
GET
- URL:
={{$json["result"][0]["download_url"]}}
- Download:
true
(to store as binary) - Binary Property:
result
6) Save the file
Choose any storage node. Common options:
- Write Binary File (local n8n host)
- S3: set credentials, bucket, and
Binary Property
=result
- Google Drive: use
Upload
withBinary Property
=result
Common variations
- Multiple outputs: add more
outputs
entries in the process body - Different formats: change encoder and extension (e.g.,
libx265
+output.hevc.mp4
) - Thumbnails or GIFs: use
-vf scale
,fps
, or palette filters; see Recipes
Troubleshooting
If you see 401/403 errors, verify the Authorization header, and ensure your API key is present in n8n credentials as FFMPEG_API_KEY
.
- Upload PUT fails: ensure you are sending Binary data and not JSON
- Task stuck in queued: try smaller inputs or verify your plan limits
- Download empty: confirm
status
iscompleted
and pick the correctresult[index]
Full example payloads
Request to /ffmpeg/process
:
{
"task": {
"inputs": [
{ "file_path": "<dir>/input.mp4" }
],
"outputs": [
{ "file": "output.mp4", "options": ["-c:v", "libx264", "-crf", "23"] }
]
}
}
Example completed task response:
{
"status": "completed",
"result": [
{
"file": "output.mp4",
"download_url": "https://..."
}
]
}
Next steps
- Add a Webhook trigger to accept file URLs from your app
- Add branching (IF node) to pick different FFmpeg options per input size
- Chain follow‑up steps: notify via Slack/Email with result link