Skip to content
Salah Adawi Salah Adawi
remotion fix video tutorial

Fixing Remotion's "Visited http://localhost but got no response"

Remotion renders dying with "Visited http://localhost:PORT/index.html but got no response"? The three flags that made my renders finish every time, and why a single frame test saves you.

Salah Adawi

Salah Adawi

3 min read

I render all my YouTube Shorts programmatically with Remotion, and for a while my renders kept dying with this:

Visited http://localhost:3000/index.html but got no response.

The port number changes between runs, because Remotion’s bundler picks a free one each time. The rest is always the same: no stack trace, nothing useful in the output above it. The port answers if you open it in a browser yourself, and the render still fails the same way on the next run. If you’re hitting this error, here’s the setup that made it go away for me.

The fix

Render single-threaded, point Remotion at your installed Chrome instead of its downloaded browser, and pin the port:

npx remotion render remotion/index.ts MyComposition out/video.mp4 \
  --browser-executable="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
  --concurrency=1 --port=3340

On Windows or Linux, swap the path for wherever Chrome lives on your machine.

Three things change here. --concurrency=1 turns off the pool of parallel browser pages Remotion normally renders with, and that pool is where my failures lived. --browser-executable skips the headless browser Remotion downloads for itself and uses the Chrome you already trust. --port stops the bundler from picking a fresh random port every run.

Honest caveat: I can’t tell you which of the three flags is the real cure, because I stopped experimenting the moment renders became boring. With all three, not a single failure since. Single-threaded rendering is slower, and a slow render that finishes beats a fast one that dies at 80%.

Bake it into a script so you never think about it again

If you render more than one composition, put the flags in a script instead of your shell history:

// scripts/render.mjs
import { execSync } from "node:child_process";

const CHROME =
  process.env.REMOTION_BROWSER ||
  "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";

for (const [id, out] of [["MyComposition", "out/video.mp4"]]) {
  execSync(
    `npx remotion render remotion/index.ts ${id} ${out} ` +
      `--browser-executable="${CHROME}" --concurrency=1 --port=3340`,
    { stdio: "inherit" },
  );
}

The env override matters on shared projects, since your Chrome path won’t match your teammate’s.

Test with a still before you render

One more habit that pairs well with flaky renders: before a full render, render a single frame.

npx remotion still remotion/index.ts MyComposition out/check.png

A still takes seconds and hits the same code path, so it catches a broken composition, a missing asset, or this same connection problem before you’ve committed minutes to a full render. When the still works and the render doesn’t, you know the problem is the render pool and not your code, which is exactly the situation the flags above are for.

Back to Blog
Share:

Related Posts