Building a barcode warehouse app: camera, OCR and Zebra printers
Notes from the warehouse app I built for TCT Lojistik: barcode scanning with a phone camera, OCR, ZPL label printing, printer discovery and connecting to an existing system.
Large numbers of parcels move in and out of a warehouse every day. When these movements are first written on paper and then entered into the system, time is lost and errors are inevitable. The warehouse app I built for our client TCT Lojistik moves this process onto the phone: parcels are scanned with the camera, records land in the company's system instantly, and labels are printed on networked Zebra printers. I am Berke Özyaşar, and in this post I share the technical decisions and practical lessons from building an app like this.
What does the app do?
- Inbound and outbound cargo flows for the warehouse
- Barcode scanning with the phone camera and, when needed, reading the text on the label with OCR
- Vehicle plate selection, parcel lists and an overview of cargo due to go out
- Cargo lookup
- Creating barcode labels, previewing them and printing on a Zebra printer
- Finding printers on the local network and printer settings
- User login with JWT
The app is built with React Native 0.81 and connects to the company's existing ASP.NET Core and SQL Server infrastructure.
Handheld terminal or phone?
The first thing that comes to mind with warehouse software is an industrial handheld terminal with a built-in laser scanner. In warehouses with heavy scanning, these devices are still the fastest and most durable option. But they are expensive, and buying one for every worker does not make sense for every business. Today's phone cameras, on the other hand, read standard barcodes and QR codes perfectly well.
The good news is that most modern handheld terminals already run Android. An app written in React Native can run on both a phone and a handheld terminal. The terminal's built-in scanner usually passes the scanned code to the app as keyboard input or as a system broadcast, and it is possible to add this input alongside camera scanning. So the hardware decision does not require rewriting the app.
Barcode scanning with the camera
On the camera side I used react-native-vision-camera. The app reads formats common in warehouses, such as Code 128, Code 39, Code 93, EAN-13 and EAN-8. Key points for a scanner like this:
- Limit the formats you scan for. Enabling only the formats used in the warehouse both increases speed and reduces misreads.
- Do not count the same code twice. The camera processes many frames per second, and the same barcode can be read many times in a row. The same code arriving again within a short window needs to be ignored.
- Give clear feedback. A successful scan needs an unmistakable signal; the person working in the warehouse is not watching the screen closely.
- Test with real labels. A test with a clean printout in the office does not show how the app behaves with labels that are crumpled, stretch-wrapped or glaring under warehouse lights.
When the barcode cannot be read: OCR
Not every label is readable. That is why the app has a second scan mode: in OCR mode, the text in the camera image is read too, so the barcode and the text on the label can be recognized together and compared. When the barcode is damaged but the number is legible, the worker does not have to type it in by hand. For OCR I used a text recognition plugin that works with vision-camera; because frames are processed on the camera side, the interface does not freeze.
Label printing: ZPL and Zebra
Zebra printers use a command language called ZPL. Simple labels can be designed directly with ZPL commands, but once a label has a logo, custom fonts or a complex layout, that becomes tedious. In this project I took a different route:
- The label is designed in the app as a normal React Native component and previewed on screen.
- That component is converted into an image.
- The image is scaled to the printer's resolution (203 dpi, 4x6 inch label), rotated if needed and converted into a black-and-white bitmap.
- The bitmap is compressed, embedded in ZPL's graphic command (^GFA) and sent to the printer.
The advantage of this approach is that what you see on screen is what you get on paper; you do not need to know ZPL to change the label design. The thing to watch is that thin lines and barcode bars do not get distorted during the black-and-white conversion. The scaling method and the threshold value are decisive here. Letting the user adjust print scale and position also helps with different label rolls.
Finding the printer on the network
Zebra printers usually accept raw data over the network on port 9100. The app opens a direct TCP connection to the printer with react-native-tcp-socket and sends the ZPL data. Instead of expecting the user to know the printer's IP address, the app scans the local network and lists devices with this port open. Scanning in parallel but with a limited number of connections, then retrying unresponsive addresses with a longer timeout, gave results that were both fast and reliable.
Connecting to the existing system
TCT already had a working server infrastructure. I built the app on top of it rather than replacing it: the mobile app talks to the existing ASP.NET Core API, and the data stays in SQL Server. Authentication is handled with JWT; the token is stored on the device and sent with every request. My advice for projects like this is always the same: the mobile app should not connect to the database directly; there should be an API in between that handles authorization and exposes only the operations that are needed.
Designing for warehouse users
A warehouse app's user is not sitting at a desk. They have a parcel in hand, may be wearing gloves, and the environment is noisy. That is why screens need to be designed around large buttons, few steps and one main task per screen. The most frequent operations, such as inbound and outbound, should start directly from the home screen, with as few menu layers as possible.
From a related area: Scano QR
Camera scanning and extracting text from images are also what Scano QR, my own app live on Google Play, is about. It scans QR codes, creates QR codes with seven different templates and extracts text from images. Issues like reading under different lighting conditions and giving users instant feedback matter just as much in a consumer app as in a warehouse app.
Conclusion
A barcode warehouse app does not require buying expensive hardware or replacing your existing system. With a phone camera, a well-tuned scanning flow, labels designed on screen and converted to ZPL, and an API that connects to the existing server, warehouse records can become real-time. If you are considering a similar solution for your warehouse, take a look at the barcode warehouse and handheld terminal apps page.