Download Reels
Node.js 18+ • Streams API • 7 min read

Download Videos & Streams in JavaScript & Node.js (Fetch API & Streams)

Building high-performance video downloaders in JavaScript requires understanding Streams, chunk processing, memory buffering, and CORS restrictions. Here is how to implement client-side and server-side video saving.

Need a fast client-side downloader?

Download Reels runs pure client-side resolvers right in your browser.

Try Online Tool →

1. Client-Side Browser Streaming with Fetch & Blob

In browser environments, downloading a large video file into memory via await response.blob() can freeze the UI or exhaust mobile memory. Using response.body.getReader() provides progressive download feedback:

async function downloadVideoWithProgress(videoUrl, filename = "video.mp4") {
  const response = await fetch(videoUrl);
  if (!response.ok) throw new Error(`HTTP ${response.status}`);

  const contentLength = response.headers.get("content-length");
  const totalBytes = contentLength ? parseInt(contentLength, 10) : 0;
  
  const reader = response.body.getReader();
  const chunks = [];
  let receivedBytes = 0;

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    
    chunks.push(value);
    receivedBytes += value.length;

    if (totalBytes > 0) {
      const percent = Math.round((receivedBytes / totalBytes) * 100);
      console.log(`Progress: ${percent}%`);
    }
  }

  // Create Blob URL and trigger browser save
  const blob = new Blob(chunks, { type: "video/mp4" });
  const downloadUrl = URL.createObjectURL(blob);
  
  const a = document.createElement("a");
  a.href = downloadUrl;
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  
  setTimeout(() => URL.revokeObjectURL(downloadUrl), 5000);
}

2. Node.js Stream Piping with pipeline()

On the backend with Node.js, never buffer video files in memory. Use stream/promises pipeline to stream directly from the HTTP socket to the filesystem:

import fs from 'node:fs';
import { pipeline } from 'node:stream/promises';
import { Readable } from 'node:stream';

async function streamVideoToFile(videoUrl, outputPath) {
  const response = await fetch(videoUrl, {
    headers: {
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0 Safari/537.36'
    }
  });

  if (!response.ok) throw new Error(`Fetch failed with status ${response.status}`);

  // Convert Web ReadableStream to Node.js Readable stream
  const nodeStream = Readable.fromWeb(response.body);
  const fileWriter = fs.createWriteStream(outputPath);

  await pipeline(nodeStream, fileWriter);
  console.log(`✅ Saved video to ${outputPath}`);
}

// Example usage:
streamVideoToFile('https://example.com/stream.mp4', './output.mp4');

3. Overcoming CORS in Static Frontends

Browser frontends hosted on static servers (like GitHub Pages) cannot make direct requests to Instagram or Facebook video endpoints because those servers do not emit Access-Control-Allow-Origin: *.

Solutions for production:

  • Direct CORS APIs: APIs like TikWM (TikTok) and Piped (YouTube) provide CORS-friendly streaming endpoints.
  • Serverless Edge Proxies: Deploy a Cloudflare Worker or Vercel Edge Function with custom CORS headers to stream video headers directly.

Related Guides: