Installation

Install wasmpeg and get a first decode running — npm or CDN, in a bundler, a framework, or Node, with no build step and no special server headers.

wasmpeg ships as an ES module with the WASM binaries alongside it. No build step, no SharedArrayBuffer, no COOP/COEP headers, and no worker setup are required.

Quick install

  1. Install the package.

    npm install wasmpeg
    pnpm add wasmpeg
    yarn add wasmpeg
    bun add wasmpeg

    Use wasmpeg-full instead if you need H.264/H.265 encode (GPL) — see which package.

  2. Import it and load the module once.

    import wasmpeg from 'wasmpeg';
    
    await wasmpeg.load();
    

    load() fetches and initializes the WASM. It’s safe to call again — later calls resolve immediately.

  3. Decode something.

    const info = await wasmpeg.probe(file);   // File / Blob / URL / Uint8Array
    const dec = await wasmpeg.decode(file);
    const frame = dec.nextFrame();            // Uint8ClampedArray of RGBA8
    dec.close();
    

That’s the whole setup. From here, the quick start covers decode, scale, probe, audio, and thumbnails.

Which package

The import surface is identical between them; only the codec set differs. Code written against wasmpeg runs unchanged against wasmpeg-full — you only swap the package when you specifically need x264/x265 encode and can meet the GPL terms.

wasmpegwasmpeg-full
LicenseLGPL-2.1-or-laterGPL-2.0-or-later
H.264 / H.265 decodeYesYes
H.264 / H.265 encodeNoYes (libx264 / libx265)
Use for closed-sourceYesOnly under GPL terms
Import surfaceIdenticalIdentical

Loading the module

load() does three things: detects the environment, picks a build, and instantiates the WASM. You await it once before any other call.


await wasmpeg.load();

It’s idempotent — call it from every module that needs wasmpeg if that’s simpler than threading a “ready” flag around; only the first call does real work. The same is true of the gpu namespace and the FFmpeg class, which share the one module instance.

If a browser can’t instantiate the module (no WebAssembly SIMD support), the failure surfaces as a rejected load() promise, before any decode runs. Wrapping the first load() in a try/catch is the simplest capability check — see Browser support.

Serving the WASM

The package contains dist/cpu.js and dist/cpu.wasm (plus webgpu.js / webgpu.wasm for the GPU build). At runtime, the .js loads its .wasm from the same directory. How that directory is served depends on your setup:

Most bundlers (Vite, webpack 5, Rollup, esbuild) handle the co-located .wasm automatically when you import wasmpeg from 'wasmpeg'. If your bundler doesn’t emit the .wasm next to the JS, copy node_modules/wasmpeg/dist/ into your static directory and point the loader at it:

await wasmpeg.load({ wasmPath: '/wasmpeg/cpu.js' });   // cpu.wasm sits beside it

See the framework guides for per-tool specifics.

<script type="module">
    import wasmpeg from 'https://esm.sh/wasmpeg';
    await wasmpeg.load();
    const info = await wasmpeg.probe(file);
</script>

Any ESM CDN that serves the package and its dist/*.wasm works (esm.sh, jsDelivr, unpkg). The .wasm is fetched relative to the JS module.

import wasmpeg from 'wasmpeg';
import { readFile } from 'node:fs/promises';

await wasmpeg.load();
const bytes = await readFile('clip.mp4');
const info = await wasmpeg.probe(bytes);

Node has no WebGPU adapter, so the CPU build is used automatically, and the .wasm is read from disk rather than fetched.

The wasmPath option

load() accepts { wasmPath } — a URL to the loader .js, with the matching .wasm expected in the same directory. Reach for it when your bundler fingerprints or relocates assets and the default same-directory resolution can’t find the binary. Point it at the .js file; the loader derives the .wasm name from it.

// Serving the dist folder yourself at /vendor/wasmpeg/
await wasmpeg.load({ wasmPath: '/vendor/wasmpeg/cpu.js' });

If you’ve copied the WebGPU build instead, point at webgpu.js. When wasmPath is omitted, the loader chooses webgpu.js where navigator.gpu exists and cpu.js otherwise.

The one thing that goes wrong
99% of setup issues are the browser failing to fetch cpu.wasm (a 404 in the network tab). The fix is always the same: make sure the .wasm is served next to the .js, or pass an explicit wasmPath. See Troubleshooting.

Requirements

  • Browsers — any with WebAssembly + SIMD128: Chrome 91+, Firefox 89+, Safari 16.4+. WebGPU scaling additionally needs a WebGPU-capable browser; everything else falls back to CPU. Full matrix in Browser support.
  • Node — ≥ 18 (uses built-in fetch/fs; no native addons).

No headers, no cross-origin isolation, and no Web Worker are required. wasmpeg runs on an ordinary static host and on the main thread (or any worker you choose to put it in).

Verify the install

A quick end-to-end check that the package resolved and the WASM loads:


await wasmpeg.load();
console.log('wasmpeg loaded');   // if this prints, the module instantiated

If load() rejects in the browser, it’s almost always one of two things: the runtime lacks SIMD (an old browser), or the .wasm 404’d. The network tab tells you which.

Next steps