Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Capture SDK

The Capture SDK (react-native-zcam1-capture) takes photos and produces C2PA-signed assets bound to hardware-backed integrity signals.

Installation

npm i react-native-zcam1-capture
cd ios && pod install

Core Concepts

The Capture SDK:

  • Renders a native iOS camera preview via ZCamera
  • Generates App Attest assertions over photo hashes
  • Embeds C2PA manifests with succinct.bindings assertion
  • Returns signed photos ready for proof generation

API Reference

initCapture(settings)

Initializes device keys and attestation. Call once on app startup.

import { initCapture, CaptureInfo, Settings } from "react-native-zcam1-capture";
 
const settings: Settings = {
  appId: "TEAM_ID.com.example.app",
  production: false,
};
 
const captureInfo: CaptureInfo = await initCapture(settings);
Parameters:
  • settings.appId - Your Team ID + Bundle ID
  • settings.production - false for development, true for production

Returns: CaptureInfo containing:

  • appId - The app identifier
  • deviceKeyId - App Attest device key ID
  • contentPublicKey - Secure Enclave content key
  • contentKeyId - Derived content key identifier
  • attestation - App Attest attestation blob

ZCamera

React component that renders the native camera preview.

import { useRef } from "react";
import { ZCamera, CaptureInfo } from "react-native-zcam1-capture";
 
function CameraScreen({ captureInfo }: { captureInfo: CaptureInfo }) {
  const camera = useRef<ZCamera>(null);
 
  return (
    <ZCamera
      ref={camera}
      captureInfo={captureInfo}
      position="back"        // "front" | "back"
      isActive={true}        // Enable/disable camera
      style={{ flex: 1 }}
    />
  );
}
Props:
  • captureInfo (required) - From initCapture()
  • position - Camera to use: "front" or "back" (default: "back")
  • isActive - Whether camera is running (default: true)
  • style - Style for the camera view

ZCamera.takePhoto()

Captures a photo and returns a signed ZPhoto.

const photo = await camera.current?.takePhoto();
 
console.log(photo.originalPath); // Raw capture path
console.log(photo.path);         // C2PA-signed photo path

Returns: ZPhoto with:

  • originalPath - Path to the raw captured image
  • path - Path to the C2PA-signed image with succinct.bindings

Complete Example

import { useEffect, useRef, useState } from "react";
import { View, Button, Text, StyleSheet } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { initCapture, ZCamera, CaptureInfo } from "react-native-zcam1-capture";
import { FileSystem, Dirs } from "react-native-file-access";
 
export function CaptureScreen() {
  const camera = useRef<ZCamera>(null);
  const [captureInfo, setCaptureInfo] = useState<CaptureInfo>();
  const [lastPhoto, setLastPhoto] = useState<string>();
 
  useEffect(() => {
    const settings = {
      appId: process.env.EXPO_PUBLIC_APP_ID!,
      production: false,
    };
    initCapture(settings).then(setCaptureInfo);
  }, []);
 
  const handleCapture = async () => {
    const photo = await camera.current?.takePhoto();
    if (!photo) return;
 
    // Save to app's document directory
    const destPath = `${Dirs.DocumentDir}/photos/${Date.now()}.jpg`;
    await FileSystem.mkdir(`${Dirs.DocumentDir}/photos`);
    await FileSystem.cp(photo.path, destPath);
 
    setLastPhoto(destPath);
  };
 
  if (!captureInfo) {
    return (
      <View style={styles.centered}>
        <Text>Initializing camera...</Text>
      </View>
    );
  }
 
  return (
    <SafeAreaView style={styles.container}>
      <ZCamera ref={camera} captureInfo={captureInfo} style={styles.camera} />
      <View style={styles.controls}>
        <Button title="Capture" onPress={handleCapture} />
        {lastPhoto && <Text>Saved: {lastPhoto}</Text>}
      </View>
    </SafeAreaView>
  );
}
 
const styles = StyleSheet.create({
  container: { flex: 1 },
  camera: { flex: 1 },
  controls: { padding: 16 },
  centered: { flex: 1, justifyContent: "center", alignItems: "center" },
});

Notes

  • initCapture() generates Secure Enclave keys on first call; subsequent calls load existing keys
  • App Attest only works on physical devices; the SDK uses mock values in simulators
  • The captured photo at photo.path contains a C2PA manifest with succinct.bindings—this is required for proof generation