BT

React Hooks

@bodytracker/react wraps a shared BodyTracker instance with hooks that read tracker state reactively instead of polling the imperative methods in the API Reference. Every hook below reads from the same underlying tracker, provided once near the root of your component tree.

useTracking()

Hooksince v1.0.0

The primitive hook for driving the tracker's lifecycle from a component: exposes the current status, start/stop callbacks that wrap init() and startSession()/stopSession(), and any error thrown along the way. Most other hooks build on the same underlying tracker instance this hook reads from.

TypeScript
function useTracking(): UseTrackingResult

Returns

UseTrackingResultAn object with the tracker's status plus imperative start and stop callbacks.

ParameterTypeDescription
statusRequired
TrackerStatusThe tracker's current lifecycle status, re-rendering the component on every change.
startRequired
() => Promise<void>Initializes the tracker (if needed) and starts a session with default options.
stopRequired
() => Promise<void>Stops the active session.
errorRequired
Error | nullThe most recent error thrown by start() or stop(), or null if there wasn't one.

Example

TrackingButton.tsxTSX
import { useTracking } from "@bodytracker/react"; export function TrackingButton() {  const { status, start, stop, error } = useTracking();   return (    <div>      <button        onClick={status === "tracking" ? stop : start}        disabled={status === "initializing"}      >        {status === "tracking" ? "Stop tracking" : "Start tracking"}      </button>      {error && <p role="alert">{error.message}</p>}    </div>  );}

useSession()

Hooksince v1.0.0

Reads the currently active tracking session, if any, and exposes callbacks to start and stop one with full StartSessionOptions control (activity type, label) — a more configurable alternative to useTracking()'s bare start()/stop().

TypeScript
function useSession(): UseSessionResult

Returns

UseSessionResultThe active session (or null), session controls, and a recording flag.

ParameterTypeDescription
sessionRequired
Session | nullThe current session, or null if none is active.
startSessionRequired
(options?: StartSessionOptions) => Promise<Session>Starts a new session with the given activity and label.
stopSessionRequired
() => Promise<SessionSummary>Stops the active session and resolves with its summary.
isRecordingRequired
booleantrue when session.status === "recording".

Example

SessionRecorder.tsxTSX
import { useSession } from "@bodytracker/react"; export function SessionRecorder() {  const { session, startSession, stopSession, isRecording } = useSession();   return (    <div>      <button        onClick={() =>          isRecording ? stopSession() : startSession({ activity: "walking", label: "Evening walk" })        }      >        {isRecording ? "End session" : "Start session"}      </button>      {session && <p>Session {session.id}{session.status}</p>}    </div>  );}

useCamera()

Hooksince v1.2.0

Exposes the raw camera stream backing the tracker along with the list of available video input devices, so you can render a live preview or build a device picker without touching getUserMedia directly.

TypeScript
function useCamera(): UseCameraResult

Returns

UseCameraResultThe active MediaStream, available devices, and controls for selecting one.

ParameterTypeDescription
streamRequired
MediaStream | nullThe tracker's active camera stream, or null before init() resolves.
devicesRequired
MediaDeviceInfo[]All video input devices available to the browser.
selectedDeviceIdRequired
string | nullThe deviceId currently in use, matching BodyTrackerConfig.cameraDeviceId if one was set.
selectDeviceRequired
(deviceId: string) => voidSwitches the active camera to the given device id.
permissionRequired
"granted" | "denied" | "prompt"The current camera permission state reported by the browser.

Example

CameraPreview.tsxTSX
import { useRef, useEffect } from "react";import { useCamera } from "@bodytracker/react"; export function CameraPreview() {  const { stream, devices, selectedDeviceId, selectDevice, permission } = useCamera();  const videoRef = useRef<HTMLVideoElement>(null);   useEffect(() => {    if (videoRef.current) videoRef.current.srcObject = stream;  }, [stream]);   if (permission === "denied") return <p>Camera access is required to track movement.</p>;   return (    <div>      <video ref={videoRef} autoPlay muted playsInline />      <select value={selectedDeviceId ?? ""} onChange={(e) => selectDevice(e.target.value)}>        {devices.map((d) => (          <option key={d.deviceId} value={d.deviceId}>            {d.label || "Camera"}          </option>        ))}      </select>    </div>  );}

useActivity()

Hooksince v1.2.0

Subscribes to activityChanged and qualityChanged internally and exposes the current activity, current tracking quality, and a rolling history of recent activity snapshots — the reactive counterpart to calling getActivity() imperatively.

TypeScript
function useActivity(): UseActivityResult

Returns

UseActivityResultThe current activity, its quality, and a short history of recent snapshots.

ParameterTypeDescription
currentActivityRequired
ActivityTypeThe most recently detected activity.
qualityRequired
QualityLevelThe current tracking quality for the active camera view.
historyRequired
ActivitySnapshot[]The most recent activity snapshots, oldest first, capped to a fixed rolling window.

Example

ActivityBadge.tsxTSX
import { useActivity } from "@bodytracker/react"; export function ActivityBadge() {  const { currentActivity, quality, history } = useActivity();   return (    <div>      <span>{currentActivity}</span>      <span data-quality={quality}>{quality}</span>      <small>{history.length} recent samples</small>    </div>  );}

useEvents()

Hooksince v2.0.0

Subscribes handler to a tracker event for the lifetime of the component, calling tracker.on() on mount and the returned unsubscribe function automatically on unmount or whenever event/handler change. Use this instead of calling tracker.on()/off() directly inside useEffect.

TypeScript
function useEvents<T = unknown>(event: TrackerEventName, handler: (payload: T) => void): void

Parameters

ParameterTypeDescription
eventRequired
TrackerEventNameThe event name to subscribe to.
handlerRequired
(payload: T) => voidCalled with the event's payload. Pass a type parameter to useEvents<T> to type it precisely.

Returns

voidThis hook has no return value — its effect is the subscription itself.

Example

MovementLogger.tsxTSX
import { useState } from "react";import { useEvents } from "@bodytracker/react"; interface ActivityChangedPayload {  from: string;  to: string;  timestamp: string;} export function MovementLogger() {  const [log, setLog] = useState<string[]>([]);   useEvents<ActivityChangedPayload>("activityChanged", (payload) => {    setLog((prev) => [...prev, `${payload.from} -> ${payload.to}`]);  });   return (    <ul>      {log.map((entry, i) => (        <li key={i}>{entry}</li>      ))}    </ul>  );}

useAnalytics()

Hooksince v3.0.0

Aggregates historical session data for the current API key into summary analytics — total sessions, total tracked minutes, the most frequent activity, and an overall average quality — useful for dashboards and progress views.

TypeScript
function useAnalytics(): UseAnalyticsResult

Returns

UseAnalyticsResultAggregate stats computed from all sessions recorded under the current API key.

ParameterTypeDescription
totalSessionsRequired
numberThe total number of completed sessions.
totalMinutesRequired
numberThe sum of every completed session's duration, in minutes.
mostFrequentActivityRequired
ActivityType | nullThe activity recorded most often, or null if no sessions have completed yet.
averageQualityRequired
QualityLevelThe average tracking quality across all completed sessions.

Example

AnalyticsSummary.tsxTSX
import { useAnalytics } from "@bodytracker/react"; export function AnalyticsSummary() {  const { totalSessions, totalMinutes, mostFrequentActivity, averageQuality } = useAnalytics();   return (    <dl>      <dt>Sessions</dt>      <dd>{totalSessions}</dd>      <dt>Total time tracked</dt>      <dd>{totalMinutes} min</dd>      <dt>Most frequent activity</dt>      <dd>{mostFrequentActivity ?? "—"}</dd>      <dt>Average quality</dt>      <dd>{averageQuality}</dd>    </dl>  );}