React Native Pro SDK
Complete SDK for blockchain-verified content registration with StarkNet wallet management, on-device zero-knowledge proofs, offline queue, and enterprise telemetry.
📦 Current Version: 5.0.0
Full on-device processing — images never leave the device. Native Poseidon hash, watermark, MobileCLIP embedding, and .facti build via blockfact-core. On-device ZKP via Mopro/Arkworks (<1s). Optional IPFS pinning via uploadToIPFS(). Backend is a thin registration relay (~3.5s).
Installation
npm install @blockfact/react-native-facti-pro blockfact-core mopro-ffiNative Setup
Run the setup script to install native ZKP libraries, circuit files, and the MobileCLIP embedding model (82MB, downloaded from CDN):
npx @blockfact/setupSee the Native Module Setup Guide for platform-specific details.
Peer Dependencies
npm install react-native-get-random-values
npm install react-native-keychain
npm install react-native-encrypted-storage
npm install react-native-blob-util
npm install @react-native-community/netinfo
npm install react-native-device-infoiOS Setup
cd ios && pod install && cd ..Quick Start
1. Wrap Your App
import { BlockFactProvider } from '@blockfact/react-native-facti-pro';
export default function App() {
return (
<BlockFactProvider apiBase="https://api.blockfact.io">
<YourApp />
</BlockFactProvider>
);
}2. Create a Wallet
Two modes — standalone (no Web3Auth needed) or Web3Auth:
import { useBlockFact } from '@blockfact/react-native-facti-pro';
function WalletScreen() {
const { wallet, createWallet, hasWallet } = useBlockFact();
// Standalone — generates keypair, deploys on-chain
const handleStandalone = () => createWallet();
// Or with Web3Auth
const handleWeb3Auth = () => createWallet({ idToken: web3authToken });
if (!hasWallet) {
return <Button title="Create Wallet" onPress={handleStandalone} />;
}
return <Text>Wallet: {wallet.address}</Text>;
}3. Register Content
function CameraScreen() {
const { registerContent } = useBlockFact();
const handleCapture = async (photo) => {
const { jobId, status } = await registerContent({
filePath: photo.uri,
filename: photo.fileName || 'photo.jpg', // from camera response
mime: photo.type || 'image/jpeg', // defaults to image/jpeg
latitude: position.coords.latitude,
longitude: position.coords.longitude,
});
// Job is queued — processes automatically
// Survives app kills, resumes on relaunch
// Auto-retries when network returns
console.log('Queued:', jobId);
};
}📡 Offline Resilient
Jobs are persisted to encrypted storage. If the app is killed or goes offline, jobs resume automatically on relaunch or when network returns.
API Reference
BlockFactProvider
<BlockFactProvider
apiBase="https://api.blockfact.io" // Required
modelUrl="https://cdn.blockfact.io/models/mobileclip-s1.onnx" // Optional — custom model CDN
onModelDownloadProgress={(progress) => { // Optional — 0-100
console.log('Model download:', progress + '%');
}}
telemetry={{ // Optional — enterprise only
enabled: true,
apiKey: 'ent_live_abc123',
tags: { organizationId: 'acme-corp', sourceId: 'tablet-001' }
}}
>
{children}
</BlockFactProvider>🔒 Images Never Leave the Device
In v5, all image processing (hashing, watermarking, embedding, .facti build) happens on-device via native Rust modules. Only a few KB of metadata (hash + proof + embedding vector) are sent to the backend for blockchain registration.
useBlockFact()
const {
// State
wallet, // { address, mode, userId, publicKey? }
loading, // boolean
error, // string | null
blocked, // boolean — true if SDK version is too old
sdkVersion, // string — e.g. "5.0.0"
hasWallet, // boolean
queue, // UploadQueue instance
// Functions
createWallet, // (params?) => Promise<Wallet>
registerContent, // (params) => Promise<{ jobId, status }>
deleteWallet, // () => Promise<void>
uploadToIPFS, // (factiPath: string) => Promise<{ cid, url }>
ensureEmbeddingModel, // () => Promise<void> — pre-downloads MobileCLIP model
} = useBlockFact();createWallet(params?)
// Standalone mode — no Web3Auth dependency
const wallet = await createWallet();
// or with custom user ID
const wallet = await createWallet({ userId: 'user-123' });
// Web3Auth mode
const wallet = await createWallet({ idToken: web3authJWT });
// Returns:
{
address: string, // StarkNet address (0x...)
mode: 'standalone' | 'web3auth',
userId: string,
publicKey?: string, // Only in standalone mode
}🔐 Security
Private keys are stored in iOS Keychain / Android Keystore with biometric authentication (BIOMETRY_ANY + WHEN_UNLOCKED_THIS_DEVICE_ONLY). Keys never leave the device.
registerContent(params)
const { jobId, status, factiLocalPath } = await registerContent({
filePath: string, // Required — local file path
filename?: string, // Default: 'photo.jpg'
mime?: string, // Default: 'image/jpeg'
latitude?: number, // GPS latitude
longitude?: number, // GPS longitude
metadata?: object, // Custom metadata
});
// Returns immediately — job processes in background
// {
// jobId: 'abc123',
// status: 'queued',
// factiLocalPath: '/path/to/Documents/facti/abc123.facti' // NEW in v5
// }
// To optionally pin to IPFS:
const { cid, url } = await uploadToIPFS(factiLocalPath);Upload Queue
const { queue } = useBlockFact();
// Monitor jobs
queue.jobs // All jobs
queue.pending // Jobs not yet completed
// Subscribe to changes
const unsub = queue.subscribe(() => {
console.log('Queue updated:', queue.jobs);
});
// Remove a job
await queue.removeJob(jobId);
// Job statuses:
// 'queued' → 'processing' → 'completed'
// → 'failed'
// → 'waiting_network' (auto-resumes)Processing Pipeline
- 1. On-Device Poseidon Hash + Watermark (<1s)
- • Computes Poseidon hash from wallet + GPS + timestamp (native Rust)
- • Embeds hash as steganographic watermark into image pixels (native Rust)
- • Image never leaves the device
- 2. Native ZKP Generation (<1s)
- • Generates Groth16 proof natively via Mopro/Arkworks (Rust)
- • Proof cryptographically attests device knows the private inputs
- • No server round-trip — proof generated entirely on-device
- 3. MobileCLIP Embedding (~80ms)
- • Generates 512-dim image embedding on-device via MobileCLIP-S1 ONNX model
- • Enables reverse image verification on blockfact.io/verify
- • Model downloaded on first use, cached permanently
- 4. Blockchain Registration (~3.5s)
- • Sends hash + proof + embedding (~few KB) to thin backend relay
- • Backend registers on StarkNet with Garaga on-chain verification
- • Returns tx_hash
- 5. Local .facti Build (instant)
- • Builds .facti file on-device from watermarked image + metadata
- • Saved to local storage — available immediately
- • Optional: call
uploadToIPFS(factiLocalPath)to pin to IPFS
🔐 Learn More
See the ZKP Architecture Guide for a deep dive into the Poseidon circuit, Groth16 proving, and the on-chain verification flow.
Enterprise Telemetry
Enterprise customers can enable telemetry for fleet monitoring, anomaly detection, and audit trails. Free users are completely unaffected — no API key means no telemetry.
<BlockFactProvider
apiBase="https://api.blockfact.io"
telemetry={{
enabled: true,
apiKey: 'ent_live_abc123', // From enterprise dashboard
tags: {
organizationId: 'acme-corp',
projectId: 'field-ops',
sourceId: 'tablet-001', // For fleet tracking
}
}}
>Events tracked automatically:
- •
source.sdk_initialized— SDK startup with device info - •
source.health_check— Every 5 minutes (queue depth, network status) - •
source.sdk_outdated— When newer version available - •
content.captured— When registerContent() is called - •
content.registered— Successful blockchain registration - •
content.registration_failed— Failed registration
Version Gate
The SDK checks the minimum required version on startup. If your version is too old, blocked will be true and all operations will throw with an upgrade message.
const { blocked, error, sdkVersion } = useBlockFact();
if (blocked) {
return <Text>{error}</Text>;
// "SDK v2.5.1 is blocked. Minimum required: v3.0.0. Please upgrade to v3.2.0."
}Standalone Verification
import { verifyContent } from '@blockfact/react-native-facti-pro';
const result = await verifyContent('https://ipfs.io/ipfs/Qm.../file.facti');
// { valid: true, metadata: { ... } }Error Handling
try {
const { jobId } = await registerContent({...});
} catch (error) {
if (error.message.includes('blocked')) {
// SDK version too old — must upgrade
} else if (error.message.includes('No wallet')) {
await createWallet();
} else if (error.message.includes('filePath')) {
// Missing required param
}
}Security Features
- ✅ On-Device Processing: Images never leave the device — hash, watermark, embedding, .facti all built locally
- ✅ Native ZKP: Groth16 proofs generated on-device via Mopro/Arkworks in <1s
- ✅ Biometric Protection: Face ID, Touch ID, Fingerprint for key access
- ✅ Encrypted Storage: Queue and wallet data encrypted at rest
- ✅ Device Attestation: iOS DeviceCheck / Android Play Integrity (when available)
- ✅ Idempotency: Duplicate registrations prevented via content-derived keys
- ✅ Version Gate: Server-controlled minimum SDK version enforcement
- ✅ Blockchain Verification: Immutable StarkNet registration
- ✅ IPFS Storage: Decentralized .facti file hosting via Pinata
Migration from v4.x
⚠️ Breaking Changes in v5.0.0
- • New peer dependency:
blockfact-core— on-device Poseidon hash, watermark, .facti builder, MobileCLIP embedding - • Return type changed:
registerContent()now returnsfactiLocalPathinstead offactiUrl— .facti files are built on-device, not uploaded to IPFS - • New exports:
uploadToIPFS(factiPath)for optional IPFS pinning,ensureEmbeddingModel()to pre-download MobileCLIP - • Removed props:
skipZkpandwsUrlonBlockFactProvider - • New props:
modelUrlandonModelDownloadProgressonBlockFactProvider - • Setup CLI:
npx @blockfact/setupnow also downloads the MobileCLIP ONNX model (82MB) - • Images never leave device: No S3 upload, no server-side watermarking — all processing is on-device
See the full v5 Migration Guide for step-by-step instructions.
Migration from v3.x
⚠️ Breaking Changes in v4.0.0
- • Native ZKP: Replaced JS
snarkjs/circomlibjswith nativemopro-ffi— requires native module linking - • New dependency:
mopro-ffi(optional peer dep — falls back to server-side ZKP if not installed) - • Setup script: Run
npx @blockfact/setupto install native libs + circuit files - • Expo: Expo Go no longer supported — use dev client or
npx expo prebuild - • Removed:
snarkjsandcircomlibjsdependencies - • No API changes:
registerContent()andcreateWallet()work the same way
Migration from v2.x
⚠️ Breaking Changes in v3.0.0
- •
BlockFactProvidernow requiresapiBaseprop - •
registerContent()takesfilePathinstead ofimageUri, returns{ jobId, status } - •
createWallet()accepts optional{ idToken }or{ userId } - • Replaced
async-storagewithreact-native-encrypted-storage - • Removed
bufferpolyfill requirement - • Added
react-native-blob-util,@react-native-community/netinfo,react-native-device-infoas dependencies
Support
- 📧 Email: support@blockfact.io
- 💬 Discord: Join our community
- 🐛 GitHub: Report issues