remotion-dev/remotion · error · Error

getImageDimensions() is only available in the browser.

Error message

getImageDimensions() is only available in the browser.

What it means

Thrown by getImageDimensions() when `document` is undefined (line 14). The function constructs a DOM `Image()` and waits for onload to read width/height, so it requires a browser environment.

Source

Thrown at packages/media-utils/src/get-image-dimensions.ts:14

import {pLimit} from './p-limit';
import type {ImageDimensions} from './types';

const imageDimensionsCache: {[key: string]: ImageDimensions} = {};

const limit = pLimit(3);

const fn = async (src: string): Promise<ImageDimensions> => {
	if (imageDimensionsCache[src]) {
		return imageDimensionsCache[src];
	}

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

	const imageDimensions = await new Promise<ImageDimensions>(
		(resolved, reject) => {
			const image = new Image();

			image.onload = () => {
				const {width, height} = image;
				resolved({width, height});
			};

			image.onerror = reject;

			image.src = src;
		},
	);

	imageDimensionsCache[src] = imageDimensions;

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Call getImageDimensions() only inside Remotion components or other client code that runs in a browser.
  2. For server-side dimension reads, use a Node image library (e.g. sharp, image-size, probe-image-size) instead of this DOM-based helper.
  3. In tests, set the environment to jsdom/happy-dom or load a real image asset the polyfill can decode.
  4. Guard the call site with typeof document !== 'undefined' to skip it during SSR.

Example fix

// before (throws in Node SSR)
import {getImageDimensions} from '@remotion/media-utils';
export async function getStaticProps() {
  const dims = await getImageDimensions('/hero.png');
  return {props: {dims}};
}

// after (server uses sharp; client keeps the hook)
// server
import sharp from 'sharp';
const {width, height} = await sharp(file).metadata();
// client (Remotion)
const dims = await getImageDimensions(staticFile('hero.png'));
Defensive patterns

Strategy: validation

Validate before calling

import {getImageDimensions} from '@remotion/media-utils';

async function safeGetImageDimensions(src: string) {
  if (typeof document === 'undefined') {
    // server-side: prefer sharp/probe-image-size here
    return null;
  }
  return getImageDimensions(src);
}

Type guard

const canUseDomImage = (): boolean => typeof document !== 'undefined' && typeof Image !== 'undefined';

Try / catch

try {
  const dims = await getImageDimensions(src);
} catch (err) {
  if ((err as Error).message.includes('only available in the browser')) {
    // server path: use sharp/probe-image-size instead
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Calling getImageDimensions() during SSR, in a Node build step, in Node-based tests, or in any non-browser runtime; calling it at module top level so it runs at import time on the server.

Common situations: Computing layout dimensions for images at build time; Next.js getStaticProps trying to size remote images; server-side rendered galleries; CI scripts that try to inspect image dimensions for validation.

Related errors


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