Dozor
@kharko/dozor-react

useDozor()

useDozor() returns the recorder instance with reactive state properties. Call it from any component below <DozorProvider> to read state or invoke methods.

import { useDozor } from "@kharko/dozor-react";

function MyComponent() {
  const dozor = useDozor();

  // dozor.state, dozor.isRecording, dozor.bufferSize — reactive
  // dozor.hold(), dozor.release(), dozor.identify() — methods

  return null;
}

The hook throws if called outside a <DozorProvider> — it's not expected to be used optionally. If you need optional integration, guard at the provider level.

State shape

All state properties are reactive — they update via useSyncExternalStore whenever the recorder fires a change notification.

PropertyTypeNotes
state"not_initialized" | "idle" | "recording" | "paused"Includes "not_initialized" (only meaningful when options was omitted from the provider). After stop() / cancel() the recorder returns to "idle" — there is no terminal "stopped" variant.
sessionIdstring | nullnull before init() and after stop() / cancel() until the next start().
isRecordingbooleanConvenience for state === "recording".
isPausedbooleantrue whenever state === "paused" — covers both manual pause() and auto-pause from tab visibility.
isHeldbooleanTrue between hold() and release().
userIdstring | nullFrom identify(), null otherwise.
bufferSizenumberReflects the value at the last state-change notification — does not update in real-time as rrweb emits.

Note on bufferSize cadence: the underlying SDK fires state-change notifications on lifecycle transitions (start, pause, hold, etc.), not on every captured event. So bufferSize is "fresh enough for a status indicator" but not "frame-perfect". If you genuinely need per-event granularity, subscribe via dozor.subscribe() directly.

Method shape

Same surface as the core SDK — see Methods for full descriptions:

init (manual-init flows) · start · pause · resume · stop · cancel · hold · release · identify

Common patterns

Status indicator

function RecordingBadge() {
  const dozor = useDozor();

  if (!dozor.isRecording) return null;

  return <span className="badge">● Recording — {dozor.bufferSize} events</span>;
}

Wire identify into your auth

function IdentifyOnLogin() {
  const dozor = useDozor();
  const { user } = useAuth();

  useEffect(() => {
    if (user) {
      dozor.identify(user.id, { email: user.email, plan: user.plan });
    }
  }, [user, dozor]);

  return null;
}

Conditional recording

function CheckoutFlow() {
  const dozor = useDozor();
  // Provider was set up with `options.hold: true` — buffer fills,
  // nothing ships yet.
  return (
    <>
      <button
        onClick={() => {
          submitOrder();
          dozor.release();
        }}
      >
        Complete purchase
      </button>
      <button onClick={() => dozor.cancel()}>Leave</button>
    </>
  );
}

See Recipes for more patterns.

On this page