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→MergeandGet 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
outputsentries 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
statusiscompletedand 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
}
}