1. React Native
  2. VisionCamera Component

React Native

VisionCamera Component

INFO

v3.0.0: VisionCamera is now the primary camera component. The VisionSdkView component has been removed.

The VisionCamera component is the primary camera component for barcode scanning and OCR in React Native Vision SDK. It provides a streamlined API without requiring API keys or cloud configuration for basic scanning functionality.

Features

  • Photo capture with quality optimization
  • Barcode & QR code scanning with multiple symbologies
  • OCR (Optical Character Recognition) support
  • Real-time object detection (text, barcodes, QR codes, documents)
  • Torch control with declarative and imperative APIs
  • Zoom control on a wide-normalized ratio scale, identical on both platforms
  • Focus control - focus mode plus one-shot tap-to-focus
  • Lens pinning - restrict the session to a specific physical lens
  • Camera state stream - status, active lens, live zoom range, preview liveness
  • Auto & Manual capture modes
  • Image sharpness scoring for quality assurance
  • Customizable overlay - render your own UI on top of the camera
  • Camera switching - switch between front and back cameras on both platforms (iOS swaps the input in place on the running session, Android rebuilds the session)

Basic Usage

        import React, { useRef } from 'react';
import { VisionCamera, VisionCameraRefProps } from 'react-native-vision-sdk';

function CameraScreen() {
  const cameraRef = useRef<VisionCameraRefProps>(null);

  const handleCapture = (event) => {
    console.log('Image captured:', event.image);
    console.log('Sharpness score:', event.sharpnessScore);
  };

  const handleBarcodeDetected = (event) => {
    console.log('Barcodes:', event.codes);
    event.codes.forEach(code => {
      console.log('Value:', code.scannedCode);
      console.log('Type:', code.symbology);
      console.log('Position:', code.boundingBox);
    });
  };

  return (
    <VisionCamera
      ref={cameraRef}
      scanMode="barcode"
      onCapture={handleCapture}
      onBarcodeDetected={handleBarcodeDetected}
    />
  );
}

      

Scan Modes

Photo Mode

Basic photo capture without barcode or text detection:

        <VisionCamera
  scanMode="photo"
  onCapture={(event) => {
    console.log('Image path:', event.image);
    console.log('Sharpness:', event.sharpnessScore);
  }}
/>

      

Barcode Scanning

Detect and scan barcodes with enhanced metadata:

        <VisionCamera
  scanMode="barcode"
  onBarcodeDetected={(event) => {
    event.codes.forEach(code => {
      console.log('Code:', code.scannedCode);
      console.log('Type:', code.symbology);
      console.log('Bounds:', code.boundingBox);
      console.log('GS1:', code.gs1ExtractedInfo);
    });
  }}
/>

      

QR Code Scanning

Specifically scan QR codes:

        <VisionCamera
  scanMode="qrcode"
  onBarcodeDetected={(event) => {
    console.log('QR Codes:', event.codes);
  }}
/>

      

OCR (Text Recognition)

Document and text detection:

        <VisionCamera
  scanMode="ocr"
  autoCapture={true}
  onCapture={(event) => {
    console.log('Document captured:', event.image);
    // Barcodes detected in the image are also available
    if (event.barcodes) {
      console.log('Barcodes in image:', event.barcodes);
    }
  }}
  onRecognitionUpdate={(event) => {
    console.log('Text detected:', event.text);
    console.log('Document detected:', event.document);
  }}
/>

      

Ref Methods

Access camera controls via ref:

        const cameraRef = useRef<VisionCameraRefProps>(null);

// Capture photo
cameraRef.current?.capture();

// Start/stop camera
cameraRef.current?.start();
cameraRef.current?.stop();

      
NOTE

Camera Auto-Start: The camera starts automatically when mounted - you don't need to call start() manually in most cases. Use start() only after you've previously stopped it (e.g., when returning to the camera screen from background).

Method Parameters Description
capture() - Capture a photo manually (when autoCapture is false)
start() - Start the camera (only needed if you previously stopped it)
stop() - Stop the camera (e.g., when screen goes to background)
rescan() - Tear the session down and rebuild it (required on Android before a repeated capture())
setZoom(level) number Set the wide-normalized zoom ratio
setTorch(enabled) boolean Turn the torch on or off
setFocusPoint(x, y) number, number One-shot focus at a normalized point (0-1)
INFO

Property Control: Camera facing is controlled via the cameraFacing prop. Zoom, torch, focus mode and lens pinning are available both as props (zoomRatio, torch, focusMode, pinnedLensId) and as ref methods - see Camera Controls for which to reach for. The enableFlash and zoomLevel props and the toggleFlash() method are deprecated as of v3.12.0 in favour of torch / zoomRatio / setTorch().


Event Handlers

Enhanced Barcode Detection

        <VisionCamera
  scanMode="barcode"
  onBarcodeDetected={(event) => {
    // Each barcode includes full metadata
    event.codes.forEach(code => {
      console.log('Barcode Value:', code.scannedCode);
      console.log('Symbology:', code.symbology);
      console.log('Position:', code.boundingBox); // {x, y, width, height}
      console.log('GS1 Data:', code.gs1ExtractedInfo);
    });
  }}
/>

      

Image Capture with Quality Score

        <VisionCamera
  scanMode="photo"
  onCapture={(event) => {
    console.log('Image path:', event.image);
    console.log('Native URI:', event.nativeImage);
    console.log('Sharpness score:', event.sharpnessScore); // 0.0 - 1.0
    console.log('Detected barcodes:', event.barcodes); // Available in all modes
  }}
/>

      

Real-time Recognition Updates

        <VisionCamera
  scanMode="ocr"
  onRecognitionUpdate={(event) => {
    console.log('Text detected:', event.text);
    console.log('Barcode detected:', event.barcode);
    console.log('QR code detected:', event.qrcode);
    console.log('Document detected:', event.document);
  }}
/>

      

Sharpness Score Monitoring

        <VisionCamera
  scanMode="photo"
  onSharpnessScoreUpdate={(event) => {
    console.log('Sharpness:', event.sharpnessScore); // 0.0 to 1.0
    // Values above 0.7 generally indicate sharp images
  }}
/>

      

Error Handling

        <VisionCamera
  scanMode="barcode"
  onError={(event) => {
    console.error('Error:', event.message);
    console.error('Error code:', event.code); // Numeric error code
  }}
/>

      
INFO

iOS Error Filtering: On iOS, error codes 13, 14, 15, and 16 are automatically filtered and won't trigger the onError callback.


Advanced Examples

Custom Overlay with Controls

        import React, { useRef, useState } from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { VisionCamera, VisionCameraRefProps } from 'react-native-vision-sdk';

function CustomCameraOverlay() {
  const cameraRef = useRef<VisionCameraRefProps>(null);
  const [sharpness, setSharpness] = useState(0);

  return (
    <View style={styles.container}>
      <VisionCamera
        ref={cameraRef}
        scanMode="ocr"
        style={styles.camera}
        onSharpnessScoreUpdate={(event) => setSharpness(event.sharpnessScore)}
      />

      {/* Custom overlay positioned absolutely */}
      <View style={styles.overlay}>
        <View style={styles.header}>
          <Text style={styles.sharpnessText}>
            Sharpness: {(sharpness * 100).toFixed(0)}%
          </Text>
        </View>

        <View style={styles.footer}>
          <TouchableOpacity
            style={styles.captureButton}
            onPress={() => cameraRef.current?.capture()}
          >
            <Text style={styles.captureText}>Capture</Text>
          </TouchableOpacity>
        </View>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  camera: {
    flex: 1,
  },
  overlay: {
    ...StyleSheet.absoluteFillObject,
    justifyContent: 'space-between',
  },
  header: {
    padding: 20,
    backgroundColor: 'rgba(0, 0, 0, 0.5)',
  },
  sharpnessText: {
    color: 'white',
    fontSize: 16,
    fontWeight: 'bold',
  },
  footer: {
    padding: 20,
    alignItems: 'center',
  },
  captureButton: {
    backgroundColor: '#007AFF',
    paddingHorizontal: 30,
    paddingVertical: 15,
    borderRadius: 30,
  },
  captureText: {
    color: 'white',
    fontSize: 18,
    fontWeight: 'bold',
  },
});

      

Barcode Scanner with Torch and Zoom

TIP

This example drives the camera from local component state. For anything more involved - reading the camera's real zoom range, gating on preview liveness, tap-to-focus, lens pinning - use useCameraControls() instead. See Camera Controls.

        import React, { useState } from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { VisionCamera } from 'react-native-vision-sdk';
import type { VisionCameraBarcodeResult } from 'react-native-vision-sdk';

function AdvancedBarcodeScanner() {
  const [flash, setFlash] = useState(false);
  const [zoom, setZoom] = useState(1.0);
  const [codes, setCodes] = useState<VisionCameraBarcodeResult[]>([]);

  return (
    <View style={{ flex: 1 }}>
      <VisionCamera
        scanMode="barcode"
        torch={flash}
        zoomRatio={zoom}
        style={{ flex: 1 }}
        onBarcodeDetected={(event) => {
          setCodes(event.codes);
        }}
      />

      {/* Controls positioned absolutely */}
      <View style={styles.controls}>
        <TouchableOpacity onPress={() => setFlash(!flash)}>
          <Text style={styles.controlText}>
            {flash ? ' Flash ON' : ' Flash OFF'}
          </Text>
        </TouchableOpacity>

        <View style={styles.zoomControl}>
          <TouchableOpacity onPress={() => setZoom(Math.max(1.0, zoom - 0.5))}>
            <Text style={styles.controlText}>-</Text>
          </TouchableOpacity>
          <Text style={styles.controlText}>Zoom: {zoom.toFixed(1)}x</Text>
          <TouchableOpacity onPress={() => setZoom(Math.min(5.0, zoom + 0.5))}>
            <Text style={styles.controlText}>+</Text>
          </TouchableOpacity>
        </View>
      </View>

      {codes.length > 0 && (
        <View style={styles.results}>
          <Text style={styles.resultsTitle}>Detected Barcodes:</Text>
          {codes.map((code, index) => (
            <View key={index} style={styles.resultItem}>
              <Text style={styles.resultText}>
                {code.symbology}: {code.scannedCode}
              </Text>
            </View>
          ))}
        </View>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  controls: {
    position: 'absolute',
    top: 20,
    left: 20,
    right: 20,
    backgroundColor: 'rgba(0, 0, 0, 0.7)',
    padding: 15,
    borderRadius: 10,
  },
  controlText: {
    color: 'white',
    fontSize: 16,
  },
  zoomControl: {
    flexDirection: 'row',
    justifyContent: 'space-around',
    marginTop: 10,
  },
  results: {
    position: 'absolute',
    bottom: 20,
    left: 20,
    right: 20,
    backgroundColor: 'rgba(0, 0, 0, 0.8)',
    padding: 15,
    borderRadius: 10,
  },
  resultsTitle: {
    color: 'white',
    fontSize: 16,
    fontWeight: 'bold',
    marginBottom: 10,
  },
  resultItem: {
    marginVertical: 5,
  },
  resultText: {
    color: 'white',
    fontSize: 14,
  },
});

      

Document Scanner with Auto-Capture

        import React, { useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { VisionCamera } from 'react-native-vision-sdk';

function DocumentScanner() {
  const [documentDetected, setDocumentDetected] = useState(false);
  const [capturedImages, setCapturedImages] = useState([]);

  return (
    <View style={{ flex: 1 }}>
      <VisionCamera
        scanMode="ocr"
        autoCapture={true}
        style={{ flex: 1 }}
        onRecognitionUpdate={(event) => {
          setDocumentDetected(event.document);
        }}
        onCapture={(event) => {
          console.log('Document captured:', event.image);
          setCapturedImages(prev => [...prev, {
            uri: event.image,
            sharpness: event.sharpnessScore
          }]);
        }}
      />

      {documentDetected && (
        <View style={styles.detectionIndicator}>
          <Text style={styles.indicatorText}>
             Document Detected - Auto-capturing...
          </Text>
        </View>
      )}

      {capturedImages.length > 0 && (
        <View style={styles.captureCount}>
          <Text style={styles.countText}>
            Captured: {capturedImages.length} documents
          </Text>
        </View>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  detectionIndicator: {
    position: 'absolute',
    top: 50,
    left: 20,
    right: 20,
    backgroundColor: 'rgba(76, 175, 80, 0.9)',
    padding: 15,
    borderRadius: 10,
    alignItems: 'center',
  },
  indicatorText: {
    color: 'white',
    fontSize: 16,
    fontWeight: 'bold',
  },
  captureCount: {
    position: 'absolute',
    bottom: 30,
    alignSelf: 'center',
    backgroundColor: 'rgba(0, 0, 0, 0.8)',
    padding: 10,
    borderRadius: 8,
  },
  countText: {
    color: 'white',
    fontSize: 14,
  },
});

      

Scan Area Restriction

        import React from 'react';
import { View, Dimensions } from 'react-native';
import { VisionCamera } from 'react-native-vision-sdk';

function RestrictedScanArea() {
  const screenWidth = Dimensions.get('window').width;
  const screenHeight = Dimensions.get('window').height;

  const scanAreaWidth = 200;
  const scanAreaHeight = 100;
  const scanAreaX = (screenWidth - scanAreaWidth) / 2;
  const scanAreaY = (screenHeight - scanAreaHeight) / 2;

  return (
    <View style={{ flex: 1 }}>
      <VisionCamera
        scanMode="barcode"
        style={{ flex: 1 }}
        scanArea={{
          x: scanAreaX,
          y: scanAreaY,
          width: scanAreaWidth,
          height: scanAreaHeight
        }}
        frameSkip={10} // Process every 10th frame
        onBarcodeDetected={(event) => {
          console.log('Barcode detected in scan area:', event.codes);
        }}
      />

      {/* Visualize scan area */}
      <View style={{
        position: 'absolute',
        left: scanAreaX,
        top: scanAreaY,
        width: scanAreaWidth,
        height: scanAreaHeight,
        borderWidth: 2,
        borderColor: '#00FF00',
        backgroundColor: 'transparent',
      }} />
    </View>
  );
}

      

Performance Tips

  1. Throttle high-frequency events like onSharpnessScoreUpdate and onRecognitionUpdate:

            const lastUpdate = useRef(0);
    const throttleMs = 200;
    
    const handleSharpnessUpdate = (event) => {
      const now = Date.now();
      if (now - lastUpdate.current >= throttleMs) {
        lastUpdate.current = now;
        setSharpness(event.sharpnessScore);
      }
    };
    
          
  2. Use frameSkip to process fewer frames:

            <VisionCamera frameSkip={10} /> // Process every 10th frame
    
          
  3. Use autoCapture={false} for manual control to reduce processing

  4. Cleanup on unmount: The camera automatically stops when unmounted

  5. Avoid hot reload during development: Kill and restart the app for best results


Platform Support

iOS

  • Auto-starts camera when view is mounted
  • Supports all scan modes
  • Torch, zoom, focus and lens pinning fully supported
  • Zoom range depends on device capabilities - read it from onCameraStateChanged
  • Camera switching fully supported (front/back) - a live in-place input swap on the running session

Android

  • Auto-starts camera when view is attached to window
  • Supports all scan modes
  • Torch, zoom, focus and lens pinning fully supported
  • Zoom range depends on device capabilities - read it from onCameraStateChanged
  • Camera switching fully supported (front/back) - the session is rebuilt around the new facing, and a genuine facing switch drops pinnedLensId back to Auto
NOTE

There are real platform differences in how zoom behaves while a lens is pinned. See Camera Controls for the full comparison.


Template Support

NEW in v3.0.0: VisionCamera supports templates via the template prop for barcode pattern matching.

        import { VisionCamera } from 'react-native-vision-sdk';
import type { TemplateData } from 'react-native-vision-sdk';

const [activeTemplate, setActiveTemplate] = useState<TemplateData | null>(null);

<VisionCamera
  scanMode="barcode"
  template={activeTemplate}  // Pass TemplateData object or null
  onBarcodeDetected={(event) => {
    console.log('Detected:', event.codes);
  }}
/>

      

See Template Management for complete documentation on creating and using templates.



Troubleshooting

Camera feed not showing

  • Ensure camera permissions are granted
  • Check that the component has proper dimensions (flex: 1)
  • Verify device has a working camera

Events not firing after hot reload

  • This is a known React Native limitation with native views
  • Workaround: Kill and restart the app instead of hot reloading
  • Note: This does NOT affect production builds

Barcodes not detected

  • Ensure good lighting conditions
  • Check that scanMode is set correctly
  • Verify barcode is within camera view and properly focused

Poor image quality

  • Monitor onSharpnessScoreUpdate - values above 0.7 are generally good
  • Ensure adequate lighting
  • Keep device steady during capture