Integrating an RFID Reader into a React Application Using the Web Serial API

Mathan Kumar

4 min read

RFID Reader into a React Application Using the Web Serial API

Introduction

Recently, I worked on integrating an RFID reader into a React application. Although I’ve integrated APIs and third-party libraries many times before, working with hardware devices was a completely different experience. It gave me an opportunity to understand how browsers communicate with physical devices and how browser APIs can be used beyond traditional web development.

RFID Reader into a React Application Using the Web Serial API

Like many developers, my first assumption was that the hardware team would provide a private npm package that I could install and use directly.

I expected the integration to be as simple as:

import { connectRFID, scanTag } from “@company/rfid-sdk”; 

The plan seemed straightforward:

  • Install the package
  • Import the required functions
  • Connect the device
  • Start scanning RFID tags

However, the actual implementation was very different.

Instead of an npm package, I received a standalone SDK built with HTML, CSS, and JavaScript. At first, I wasn’t sure how I was supposed to integrate an entire web application into an existing React project.

Rather than trying to embed the SDK into my application, I decided to understand how it worked internally. That decision completely changed my approach.

Expected npm package vs HTML/CSS/JS SDK

Understanding the SDK for RFID

After exploring the SDK, I found that it wasn’t a React library or a complex framework. It was simply a collection of HTML, CSS, and JavaScript files that communicated with the RFID reader.

As I read through the source code, one thing became clear: the SDK wasn’t performing any hidden logic. It was simply acting as a wrapper around the browser’s Web Serial API.

Its overall workflow was quite simple:

  • Open a serial connection
  • Send commands to the RFID reader
  • Read the device response
  • Extract the RFID tag information
  • Return the result to the application

Once I understood this flow, I realized there was no need to integrate the entire SDK. Instead, I could implement only the functionality my application required while keeping everything inside the React codebase.

This approach made the application cleaner, easier to maintain, and much more flexible.

architecture diagram showing: HTML/CSS/JS SDK → Web Serial API → RFID Reader.

 

Designing the Solution to Connect with RFID

To keep the implementation organised, I separated the hardware communication into reusable service functions rather than placing the logic inside React components.

The communication flow looked like this:

Connect Device

      ↓

Open Serial Port

      ↓

Send Command

      ↓

Read Response

      ↓

Extract EPC

      ↓

Return RFID Tags

Keeping each responsibility separate made the code easier to test, debug, and extend in the future.

flow diagram showing the RFID communication lifecycle

 

Connecting to the RFID Reader

The first step was establishing communication with the RFID reader.

Using the browser’s Web Serial API, the application requests permission to access a serial device:

navigator.serial.requestPort();

After the user selects the appropriate device, the serial connection is opened with the required baud rate.

await port.open({

  baudRate: 38400,

});

To avoid duplicating connection logic across components, I created reusable helper functions such as:

  • connectRFID()
  • disconnectRFID()
  • isRFIDConnected()
  • getConnectedPort()

Encapsulating this logic in a dedicated service kept the UI clean and made the connection lifecycle much easier to manage.

flow diagram showing: Request Port → Select Device → Open Port → Connected

 

Sending Commands to the RFID Reader

Once the connection is established, the application needs to communicate with the RFID reader by sending commands.

To simplify this process, I created a reusable helper:

sendCommand(command)

This function is responsible for converting commands into byte arrays, writing them to the serial port, and safely releasing the writer once the operation is complete.

Having a single function handle all outgoing communication keeps the implementation consistent and makes future command additions straightforward.

 

Reading RFID Device Responses

Reading data from the RFID reader was one of the most interesting parts of the project.

Unlike a traditional REST API request, the RFID reader continuously streams serial data. This means the application must listen for incoming responses without blocking the user interface.

To avoid waiting indefinitely, I implemented a timeout using Promise.race(). The application waits for whichever occurs first:

  • A response from the RFID reader
  • A timeout

This approach keeps the application responsive while ensuring that incoming RFID data is processed efficiently.

 

Extracting the EPC from RFID

The RFID reader returns more than just the RFID tag. Each response includes protocol information, headers, footers, and additional metadata.

For example:

AAAAA300833B2DDD901400000000BBBB

Since the application only requires the Electronic Product Code (EPC), I created a helper function:

extractEPC(response)

This function removes the unnecessary protocol information and returns only the EPC value.

By isolating this logic, the rest of the application remains independent of the device’s communication protocol.

 

Handling Duplicate Tags

During testing, I noticed that the RFID reader often detected the same tag multiple times within a short interval.

Processing duplicate values would create unnecessary work for the application, so I used JavaScript’s Set to ensure that each scan returned only unique RFID tags.

new Set(tags)

This small improvement significantly reduced redundant processing and simplified downstream logic.

 

Continuous Scanning the Tags

One of the project requirements was continuous scanning.

Instead of performing a single scan, the application needed to keep reading RFID tags until the user manually stopped the process.

To support this, I implemented two methods:

  • startContinuousScan()
  • stopContinuousScan()

The scanning loop repeatedly performs the following steps:

  1. Send the scan command
  2. Read the device response
  3. Extract the EPC value
  4. Return the detected tag to the React component
  5. Repeat until scanning is stopped

This approach works well for inventory management, warehouse operations, and asset tracking scenarios where real-time scanning is essential.

 

Overall Architecture

After separating responsibilities, the final architecture became much simpler.

React Components

        │

        ▼

RFID Service Layer

        │

        ▼

Web Serial API

        │

        ▼

RFID Reader

The React components focus solely on the user interface, while the service layer handles all communication with the hardware.

This separation makes the codebase easier to understand and simplifies future enhancements.

 

Why This Approach Worked Well

Building a dedicated RFID service instead of integrating the complete SDK provided several advantages:

  • A cleaner and more maintainable architecture
  • Better separation of concerns
  • Reusable communication logic
  • Easier testing and debugging
  • Simpler future enhancements
  • No unnecessary SDK files inside the React project

Most importantly, the solution fits naturally into any React application without introducing additional complexity.

Project structure

 

Key Takeaways

This project was about much more than connecting an RFID reader.

It reinforced several engineering practices that apply to many software projects:

  • Take time to understand how an SDK works before integrating it.
  • Focus on the underlying problem rather than blindly using provided libraries.
  • Keep hardware communication separate from UI logic.
  • Build reusable service layers whenever possible.
  • Explore browser capabilities such as the Web Serial API.
  • Treat SDKs as learning resources rather than black boxes.

These lessons have influenced how I approach integrations today.

 

Final Thoughts

When I first received the SDK, I expected a plug-and-play npm package. Instead, I was given a standalone HTML, CSS, and JavaScript application.

Although it seemed challenging at first, taking the time to understand the SDK proved to be the right decision. Once I realized it was simply using the browser’s Web Serial API, I was able to build a solution tailored to my application’s architecture instead of forcing the SDK into my project.

The end result was a lightweight, reusable RFID service that was easier to maintain, easier to extend, and fully integrated into the React application.

This experience reminded me that the best solution isn’t always the one that’s provided. Sometimes, investing time to understand the underlying technology leads to a cleaner and more scalable implementation.

If you’re integrating an RFID device into a React application and receive a similar SDK, I’d encourage you to explore how it works internally before integrating it. Understanding the communication flow can help you build a solution that’s better aligned with your application’s architecture and easier to maintain in the long run.

Happy Coding! 🚀

Technologies Used

  • React.js
  • TypeScript
  • Web Serial API
  • JavaScript (ES6+)
  • RFID Reader SDK
Related posts:

Leave a Reply

Your email address will not be published. Required fields are marked *