How to Build a QR Code Scanner App With React Native

The simplest way to build a QR code scanning app in React Native today is to use Expo and the expo-camera library, whose CameraView component scans QR and other barcodes natively. You install the package, request camera permission with the useCameraPermissions hook, set barcodeScannerSettings to QR, and handle each result in onBarcodeScanned. The rest is validation and user experience.

Key takeaways

  • expo-camera handles camera preview and QR detection; the older expo-barcode-scanner approach has been superseded.
  • Always check permission state before rendering the camera and give users a clear way to grant it.
  • Throttle or lock scanning after a hit, or the callback fires many times for one code.
  • Treat scanned data as untrusted input: validate format before acting on it.
  • Plan for offline use and low light if the app will run in warehouses, clinics or field sites.

What you need before you start

  • Node.js LTS and a code editor.
  • A new Expo project created with the official create-expo-app command.
  • A physical phone with the Expo Go app or a development build, because simulators have limited camera support.

The React Native documentation recommends using a framework such as Expo for new apps, which saves you from configuring native camera modules by hand. If you need deeper native control later, bare React Native projects can use community libraries such as VisionCamera, but most business scanners do not need that.

Create the project and add the camera package:

npx create-expo-app qr-scanner
cd qr-scanner
npx expo install expo-camera

How do you build the scanner screen?

The component below checks permission, shows the camera, scans only QR codes and locks after the first successful scan so the user can confirm the result.

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

export default function Scanner() {
  const [permission, requestPermission] = useCameraPermissions();
  const [result, setResult] = useState(null);

  if (!permission) return <View />;

  if (!permission.granted) {
    return (
      <View style={styles.center}>
        <Text>Camera access is needed to scan QR codes.</Text>
        <Button title="Allow camera" onPress={requestPermission} />
      </View>
    );
  }

  return (
    <View style={{ flex: 1 }}>
      <CameraView
        style={{ flex: 1 }}
        barcodeScannerSettings={{ barcodeTypes: ['qr'] }}
        onBarcodeScanned={result ? undefined : (scan) => setResult(scan.data)}
      />
      {result && (
        <View style={styles.panel}>
          <Text>{result}</Text>
          <Button title="Scan again" onPress={() => setResult(null)} />
        </View>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  center: { flex: 1, alignItems: 'center', justifyContent: 'center', padding: 16 },
  panel: { padding: 16, backgroundColor: 'white' },
});

Passing undefined to onBarcodeScanned once a result exists stops repeated callbacks while the code is still in view. Each scan result includes the barcode type and its data, plus bounds you can use to draw a highlight box.

Making the scanner production-ready

Validate what you scan

A QR code can contain any text, including malicious links. Decide what format your app expects, such as an asset ID pattern, a signed token or a URL on your own domain, and reject everything else with a clear message. Never open arbitrary URLs automatically.

Handle permissions and platform settings

Add a camera usage description in your app configuration so iOS shows a meaningful prompt. If a user denies permission permanently, show instructions for enabling it in device settings instead of a dead screen.

Plan for poor connectivity

Scanning works offline, but whatever you do with the result may not. Queue scans locally with a timestamp and sync when the network returns. This is the same design problem time clock apps face, which we discuss in offline time clock punching.

Design for real environments

Test in low light, with damaged or glossy labels and at different distances. Add a torch toggle (CameraView supports an enableTorch prop) and audible or haptic feedback on success.

Build checklist

ItemWhy it matters
Permission states handled (undetermined, granted, denied)Avoids blank screens and app store rejections
Scan lock or debouncePrevents duplicate records from one code
Input validationBlocks malformed or malicious payloads
Offline queueKeeps scans from being lost on weak networks
Torch and feedbackFaster, more reliable scanning on the floor
Unmount camera when screen loses focusOnly one camera preview can be active at a time
Device testing on iOS and AndroidCamera behavior differs by platform

If your team needs a scanner inside a larger workflow but lacks mobile developers, compare building from scratch with platform options; our overview of how low-code helps teams build apps quickly covers the trade-offs, and our piece on why mobile app development matters for business covers the business case.

Frequently Asked Questions

Do I need Expo to scan QR codes in React Native?

No, but it is the fastest route. Expo's camera package bundles native scanning and works with Expo Go for testing. Bare React Native apps can use community camera libraries that offer code scanning, which give more control over frame processing but require native setup on iOS and Android.

Why does onBarcodeScanned fire multiple times?

The camera analyzes frames continuously, so a code that stays in view is detected repeatedly. Store the first result in state and set the callback to undefined until the user chooses to scan again, or ignore repeat values within a short time window. This prevents duplicate records and repeated network calls.

Can the app scan barcodes other than QR codes?

Yes. The barcodeTypes array accepts other formats such as EAN-13, UPC-A and Code 128. Limit the list to the formats you actually use, because scanning fewer types reduces false reads and makes your validation logic simpler and easier to test.

Next steps

Build the screen above, test it on two physical devices, then add validation and an offline queue before connecting it to your backend. Write down the exact payload format your QR codes will use so labels and app stay in sync.

Last reviewed: October 2026.

Sources

Comments

Popular Posts

Why Workday Onboarding Breaks Down for Frontline Employees

How to Improve the Customer Experience (CX)

How Do I Log In and Sign In to Workday HCM

UKG Union Contract and Overtime Rules for Multi-Site Food Plants

Infor HCM Software Engineer Jobs: Salary Factors and Skills

How to Search in Workday: Find Reqs, Reports, People and Tasks

ERP Solution Guide: How to Choose the Best ERP for You

The End of Remote Work: Why Companies Want You Back

The Future of Employee Healthcare Key Concerns and Strategies for 2024

How Digital Marketing Helps Your Business Grow: A Practical Plan