ZCamera
React component that renders a native iOS camera preview with hardware-backed C2PA signing.
Usage
import { useRef } from "react";
import { ZCamera, type CaptureInfo } from "@succinctlabs/react-native-zcam1";
function CameraScreen({ captureInfo }: { captureInfo: CaptureInfo }) {
const camera = useRef<ZCamera>(null);
return (
<ZCamera
ref={camera}
captureInfo={captureInfo}
position="back"
isActive={true}
zoom={2.0}
style={{ flex: 1 }}
/>
);
}Props
captureInfo (required)
- Type:
CaptureInfo
Capture information from initCapture(). Required for C2PA signing. See initCapture Returns for details.
position
- Type:
"front" | "back" - Default:
"back"
Which camera to use.
isActive
- Type:
boolean - Default:
true
Whether the camera is actively running.
captureFormat
- Type:
"jpeg" | "dng" - Default:
"jpeg"
Desired capture format. When set to "dng", captures RAW DNG file while still producing a C2PA-signed JPEG copy.
zoom
- Type:
number - Default:
2.0(back),1.0(front)
Zoom factor. For devices with ultra-wide lens:
1.0= ultra-wide (0.5x user-facing)2.0= wide-angle (1x user-facing)
Use getMinZoom() and getMaxZoom() methods to determine valid range.
torch
- Type:
boolean - Default:
false
Whether torch (flashlight) is enabled during preview.
exposure
- Type:
number - Default:
0
Exposure compensation in EV units.
filmStyle
- Type:
CameraFilmStyle|string - Default:
"normal"
Film style preset to apply to camera. You can specify a built-in option or a custom film style you defined in customFilmStyles.
filmStyleOverrides
- Type:
Partial<Record<CameraFilmStyle, FilmStyleRecipe>> - Optional
Override built-in film style presets with custom recipes. When a preset name is used with filmStyle prop and an override exists, the custom recipe is applied instead.
<ZCamera
filmStyle="mellow"
filmStyleOverrides={{
mellow: [
{ type: "whiteBalance", config: { temperature: 7000, tint: 30 } },
{ type: "saturation", value: 1.3 },
{ type: "contrast", value: 0.85 },
]
}}
/>customFilmStyles
- Type:
Record<string, FilmStyleRecipe> - Optional
Define additional custom film styles by name. Reference them using the filmStyle prop.
<ZCamera
filmStyle={"myVintage" as CameraFilmStyle}
customFilmStyles={{
myVintage: [
{ type: "whiteBalance", config: { temperature: 6800 } },
{ type: "vibrance", value: 0.6 },
{ type: "highlightShadow", config: { highlights: 0.2, shadows: 0.5 } },
]
}}
/>See FilmStyleEffect for all available effect types.
captureTimestampEnabled
- Type:
boolean - Default:
false
When true, a trusted GPS timestamp is embedded in the C2PA manifest at capture time. The timestamp is sourced from GPS rather than the device clock, making it tamper-evident. Requires location permission. Stored as trustedTimestamp in PhotoMetadataInfo / VideoMetadataInfo.
captureLocationEnabled
- Type:
boolean - Default:
false
When true, GPS coordinates are embedded in the C2PA manifest at capture time. Requires location permission. Stored as location (LocationInfo) in photo/video metadata. If retrieval fails, AuthenticityData.isLocationAvailable is set to false and locationRetrievalStatus contains the error reason.
depthEnabled
- Type:
boolean - Default:
false
Enable depth data capture at session level. When true, depth data can be captured but zoom may be restricted on dual-camera devices.
onOrientationChange
- Type:
(orientation: DeviceOrientation) => void - Optional
Callback fired when the device physical orientation changes. Uses accelerometer data, so it works even when iOS orientation lock is enabled. Useful for rotating UI controls to match the device orientation.
<ZCamera
captureInfo={captureInfo}
onOrientationChange={(orientation) => {
// orientation: "portrait" | "landscapeLeft" | "landscapeRight" | "portraitUpsideDown"
console.log("Device orientation:", orientation);
}}
/>See DeviceOrientation for the type definition.
certChain
- Type:
SelfSignedCertChain|ExistingCertChain - Optional
Certificate chain for signing the C2PA manifest. If not provided, a self-signed certificate is automatically generated.
// Self-signed (default)
type SelfSignedCertChain = {
signingAlgorithm?: string; // Default: "ES256"
tsaUrl?: string; // Optional timestamp authority URL
}
// Existing certificate
type ExistingCertChain = {
pem: string; // Certificate chain in PEM format
}// Use self-signed (automatic)
<ZCamera captureInfo={captureInfo} />
// Or provide custom certificate
<ZCamera
captureInfo={captureInfo}
certChain={{ pem: customCertChainPem }}
/>style
- Type:
StyleProp<ViewStyle> - Optional
Style for the underlying native view.
Methods
takePhoto()
Captures a photo and returns a signed ZPhoto. See takePhoto for details.
getMinZoom()
Gets the minimum supported zoom factor. See getMinZoom.
getMaxZoom()
Gets the maximum supported zoom factor. See getMaxZoom.
hasUltraWideCamera()
Checks if device has an ultra-wide camera. See hasUltraWideCamera.
focusAtPoint(x, y)
Focuses at a specific point in the preview. See focusAtPoint.
setZoomAnimated(factor)
Sets zoom with smooth animation. See setZoomAnimated.
isDepthSupported()
Checks if device supports depth data capture. See isDepthSupported.
getSwitchOverZoomFactors()
Gets the zoom factors where the device switches between physical lenses. See getSwitchOverZoomFactors.
startVideoRecording(position?)
Starts recording a video. See startVideoRecording.
stopVideoRecording()
Stops video recording and returns the finalized file. See stopVideoRecording.
getDeviceDiagnostics()
Returns diagnostic information about the current camera device.
const diagnostics = await camera.current?.getDeviceDiagnostics();Returns: Promise<DeviceDiagnostics>
type DeviceDiagnostics = {
deviceType: string; // e.g., "builtInTripleCamera"
minZoom: number; // Minimum zoom factor
maxZoom: number; // Maximum zoom factor
currentZoom: number; // Current zoom factor
switchOverFactors: number[]; // Lens switch points
switchingBehavior: number; // AVFoundation switching behavior
isVirtualDevice: boolean; // Whether device is virtual (multi-camera)
currentExposureBias: number; // Current exposure compensation (EV)
minExposureBias: number; // Min supported exposure compensation
maxExposureBias: number; // Max supported exposure compensation
currentISO: number; // Current ISO value
exposureDuration: number; // Current exposure duration (seconds)
}Useful for debugging zoom issues on different device configurations.
hasDepthZoomLimitations()
Checks if enabling depth would restrict zoom on this device.
const hasLimitations = await camera.current?.hasDepthZoomLimitations();Returns: Promise<boolean> - true if zoom is limited to discrete levels when depth is enabled (typically dual-camera devices), false for triple-camera devices.
getDepthSupportedZoomRanges()
Gets the zoom ranges supported when depth data delivery is enabled.
const ranges = await camera.current?.getDepthSupportedZoomRanges();
// Example: [[2.0, 2.0], [4.0, 4.0]] for discrete levels
// Example: [[1.0, 6.0]] for continuous zoomReturns: Promise<number[][]> - Array of [min, max] pairs. If min == max, it's a discrete level.
Example
import { useEffect, useRef, useState } from "react";
import { View, Button, StyleSheet } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { initCapture, ZCamera, type CaptureInfo } from "@succinctlabs/react-native-zcam1";
export function CaptureScreen() {
const camera = useRef<ZCamera>(null);
const [captureInfo, setCaptureInfo] = useState<CaptureInfo>();
useEffect(() => {
initCapture({
appId: process.env.EXPO_PUBLIC_APP_ID!,
production: false,
}).then(setCaptureInfo);
}, []);
const handleCapture = async () => {
const photo = await camera.current?.takePhoto();
console.log("Captured:", photo?.path);
};
if (!captureInfo) return null;
return (
<SafeAreaView style={styles.container}>
<ZCamera
ref={camera}
captureInfo={captureInfo}
style={styles.camera}
filmStyle="mellow"
zoom={2.0}
/>
<View style={styles.controls}>
<Button title="Capture" onPress={handleCapture} />
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: { flex: 1 },
camera: { flex: 1 },
controls: { padding: 16 },
});