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.
Requires a provider
All hooks on this page expect a <BodyTrackerProvider> somewhere above them in the tree, constructed once with your BodyTrackerConfig. Calling a hook outside a provider throws at render time.
useTracking()
Hooksince v1.0.0The 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.
function useTracking(): UseTrackingResultReturns
UseTrackingResult — An object with the tracker's status plus imperative start and stop callbacks.
| Parameter | Type | Description |
|---|---|---|
statusRequired | TrackerStatus | The 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 | null | The most recent error thrown by start() or stop(), or null if there wasn't one. |
Example
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.0Reads 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().
function useSession(): UseSessionResultReturns
UseSessionResult — The active session (or null), session controls, and a recording flag.
| Parameter | Type | Description |
|---|---|---|
sessionRequired | Session | null | The 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 | boolean | true when session.status === "recording". |
Example
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.0Exposes 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.
function useCamera(): UseCameraResultReturns
UseCameraResult — The active MediaStream, available devices, and controls for selecting one.
| Parameter | Type | Description |
|---|---|---|
streamRequired | MediaStream | null | The tracker's active camera stream, or null before init() resolves. |
devicesRequired | MediaDeviceInfo[] | All video input devices available to the browser. |
selectedDeviceIdRequired | string | null | The deviceId currently in use, matching BodyTrackerConfig.cameraDeviceId if one was set. |
selectDeviceRequired | (deviceId: string) => void | Switches the active camera to the given device id. |
permissionRequired | "granted" | "denied" | "prompt" | The current camera permission state reported by the browser. |
Example
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.0Subscribes 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.
function useActivity(): UseActivityResultReturns
UseActivityResult — The current activity, its quality, and a short history of recent snapshots.
| Parameter | Type | Description |
|---|---|---|
currentActivityRequired | ActivityType | The most recently detected activity. |
qualityRequired | QualityLevel | The current tracking quality for the active camera view. |
historyRequired | ActivitySnapshot[] | The most recent activity snapshots, oldest first, capped to a fixed rolling window. |
Example
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.0Subscribes 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.
function useEvents<T = unknown>(event: TrackerEventName, handler: (payload: T) => void): voidParameters
| Parameter | Type | Description |
|---|---|---|
eventRequired | TrackerEventName | The event name to subscribe to. |
handlerRequired | (payload: T) => void | Called with the event's payload. Pass a type parameter to useEvents<T> to type it precisely. |
Returns
void — This hook has no return value — its effect is the subscription itself.
Example
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.0Aggregates 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.
function useAnalytics(): UseAnalyticsResultReturns
UseAnalyticsResult — Aggregate stats computed from all sessions recorded under the current API key.
| Parameter | Type | Description |
|---|---|---|
totalSessionsRequired | number | The total number of completed sessions. |
totalMinutesRequired | number | The sum of every completed session's duration, in minutes. |
mostFrequentActivityRequired | ActivityType | null | The activity recorded most often, or null if no sessions have completed yet. |
averageQualityRequired | QualityLevel | The average tracking quality across all completed sessions. |
Example
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> );}