The official React wrapper for the Camera Kit Web SDK. It provides declarative components and hooks that handle SDK bootstrapping, session lifecycle, media sources, and Lens management — so you can integrate Snap AR into React apps with minimal boilerplate.
npm install @snap/react-camera-kit @snap/camera-kit@snap/camera-kit^1.13.0(peer dependency)react>=16.8.0andreact-dom>=16.8.0rxjs>=7https://for deployed apps (http://localhostworks for local development)
You'll need a Camera Kit API token, Lens ID, and Lens Group ID from the Snap Developer Portal. See Setting Up Accounts if you're new to Camera Kit.
import { CameraKitProvider, LensPlayer } from "@snap/react-camera-kit";
function App() {
return (
<CameraKitProvider apiToken="YOUR_API_TOKEN">
<LensPlayer lensId="YOUR_LENS_ID" lensGroupId="YOUR_LENS_GROUP_ID" />
</CameraKitProvider>
);
}That's it — CameraKitProvider initializes the SDK, and LensPlayer sets up the camera, applies the Lens, and renders the output canvas.
The root provider that initializes the Camera Kit SDK. All other components and hooks must be descendants of this provider.
import { CameraKitProvider, createConsoleLogger } from "@snap/react-camera-kit";
<CameraKitProvider apiToken="YOUR_API_TOKEN" logger={createConsoleLogger()} logLevel="info">
{children}
</CameraKitProvider>;| Prop | Type | Default | Description |
|---|---|---|---|
apiToken |
string |
required | Camera Kit API token |
logger |
CameraKitLogger |
noopLogger |
Logger instance — use createConsoleLogger() for development |
logLevel |
"debug" | "info" | "warn" | "error" |
"info" |
Log verbosity |
renderWhileTabHidden |
boolean |
false |
Continue rendering when the browser tab is hidden |
stabilityKey |
string | number |
auto | Manual control over when the SDK re-initializes |
extendContainer |
(container) => container |
— | Customize the SDK's DI container |
createBootstrapEventHandler |
MetricEventHandlerFactory |
— | Factory for tracking bootstrap success/failure |
All-in-one component that handles source setup, Lens application, and playback. Defaults to the user's camera if no source is provided.
<LensPlayer lensId="YOUR_LENS_ID" lensGroupId="YOUR_LENS_GROUP_ID" className="camera-canvas" />| Prop | Type | Default | Description |
|---|---|---|---|
lensId |
string |
— | Lens to apply |
lensGroupId |
string |
— | Lens Group containing the Lens |
source |
SourceInput |
{ kind: "camera" } |
Media source (camera, video, or image) |
outputSize |
OutputSize |
— | Rendering canvas size |
lensLaunchData |
LensLaunchData |
— | Launch parameters passed to the Lens |
lensReadyGuard |
() => Promise<void> |
— | Async guard called while Lens is loading (2s timeout) |
refreshTrigger |
unknown |
— | When this value changes, the Lens is removed and reapplied |
canvasType |
"live" | "capture" |
"live" |
Which canvas to render. For custom layouts, use LiveCanvas/CaptureCanvas as children instead |
fpsLimit |
number |
— | Maximum rendering framerate |
muted |
boolean |
false |
Mute audio output |
screenRegions |
ScreenRegions |
— | Screen regions for Lens-aware UI layout |
onError |
(error, lens) => void |
— | Callback for playback errors |
className |
string |
— | CSS class name |
style |
CSSProperties |
— | Inline styles |
children |
ReactNode |
— | Custom children (use with LiveCanvas/CaptureCanvas) |
Render the live preview or capture canvas as children of LensPlayer:
<LensPlayer lensId="YOUR_LENS_ID" lensGroupId="YOUR_LENS_GROUP_ID">
<div>
<LiveCanvas style={{ width: "100%" }} />
</div>
<div>
<CaptureCanvas style={{ width: "100%" }} />
</div>
</LensPlayer>Both accept className and style props.
Access the full Camera Kit context — SDK status, source/Lens state, and imperative methods. Must be called within a CameraKitProvider.
import { useCameraKit } from "@snap/react-camera-kit";
function Controls() {
const { sdkStatus, lens, lenses, isMuted, toggleMuted, applyLens, removeLens, fetchLenses } = useCameraKit();
if (sdkStatus !== "ready") return <p>Loading SDK...</p>;
return (
<div>
<p>Lens: {lens.lensId ?? "None"}</p>
<button onClick={toggleMuted}>{isMuted ? "Unmute" : "Mute"}</button>
<button onClick={removeLens}>Remove Lens</button>
</div>
);
}State properties:
| Property | Type | Description |
|---|---|---|
sdkStatus |
"uninitialized" | "initializing" | "ready" | "error" |
SDK initialization status |
sdkError |
Error | undefined |
Error from SDK initialization |
source |
CurrentSource |
Current source status, input, and error |
lens |
CurrentLens |
Current Lens status, IDs, and error |
lenses |
Lens[] |
Array of loaded Lens objects |
liveCanvas |
HTMLCanvasElement | undefined |
Live preview canvas element |
captureCanvas |
HTMLCanvasElement | undefined |
Capture canvas element |
keyboard |
Keyboard | undefined |
Keyboard API for Lens keyboard requests |
isMuted |
boolean |
Whether audio is muted |
fpsLimit |
number | undefined |
Current FPS limit |
screenRegions |
ScreenRegions | undefined |
Current screen regions |
Methods:
| Method | Description |
|---|---|
applySource(input, size?) |
Apply a media source (camera, video, or image) |
removeSource() |
Remove the current source |
fetchLens(lensId, groupId) |
Load a single Lens (returns cached if already loaded) |
fetchLenses(groupId) |
Load all Lenses in a group (accepts string or string[]) |
applyLens(lensId, groupId, launchData?, readyGuard?) |
Apply a Lens by ID |
removeLens() |
Remove the current Lens |
refreshLens() |
Remove and reapply the current Lens |
reinitialize() |
Re-bootstrap the SDK (useful after errors) |
setMuted(muted) |
Set the muted state |
toggleMuted() |
Toggle audio mute |
setFPSLimit(fps) |
Set maximum rendering FPS |
setScreenRegions(regions) |
Set screen regions for Lens-aware layout |
Declaratively apply a Lens — it updates automatically when parameters change.
import { useApplyLens } from "@snap/react-camera-kit";
useApplyLens("YOUR_LENS_ID", "YOUR_LENS_GROUP_ID");| Parameter | Type | Description |
|---|---|---|
lensId |
string | undefined |
Lens ID — pass undefined to remove |
lensGroupId |
string | undefined |
Lens Group ID |
lensLaunchData |
LensLaunchData |
Optional launch parameters |
lensReadyGuard |
() => Promise<void> |
Optional async ready guard |
Declaratively apply a media source. Defaults to camera if no source is provided.
import { useApplySource } from "@snap/react-camera-kit";
// Video source with fixed output size
useApplySource({ kind: "video", url: "/demo.mp4", autoplay: true }, { mode: "fixed", width: 720, height: 1280 });| Parameter | Type | Default | Description |
|---|---|---|---|
source |
SourceInput |
{ kind: "camera" } |
Media source |
outputSize |
OutputSize |
— | Rendering size |
Declaratively set playback options.
import { usePlaybackOptions } from "@snap/react-camera-kit";
usePlaybackOptions({
fpsLimit: 30,
muted: false,
onError: (error) => console.error("Playback error:", error),
});| Option | Type | Description |
|---|---|---|
fpsLimit |
number |
Maximum rendering FPS |
muted |
boolean |
Mute audio |
screenRegions |
ScreenRegions |
Screen regions for Lens layout |
onError |
(error, lens) => void |
Playback error callback |
Pass a SourceInput to LensPlayer's source prop or to useApplySource:
// Camera (default)
{ kind: "camera" }
{ kind: "camera", deviceId: "abc123", options: { cameraFacing: "environment" } }
// Video
{ kind: "video", url: "/demo.mp4", autoplay: true }
// Image
{ kind: "image", url: "/photo.jpg" }| Option | Type | Default | Description |
|---|---|---|---|
cameraFacing |
"user" | "environment" |
"user" |
Front or back camera |
cameraConstraints |
MediaTrackConstraints |
{ width: 1280, height: 720 } |
Camera resolution constraints |
cameraRotation |
0 | -90 | 90 | 180 |
0 |
Camera rotation |
fpsLimit |
number |
— | Max FPS for the source |
outputSize |
OutputSize |
— | Rendering canvas size |
// Fixed resolution
{ mode: "fixed", width: 720, height: 1280 }
// Match input source resolution
{ mode: "match-input" }Use useCameraKit() to track the status of the SDK, source, and Lens. Each progresses through "none" → "loading" → "ready" (or "error"):
function Preview() {
const { sdkStatus, sdkError, source, lens } = useCameraKit();
if (sdkStatus === "error") return <p>SDK failed: {sdkError?.message}</p>;
if (sdkStatus !== "ready") return <p>Initializing...</p>;
if (source.status === "loading") return <p>Setting up camera...</p>;
if (lens.status === "error") return <p>Lens error: {lens.error?.message}</p>;
return (
<LensPlayer lensId="YOUR_LENS_ID" lensGroupId="YOUR_LENS_GROUP_ID">
{lens.status !== "ready" && <div className="spinner" />}
<LiveCanvas />
</LensPlayer>
);
}import { CameraKitProvider, LensPlayer, LiveCanvas, useCameraKit } from "@snap/react-camera-kit";
import { useEffect } from "react";
const LENS_GROUP_ID = "YOUR_LENS_GROUP_ID";
function LensSwitcher() {
const { sdkStatus, lenses, lens, fetchLenses, applyLens, isMuted, toggleMuted, reinitialize, sdkError } =
useCameraKit();
useEffect(() => {
if (sdkStatus === "ready") fetchLenses(LENS_GROUP_ID);
}, [sdkStatus]);
if (sdkStatus === "error") {
return (
<div>
<p>SDK error: {sdkError?.message}</p>
<button onClick={reinitialize}>Retry</button>
</div>
);
}
return (
<div>
<select value={lens.lensId ?? ""} onChange={(e) => applyLens(e.target.value, LENS_GROUP_ID)}>
<option value="" disabled>
Select a Lens
</option>
{lenses.map((l) => (
<option key={l.id} value={l.id}>
{l.name}
</option>
))}
</select>
<button onClick={toggleMuted}>{isMuted ? "Unmute" : "Mute"}</button>
<LensPlayer lensId={lens.lensId} lensGroupId={LENS_GROUP_ID}>
<LiveCanvas style={{ width: "100%", maxWidth: 640 }} />
</LensPlayer>
</div>
);
}
export default function App() {
return (
<CameraKitProvider apiToken="YOUR_API_TOKEN">
<LensSwitcher />
</CameraKitProvider>
);
}| Export | Description |
|---|---|
createConsoleLogger() |
Returns a logger that prints to the browser console |
createNoopLogger() |
Returns a silent logger (default) |
isCameraSource(source) |
Type guard for CameraSourceInput |
isVideoSource(source) |
Type guard for VideoSourceInput |
isImageSource(source) |
Type guard for ImageSourceInput |
CameraRotationOptions |
Valid rotation values: [0, -90, 90, 180] |
npm install # Install dependencies
npm run build # Build ESM + CJS
npm run watch # Build in watch mode
npm run typecheck # Type checking
npm test # Run tests
npm run clean # Clean dist folderA Vite demo app is available in demo/:
npm run demo:install
cp demo/.env.example demo/.env
npm run demo:devWe welcome contributions! Please see our Contributing Guidelines for details.