Shipnative
ShipnativeShipnative
Sign in
GuideJuly 2026 · 7 min read

React Native QR Code Scanner: Build One (2026)

A QR scanner is the backbone of ticketing, event check-in, inventory, loyalty, and pay-at-table apps — and in 2026 it’s about 40 lines of code with expo-camera. This guide covers the whole thing: camera permission done right, a live scanner that reads QR and barcodes, the duplicate-scan trap everyone hits, and handling the result. Then the shortcut — having an AI builder wire it so you skip straight to the part that matters.

One package: expo-camera

If you searched this a year ago you’d have found expo-barcode-scanner. That package is deprecated — its scanning is now built into expo-camera, which is the one library you need. It exposes a CameraView component with an onBarcodeScanned callback. That callback is the entire feature.

Like any camera feature, scanning is native, so the final app needs a development build rather than Expo Go. Everything else is plain React.

Step 1 — Install and permit

npx expo install expo-camera

Camera access needs an explicit permission and a usage string. Add the reason to app.jsonso App Store review doesn’t reject you:

{
  "expo": {
    "plugins": [
      ["expo-camera", {
        "cameraPermission": "We use the camera to scan QR codes."
      }]
    ]
  }
}

Step 2 — The full scanner screen

This is a complete, working screen. Note the scanned flag — without it, onBarcodeScanned fires continuously and you get the same code a hundred times:

import { useState } from 'react';
import { Button, StyleSheet, Text, View } from 'react-native';
import { CameraView, useCameraPermissions } from 'expo-camera';

export default function ScannerScreen() {
  const [permission, requestPermission] = useCameraPermissions();
  const [scanned, setScanned] = useState(false);
  const [result, setResult] = useState('');

  if (!permission) return <View />;
  if (!permission.granted) {
    return (
      <View style={styles.center}>
        <Text style={{ color: 'white', marginBottom: 12 }}>
          Camera access is needed to scan.
        </Text>
        <Button title="Grant permission" onPress={requestPermission} />
      </View>
    );
  }

  const onScan = ({ data }) => {
    if (scanned) return;      // guard: handle each code once
    setScanned(true);
    setResult(data);
    // do something: look up ticket, open URL, add inventory…
  };

  return (
    <View style={styles.center}>
      <CameraView
        style={StyleSheet.absoluteFill}
        barcodeScannerSettings={{ barcodeTypes: ['qr', 'ean13', 'code128'] }}
        onBarcodeScanned={scanned ? undefined : onScan}
      />
      {scanned && (
        <View style={styles.overlay}>
          <Text style={{ color: 'white' }}>Scanned: {result}</Text>
          <Button title="Scan again" onPress={() => setScanned(false)} />
        </View>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  center: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#000' },
  overlay: { position: 'absolute', bottom: 60, alignItems: 'center', gap: 10 },
});

Setting onBarcodeScanned to undefined once scanned is a belt-and-suspenders way to stop the callback entirely until you reset.

Step 3 — Do something with the result

The data string is whatever the code encodes. From there the app is just normal logic:

  • Ticket / check-in: look the code up in your database, mark it used, show valid/invalid.
  • Inventory: match the barcode to a product, increment or decrement stock.
  • Link: if it’s a URL, open it — but confirm with the user first, never auto-navigate.

One security note: treat scanned data as untrusted input. A QR code can encode anything, so validate before you act — especially before opening a URL.

Step 4 — Build for a real device

npx expo run:ios # or eas build --profile development

Test with an actual printed or on-screen code. The simulator can’t use a real camera, so device testing here isn’t optional.

The shortcut: describe it, don’t wire it

The scanner itself is 40 lines, but the surrounding app — the ticket database, the check-in list, the valid/used states — is the real work. That’s where an AI builder earns its place. Describe “an event check-in app that scans ticket QR codes and marks them used” in ShipNative and it wires expo-camera, the permission prompt, the scan guard, and a screen to see results — previewed live on your phone.

You bring the camera and a printed code; the boilerplate is already handled. See the loyalty-card build plan for a scanner-plus-database app you can generate today.

Build a scanner app free

Describe your scanning app in one sentence and see it running on your phone in minutes at shipnative.dev. No credit card, full Expo export whenever you want it.

Frequently Asked Questions

What is the best library for a QR scanner in React Native?

For Expo apps, expo-camera is the modern default — it handles QR and barcode scanning through the CameraView component with an onBarcodeScanned callback. The older expo-barcode-scanner package is deprecated and folded into expo-camera.

Does a QR scanner work in Expo Go?

The camera and scanning work in Expo Go for development, but you need a development or production build to ship. Camera access is a native capability, so plan for that one build step.

How do I stop the scanner firing the same code repeatedly?

The onBarcodeScanned callback fires many times per second. Guard it with a "scanned" flag in state, set it true on the first hit, and ignore further callbacks until you reset — otherwise you get dozens of duplicate reads.

What barcode types can expo-camera scan?

QR codes plus common 1D and 2D formats: EAN-13, UPC, Code 128, Code 39, PDF417, and more. You pass the types you want in barcodeScannerSettings so the camera only reports the formats your app cares about.

Can an AI app builder add a scanner for me?

Yes. Describe a check-in, ticket, or inventory app that scans codes and ShipNative wires expo-camera, the permission prompt, and the scan handler — then previews it live on your phone so you can test with a real code.

→

Build a Loyalty Card App

A scanner plus a simple data model is a whole product category.

See the plan →
→

Add a Real Database

Store scanned tickets or inventory with Supabase in a generated app.

Read guide →

Ship a real React Native app today

Describe, preview, and export Expo code — free to start.

Build with ShipNative →
ShipNative logoShipnative

Build mobile apps with AI. Describe, preview, and ship to iOS & Android in minutes.

Features

Text to App AIApp Generator from ScreenshotPRD to Mobile App

Tools

All free toolsApp Cost CalculatorApp Name GeneratorApp Store Keyword ToolReact Native Components

Blog

All blog postsHow to Build an App Without CodingBest AI Tools for Real Mobile AppsExpo EAS App Store ChecklistLovable, Cursor & v0 for MobileBest AI App Builders in 2026React Native AI App Builder Guide

Legal

FAQTerms of ServicePrivacy Policy

© 2026 ShipNative. All rights reserved.