KINOPIPE WITH NODE.JS

Video editing from Node.js, without FFmpeg on your machine.

Trim, resize, compress, convert, caption and transcribe by calling one HTTP endpoint per operation. Parameters are validated before anything renders, so a bad call fails as a typed error rather than a broken encode.

What running FFmpeg from Node usually costs

  • On Vercel, Netlify or Lambda there is no binary to spawn and no room to ship one, so the whole approach stops before it starts.
  • fluent-ffmpeg wraps a process, and the process still needs FFmpeg installed with the right build flags for libass, libx264 or whatever the task needs.
  • A render inside a request handler competes with the requests you are meant to be serving.

Trim a clip and wait for the file

Node.js
const KINOPIPE = 'https://kinopipe.com/api/v1'
const headers = {
  authorization: `Bearer ${process.env.KINOPIPE_API_KEY}`,
  'content-type': 'application/json',
}

async function run(tool, inputs, options = {}) {
  const started = await fetch(`${KINOPIPE}/tools/${tool}`, {
    method: 'POST',
    headers,
    body: JSON.stringify({ inputs, options }),
  })
  if (!started.ok) throw new Error(`${tool} was rejected: ${await started.text()}`)
  const { jobId } = await started.json()

  for (;;) {
    const job = await fetch(`${KINOPIPE}/jobs/${jobId}`, { headers }).then((r) => r.json())
    if (job.status === 'succeeded' || job.status === 'failed') return job
    await new Promise((resolve) => setTimeout(resolve, 2000))
  }
}

const job = await run(
  'trim-video',
  [{ id: 'main', url: 'https://example.com/interview.mp4' }],
  { start: 12, end: 48 },
)

if (job.status === 'failed') throw new Error(job.errorMessage ?? 'the job did not finish')
console.log(job.result.output.downloadUrl)
  • No dependency: fetch is built in from Node 18, and nothing above needs a package.
  • The same code runs in an edge function, because the encode happens elsewhere and the handler only makes HTTP calls.
  • Send an Idempotency-Key header when you retry, and the retry returns the original job instead of paying for a second render.
Or let an agent write the call
The same operations are exposed over MCP, so an agent in your editor discovers them and calls them directly.

FAQ

Does this work on Vercel and Lambda?

Yes, and that is usually the reason to reach for it. The handler makes HTTP calls and holds no binary, so the size limit and the missing FFmpeg both stop being problems.

What about fluent-ffmpeg?

fluent-ffmpeg is a good wrapper when you control the machine and can install FFmpeg on it. This is for when you cannot, or when you would rather not have a render inside your request path.

Can I avoid polling?

Yes. Pass a webhook with the job and the result is posted to you when it is ready.