n8n + FFmpegAPI
This guide walks you through a minimal but complete n8n workflow that matches the screenshot and the downloadable template:
- Pick a GIF using a form
- Get an upload URL
- Upload the binary
- Process it to MP4
- Show a final download link
Copy your FFmpegAPI key from the dashboard, you’ll need it to in the n8n workflow.
Choose your path
⚡ Quick Start
Import the ready-made workflow
FFMPEG_API_KEY
in n8n Variables🛠️ Manual Setup
Build from scratch for full understanding
Detailed instructions: See the Manual Setup section below
Manual Setup: Build the Workflow Step by Step
Choose this path if you want full control and understanding of the workflow.
What you’ll build
An n8n workflow that mirrors the exported JSON:
- Select a GIF in a form node (“Attach file”)
- Get an upload URL from our API
- Merge inputs (file + upload URL)
- Upload the file bytes to the pre‑signed URL
- Start an FFmpeg processing task (GIF → MP4)
- Show a completion screen with the final download URL
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 Variables to store your API key as FFMPEG_API_KEY
(the template references $vars.FFMPEG_API_KEY
).
- Open the Variables panel in n8n
- Create:
FFMPEG_API_KEY
- Value: your live API key (from the FFmpegAPI Dashboard)
Build the workflow step by step
1) Form trigger: Attach file
- Add a Form Trigger node named
Attach file
- Configure a single field:
- Label:
file
- Type:
file
- Accept:
.gif
- Required:
true
- Label:
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 {{$vars.FFMPEG_API_KEY}}
Content-Type: application/json
- Body: JSON
Body JSON:
{
"file_name": "{{ $item(\"0\").$node[\"Attach file\"].json[\"file\"][\"filename\"] }}"
}
Expected response shape:
{
"file": { "file_path": "<dir>/input.gif" },
"upload": { "url": "https://...", "method": "PUT" }
}
3) Merge (combine)
- Add a Merge node named
Merge
- Mode:
combine
→combineAll
- Connect
Attach file
→Merge
andGet Upload URL
→Merge
4) Upload File (HTTP Request)
- Add an HTTP Request node named
Upload File
- Method:
{{ $('Get Upload URL').item.json.upload.method }}
- URL:
{{ $('Get Upload URL').item.json.upload.url }}
- Send:
Binary
- Binary Property:
file
(from the form trigger) - Do not add Authorization headers for the presigned URL
4) Start processing (HTTP Request)
Add an HTTP Request node named Process File
:
- Method:
POST
- URL:
https://api.ffmpeg-api.com/ffmpeg/process
- Headers:
Authorization: Basic {{$vars.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": "{{ $('Get Upload URL').item.json.file.file_path }}" }
],
"outputs": [{ "file": "output.mp4" }]
}
}
Response contains the completed result with download URLs.
6) Completion screen (Form)
- Add a Form node named
Download URL
- Operation:
completion
- Message:
Please download the file: [Download]({{ $json.body.result[0].download_url }})
Common variations
- Multiple outputs: add more
outputs
entries in the process body - 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.gif" }],
"outputs": [{ "file": "output.mp4" }]
}
}
Example completed task response:
{
"ok": true,
"result": [
{
"file_name": "output.mp4",
"size_bytes": 1234567,
"download_url": "https://..."
}
],
"usage": {
"gb_sec": 0.45,
"time_sec": 3.2
}
}