remotion-dev/remotion · error · Error

getAudioData() is only available in the browser.

Error message

getAudioData() is only available in the browser.

What it means

Thrown by getAudioData() when the global `document` is undefined (line 23). The function needs a real browser to create an AudioContext and run fetch().decodeAudioData(), so it refuses to run in Node, SSR, or any non-DOM environment. The guard fires before any audio work happens, so the error is purely about where the call executed.

Source

Thrown at packages/media-utils/src/get-audio-data.ts:24

const metadataCache: {[key: string]: MediaUtilsAudioData} = {};

const limit = pLimit(3);

type Options = {
	sampleRate?: number;
	requestInit?: RequestInit;
};

const fn = async (
	src: string,
	options?: Options,
): Promise<MediaUtilsAudioData> => {
	if (metadataCache[src]) {
		return metadataCache[src];
	}

	if (typeof document === 'undefined') {
		throw new Error('getAudioData() is only available in the browser.');
	}

	const audioContext = new AudioContext({
		sampleRate: options?.sampleRate ?? 48000,
	});

	const response = await fetchWithCorsCatch(src, options?.requestInit);
	if (!response.ok) {
		throw new Error(
			`Failed to fetch audio data from ${src}: ${response.status} ${response.statusText}`,
		);
	}

	const arrayBuffer = await response.arrayBuffer();

	const wave = await audioContext.decodeAudioData(arrayBuffer);

	const channelWaveforms = new Array(wave.numberOfChannels)

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Only call getAudioData() inside Remotion components (which render in a Chromium browser) or client-only code guarded by typeof window !== 'undefined'.
  2. If you need audio metadata server-side, switch to Mediabunny's metadata API (see docs/mediabunny/metadata) which is not DOM-bound.
  3. In tests, configure jsdom/happy-dom or run the test in the Remotion testbed browser; do not run getAudioData under plain Node.
  4. For Next.js/Remix, mark the calling component 'use client' or move the call into a useEffect so it only runs after hydration in the browser.

Example fix

// before (runs on server, throws)
import {getAudioData} from '@remotion/media-utils';
export async function getStaticProps() {
  const data = await getAudioData('/song.mp3');
  return {props: {data}};
}

// after (client-only)
import {useAudioData} from '@remotion/media-utils';
export default function Player() {
  const data = useAudioData(staticFile('song.mp3'));
  return <Audio src={staticFile('song.mp3')} />;
}
Defensive patterns

Strategy: validation

Validate before calling

// Browser-environment guard before calling the DOM-dependent helper
import {getAudioData} from '@remotion/media-utils';

async function safeGetAudioData(src: string) {
  if (typeof document === 'undefined' || typeof window === 'undefined') {
    // skip server-side; only run in a real browser
    return null;
  }
  return getAudioData(src);
}

Type guard

const hasBrowserAudio = (): boolean =>
  typeof document !== 'undefined' &&
  typeof window !== 'undefined' &&
  typeof window.AudioContext !== 'undefined';

Try / catch

try {
  const data = await getAudioData(src);
} catch (err) {
  if ((err as Error).message.includes('only available in the browser')) {
    // SSR path: skip or compute metadata server-side via Mediabunny
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Calling getAudioData(src) from a Node script, a server-side React render (Next.js getStaticProps, Remix loader), Jest/Node tests without jsdom, or any module-eval that runs the function at import time on the server.

Common situations: Importing @remotion/media-utils into a Next.js app and calling getAudioData() in a server component; running unit tests under Node without a DOM polyfill; server-side pre-rendering that tries to compute audio waveforms; calling it inside getStaticProps/getServerSideProps.

Related errors


AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12). Data as JSON: /api/errors/39527050fff6c993. Report an issue: GitHub.