Skip to content
usefy

useUserMedia

Browser & device

Camera and microphone streams — getUserMedia lifecycle, device switching, torch, and a teardown you can rely on.

Install

$ npm install @usefy/use-user-media

Quick start

useUserMedia.tsx
import { useUserMedia } from "@usefy/use-user-media";

function CameraPreview() {
  const camera = useUserMedia({ facingMode: "environment" });

  if (camera.status === "unsupported") return <p>No camera here.</p>;
  if (camera.status === "denied") return <p>{camera.error?.message}</p>;

  return camera.stream ? (
    <video
      ref={(element) => {
        if (element) element.srcObject = camera.stream;
      }}
      autoPlay
      playsInline
      muted
    />
  ) : (
    <button onClick={camera.start}>Start camera</button>
  );
}

API reference

useUserMedia(options?)

Options

OptionTypeDefaultDescription
constraintsMediaStreamConstraints{ video: true }What to request
autoStartbooleanfalseAcquire on mount
facingMode"user" | "environment"Preferred camera; merged as a preference, not exact
deviceIdstringOpen one specific device (as exact)
onStream(stream) => voidCalled whenever a new stream becomes available
onError(error: UserMediaError) => voidCalled when acquisition fails

Changing facingMode or deviceId while a stream is live re-acquires automatically — the usual way to build a "flip camera" button.

Returns

FieldTypeDescription
streamMediaStream | nullThe live stream
statusUserMediaStatusidle · prompting · granted · denied · unsupported · error
errorUserMediaError | nullCleared by a successful start()
isSupportedbooleanWhether this environment can open a stream at all
start()() => Promise<MediaStream | null>Request (or re-request) a stream
stop()() => voidStop every track. Safe to call repeatedly
devicesMediaDeviceInfo[]Video inputs — empty until permission is granted once
activeDeviceIdstring | nullThe device the current stream came from
selectDevice(id)(id) => Promise<MediaStream | null>Open a specific device
switchDevice()() => Promise<MediaStream | null>Cycle to the next camera
isTorchSupportedbooleanWhether the active camera reports a torch
torchbooleanCurrent torch state
setTorch(on)(on) => Promise<boolean>Resolves false if the camera refused

UserMediaError

{ name: "UserMediaError", reason, message, cause } where reason is one of denied · not-found · in-use · over-constrained · unsupported · unknown.

Helpers

isUserMediaSupported(), isEnumerationSupported(), stopStream(), supportsTorch(), activeDeviceIdOf(), withVideoPreferences(), toUserMediaError().

Go deeper

This page is the quick reference. For every example, prop, and edge case, read the full README — or open Storybook to change props live.

More in browser & device