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.

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.

Appendix: 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)