How to add a QR code scanner to an app, and what to do with the string it gives you.
To add a QR code scanner to an app you need three pieces: permission to use the camera, a view that reads frames and hands you a string, and a rule for what that string means. The first two take an afternoon. The third is the real project. If the camera itself is new to you, start with the camera in React Native and come back.
Below: the limit that catches people out first, the three ways to scan a QR code in an app, the permission you can skip on Android, and the failures that only turn up in the room where people scan.
See what a scan actually returnsThe short version
You cannot test a scanner on a simulator.
This one goes at the top because it reshapes the schedule. Expo lists its camera module as device only on both Android and iOS. A simulator has no lens, so the single feature you most want to demo is the one you cannot demo until the build is on a phone.
That applies to every preview environment, including Newly's cloud simulator: it runs the app while you build, but it cannot point a lens at a sticker. So plan the loop now. A TestFlight build or a Google Play internal testing build, a phone in your hand, a code on paper. Most scanner projects run late because nobody costed that round trip.
A scan returns a string, and nothing else
The callback gives you two fields: which kind of code it was, and the data encoded in it. There is no signature, no validation and no way to tell that the code came from you. A label somebody printed at home scans exactly as cleanly as the one on your asset.
So the design question was never how to scan. It is what your codes will carry. A short opaque ID that means something only inside your own records is usually right for internal work: it prints at any size and a photo of it leaks nothing. A full URL is right when strangers will scan with the phone's own camera app and never install anything.
Decide this before you write the screen, because changing it later means reprinting every label. If the codes are going on physical stock, the same decision is worked through end to end on the inventory barcode scanning app page.
Try it
What a scan actually hands you
Pick what your codes will carry. The scanner returns a string either way. All of the work is on the two lines below it.
ASSET-4471
Look the ID up in your own data, then show the record.
A code for a record you deleted still scans cleanly. Handle the miss.
Three ways to read a code, and when each is right
The cheapest option is not building a scanner. Both iOS and Android read QR codes from the stock camera app, so if your code is a link and your audience is the public, a printed code and no app can be the whole answer. You get nothing back, which is the trade: no record of who scanned, when or where.
If the scan belongs inside your app, Expo's camera module covers the other two routes. A CameraView with an onBarcodeScanned callback gives you your own screen, your own framing box and your own torch button. Or launchScanner presents the platform's own sheet instead: the Google code scanner on Android, and DataScannerViewController on iOS 16 and later. The sheet is faster to ship and looks like the platform, not like you.
It is worth knowing what else the same component reads, because that decides what you are allowed to print. Expo documents these barcode types: aztec, ean13, ean8, qr, pdf417, upc_e, datamatrix, code39, code93, itf14, codabar, code128 and upc_a. One line in those docs is easy to misread: the note that only QR is supported on iOS sits under scanFromURLAsync, which reads a code out of a still image, not under the live camera.
Set that list yourself rather than taking the default. A scanner watching for everything will cheerfully read the courier label next to the code you wanted.
Permissions, and the Android route that skips the prompt
iOS will not open a camera without a reason string in Info.plist under NSCameraUsageDescription, and App Review reads it. Android needs the CAMERA permission. Expo's config plugin writes both during prebuild and gives you a default message, which you should replace with a sentence that says scanning, because a vague one invites a review question.
There is one real exception worth knowing about. Google's code scanner on Android runs the whole scan inside Google Play services and returns only the result, so your app never requests camera permission at all. Google's documentation states the image processing happens on the device and that it does not store the results or the image data. For a single scan buried in a longer flow, skipping the prompt is a measurable win.
The catch is delivery, not privacy. That API uses an unbundled library that has to be downloaded before use, and if you have not asked for it at install time, Play services fetches the scanner module the first time somebody scans. So the first scan on a fresh install can sit waiting on a download, over whatever connection that person has in a stockroom. Give it a visible waiting state, or your store reviews will describe it for you.
The failures that only show up where people scan
Codes get scanned in bad places. A dark stockroom, a sunlit counter, a laminated badge that reflects, a curved bottle. The fixes are unglamorous and they are all interface: a torch toggle, a framing box that tells people how close to hold the phone, and a scan target printed larger than the label designer wanted.
Repeat firing is the bug almost everyone ships. The callback runs on every frame that contains a code, so one sticker held in front of the lens for two seconds can fire dozens of times and create dozens of records. Freeze on the first hit, show the person what you read, and make them do something deliberate before the next scan.
Then there is the way out. Some codes are torn, some sit behind glass, and some phone lenses are scratched past saving. Always give people a field to type the value into. If the point of the scan was to record what somebody was looking at, add photo upload beside it so the record survives a code that will not read. A scanner with no manual path is a scanner that stops work.
Four ways to get a code into your system
| Approach | Your own scan screen | Camera permission prompt | Reads more than QR | What you give up |
|---|---|---|---|---|
| The phone's own camera app | No | never yours to ask | QR in practice | You never learn a scan happened |
| Platform scanner sheet | No | not on Android | Yes | The screen looks like the platform, not your app |
| Camera view inside your app | Yes | Yes | Yes | You build framing, torch and every error state |
| Third-party scanning SDK | Yes | Yes | Yes | A licence fee and a heavier binary |
| Typed entry next to the scanner | No | No | Yes | Speed, but it never fails |
Building the scanner into an app that does something with it
If the scanner is one screen in a larger app, the scanner is not the hard decision. What it connects to is: an asset list, a delivery record, a door, a ticket, a stock count. That is why generic scanner apps disappoint. They read the code perfectly and hand you a clipboard, and the copying you were trying to remove is still there.
Newly is an AI app builder. You describe the app in plain English and it writes a real React Native and Expo project you own, then ships it to TestFlight and to Google Play internal testing from the Deploy tab, which is exactly how the scanner gets onto a real phone to be tested. It is $25 a month and there is no free plan. The code leaves as a ZIP or through two-way GitHub sync, so the camera screen is yours to tune once it exists.
One thing to settle before any of that. Decide whether a scan has to work when the phone has no signal, because a stockroom, a basement and a loading bay are all places where the lookup behind the scan fails and the app becomes a shrug. That changes the data design far more than the camera code, so read up on scanning with no signal before you settle on a shape.
Questions people ask about adding a QR scanner
Three pieces. Declare camera access, which on iOS means an NSCameraUsageDescription string and on Android the CAMERA permission. Render a camera view with a barcode callback, or launch the platform's own scanner sheet. Then write the rule for what the decoded string means. The first two are an afternoon. The third is the project.
Describe the app the scan is meant to feed
Write down what a code will carry, what the app should show when it reads one, and what happens when it reads nothing. Build the scanner around that.
Start building