Shipping Async Video Background Removal at $0.10/sec
Why async matters for video
I've been running useKnockout - a background removal API that processes images in ~200ms - for a few months. Images are fast enough to handle synchronously: POST a file, wait 200ms, get a PNG back. Video is different. Even a 5-second clip at 30fps is 150 frames. At 200ms per frame, that's 30 seconds of processing. You can't hold an HTTP connection open for 30 seconds and call it a good API.
So today I shipped POST /video/remove - async video background removal that returns a job ID immediately, processes in the background, and gives you ProRes 4444 (RGB+alpha) when it's done.
What shipped
As of v0.11.0 (July 10, 2026):
POST /video/remove- upload a video, get a job ID backGET /jobs/{job_id}- poll for status, download the result when ready- ProRes 4444 output - RGB with full alpha channel, ready to drop into Premiere/Final Cut/DaVinci
- Node SDK
videoRemove()andgetJob()in v0.7.0 - Python SDK
video_remove()andget_job()in v0.7.0
Billing is a dedicated video.seconds meter at $0.10/sec (different from the per-image rate), with a 15-second cap to keep costs predictable.
How to use it (Node SDK)
import { useKnockout } from 'useknockout-node';
import fs from 'fs';
const client = useKnockout({ apiKey: process.env.KNOCKOUT_API_KEY });
// Submit the video
const job = await client.videoRemove({ file: fs.createReadStream('./input.mp4') });
console.log('Job ID:', job.id);
// Poll until done
let status = await client.getJob(job.id);
while (status.status === 'processing') {
await new Promise(resolve => setTimeout(resolve, 2000));
status = await client.getJob(job.id);
}
if (status.status === 'completed') {
// Download the ProRes 4444 result
const video = await fetch(status.result_url);
const buffer = await video.arrayBuffer();
fs.writeFileSync('./output.mov', Buffer.from(buffer));
}
The job object includes duration_seconds (billed amount), status (processing / completed / failed), and result_url when done.
Billing: $0.10/sec, 15s cap
Video uses its own meter (video.seconds) so you can track image vs. video usage separately. A 7-second clip costs $0.70. Clips longer than 15 seconds are trimmed (the 15s cap keeps runaway bills from killing indie projects).
For context, useKnockout's image endpoint is ~$0.005/image on the starter tier - about 40x cheaper than remove.bg's $0.11โ$0.23/image. Video is more expensive per second of processing, but still priced for solo builders.
Other recent additions
Before video, I shipped:
POST /collage(July 3) - N-photo product collages, billed N units. Pass 4 product shots, get a 2ร2 grid back.- RealESRGAN upscaling (July 2) - default upscale switched to RealESRGAN with refined alpha matting and linear compositing.
studio-shotenhance (June 22) - GFPGAN face restoration now available on/studio-shotwithenhance=true.
All of these shipped in the last month because the API is self-hostable (MIT-licensed) and I'm the only one shipping it - no committee, no quarters, just daily commits.
Why this matters
Most indie devs I talk to are either:
- Paying remove.bg [placeholder: $X/mo] and wincing at the bill, or
- Avoiding background removal features entirely because the APIs are too expensive.
Video makes it worse - remove.bg doesn't do video at all. Other video APIs charge per frame (30fps ร 5sec = 150 frames ร $0.10 = $15 for 5 seconds). At $0.10/sec, that same 5-second clip costs $0.50. Still not free, but it's in "I can actually ship this feature" territory.
What's next
I'm working on batch video (submit 10 clips, get 10 job IDs back) and a webhook callback option so you don't have to poll. The async job pattern is solid now - those are just API surface.
If you're building something that needs video background removal (marketplace demos, avatar videos, TikTok filters, whatever), the SDKs are on npm/PyPI and the API is at useknockout.com. Free tier includes 10 images/month across 5 endpoints. Video is pay-as-you-go. No lock-in - it's MIT-licensed if you want to self-host.
But the hosted version is live and you can start with a curl:
curl -X POST https://useknockout--api.modal.run/video/remove \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "file=@input.mp4"
You'll get a job ID back. Poll /jobs/{id} until it's done, then download the ProRes file. That's it.
Comments
No comments yet. Start the discussion.