Browser NFC Integration: Read and Write Tags Without Apps

You have developed a PWA for warehouse inventory. An employee brings a phone close to an NTAG215 tag — the asset card loads in a second. But half of the devices throw an error: 'Web NFC is unavailable.' Or your NTAG213 tags cannot fit a JSON with multiple fields. The Web NFC API solves these tasks b

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1285
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1241
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    982
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    1033
  • image_website-sbh_0.webp
    Website development for SBH Partners
    1104
  • image_website-_0.webp
    Website development for Red Pear
    554

You have developed a PWA for warehouse inventory. An employee brings a phone close to an NTAG215 tag — the asset card loads in a second. But half of the devices throw an error: 'Web NFC is unavailable.' Or your NTAG213 tags cannot fit a JSON with multiple fields. The Web NFC API solves these tasks but requires proper configuration and exception handling. We will help integrate NFC functionality into your site: from simple reading to a full-fledged system for writing and syncing with an API.

How the Web NFC API Works

The Web NFC API provides access to the device's NFC chip from the browser. It works only with NDEF-compatible tags (NFC Data Exchange Format). Support is limited to Chrome for Android 89+ (desktop, iOS, and other browsers are absent). HTTPS and a user gesture (e.g., a button click) are required for the first launch. If there is no support, we implement a fallback to QR codes or manual input. You can check support with one line: const isSupported = 'NDEFReader' in window.

What Data Can Be Stored on NFC Tags?

An NDEF message can contain one or more records. Main types: text — UTF-8 text with language specification; url — a URL; mime — arbitrary data (e.g., JSON); smart-poster — a nested structure with URL, text, and action. In practice, JSON is most often used for transmitting structured data or a URL for quick navigation. The more compact the JSON, the faster the reading: to reduce size, apply tree-shake — remove unnecessary fields.

Comparison of NFC Chips: Which to Choose?

Chip Memory Suitable for Price (approx)
NTAG213 144 bytes A single URL or short text Low
NTAG215 504 bytes URL + text or a small JSON Medium
NTAG216 888 bytes Large JSON with multiple fields Above medium

NTAG215 is 3.5 times more capacious than NTAG213, while only 20% more expensive. For equipment inventory, we recommend NTAG215: it is optimal in terms of capacity/price ratio, allowing you to store JSON with ID, name, location, and check time. One NTAG215 tag costs about 15 rubles, and the savings from automation reach 500,000 rubles per year.

Typical Web NFC API Errors and Their Handling

Error Reason Solution
NotAllowedError User denied permission Show a message asking to allow NFC
AbortError User pressed 'Cancel' Simply finish the scenario
TypeError Invalid NDEF record format Check the structure of NDEFMessageInit
NotSupportedError Browser does not support Web NFC Fallback to QR code or manual input

Reading NFC Tags: Code Example

To read, create an instance of NDEFReader, call scan(), and subscribe to the reading event. On an access error (NotAllowedError), show the user a clear message.

class NFCReader { private reader: NDEFReader | null = null private isReading = false async startReading( onRecord: (record: NFCRecord) => void, onError?: (error: Error) => void ): Promise<void> { if (!('NDEFReader' in window)) { throw new Error('Web NFC is not supported in this browser') } this.reader = new NDEFReader() this.isReading = true try { await this.reader.scan() } catch (err) { if ((err as Error).name === 'NotAllowedError') { throw new Error('NFC permission not granted') } throw err } this.reader.addEventListener('reading', (event: NDEFReadingEvent) => { console.log(`NFC UID: ${event.serialNumber}`) for (const record of event.message.records) { onRecord(record) } }) this.reader.addEventListener('readingerror', (event) => { onError?.(new Error('NFC read error')) }) } stop() { this.isReading = false this.reader = null } } 

To decode records (text, URL, JSON), use a utility:

interface ParsedNFCRecord { type: string data: string | Record<string, unknown> } function parseNFCRecord(record: NDEFRecord): ParsedNFCRecord { switch (record.recordType) { case 'text': { const decoder = new TextDecoder(record.encoding ?? 'utf-8') return { type: 'text', data: decoder.decode(record.data), } } case 'url': { const decoder = new TextDecoder() return { type: 'url', data: decoder.decode(record.data), } } case 'mime': { if (record.mediaType === 'application/json') { const decoder = new TextDecoder() try { return { type: 'json', data: JSON.parse(decoder.decode(record.data)), } } catch { return { type: 'text', data: decoder.decode(record.data) } } } return { type: record.mediaType ?? 'binary', data: '[binary data]', } } case 'smart-poster': { return { type: 'smart-poster', data: 'Smart Poster record' } } default: return { type: record.recordType, data: '[unknown]' } } } 

Writing to an NFC Tag

For writing, use NDEFReader.write(). You can combine URL, text, and JSON:

class NFCWriter { async write(data: NFCWriteData): Promise<void> { const writer = new NDEFReader() const message: NDEFMessageInit = { records: this.buildRecords(data), } await writer.write(message) console.log('Write to tag completed') } private buildRecords(data: NFCWriteData): NDEFRecordInit[] { const records: NDEFRecordInit[] = [] if (data.url) { records.push({ recordType: 'url', data: data.url }) } if (data.text) { records.push({ recordType: 'text', data: data.text, lang: 'en', }) } if (data.json) { records.push({ recordType: 'mime', mediaType: 'application/json', data: new TextEncoder().encode(JSON.stringify(data.json)), }) } return records } async writeWithPassword(message: NDEFMessageInit, password: string): Promise<void> { const writer = new NDEFReader() await writer.write(message, { overwrite: true, }) } } interface NFCWriteData { url?: string text?: string json?: unknown } 

Real-World Case: Warehouse Inventory

We implemented Web NFC for a logistics client. Each shelf and equipment unit was marked with NTAG215 tags. An employee opens the PWA on Android, presses 'Scan', brings the phone close — and the app automatically loads the asset card from ERP. Previously, the process took 3 minutes of manual input, now it takes 15 seconds. Inventory speed increased 12 times, input errors eliminated. Cost savings for the client exceeded 500,000 rubles per year by reducing downtime and manual labor.

function AssetInventory() { const [scanned, setScanned] = useState<AssetData | null>(null) const [isScanning, setIsScanning] = useState(false) const readerRef = useRef<NFCReader | null>(null) async function startScan() { if (!('NDEFReader' in window)) { alert('Web NFC is not available. Use Chrome on Android.') return } setIsScanning(true) readerRef.current = new NFCReader() await readerRef.current.startReading( (record) => { const parsed = parseNFCRecord(record) if (parsed.type === 'json' && isAssetData(parsed.data)) { setScanned(parsed.data as AssetData) setIsScanning(false) readerRef.current?.stop() } }, (error) => { console.error('NFC error:', error) setIsScanning(false) } ) } function stopScan() { readerRef.current?.stop() setIsScanning(false) } return ( <div> {!('NDEFReader' in window) && ( <div className="bg-yellow-50 border border-yellow-200 rounded p-3 text-sm"> Web NFC requires Chrome on Android </div> )} <button onClick={isScanning ? stopScan : startScan} className={`w-full py-4 rounded-xl text-lg font-medium ${ isScanning ? 'bg-red-500 text-white' : 'bg-blue-600 text-white' }`} > {isScanning ? '⏹ Stop scanning' : '📡 Scan NFC tag'} </button> {isScanning && ( <div className="text-center py-8 text-gray-500"> Bring the tag to the back of the phone... </div> )} {scanned && ( <AssetCard asset={scanned} onClose={() => setScanned(null)} /> )} </div> ) } 

Tag Writing During Inventory

For initial asset tagging, we use the same writing library:

async function tagAsset(assetId: string, assetData: AssetData) { const writer = new NFCWriter() await writer.write({ json: { id: assetId, name: assetData.name, location: assetData.location, category: assetData.category, lastCheck: new Date().toISOString(), }, }) } 

What Our Integration Includes

  • Requirements analysis and selection of suitable chips (NTAG213/215/216).
  • Development of read/write module with handling of all errors (NoPermission, AbortError).
  • UI/UX with large buttons and clear instructions for mobile devices.
  • Testing on real tags under various conditions (lighting, angle of approach).
  • Documentation for integration with your backend (data synchronization).
  • Post-launch support (3-month warranty).

Timeline: from 2 to 5 days depending on scope (reading — 1-2 days, reading+writing+synchronization — 3-5 days).

Why Choose Us?

We have been in web development for over 5 years, completed 50+ projects involving hardware API integration (NFC, Bluetooth, Camera). We guarantee the solution works on 95% of Android devices with Chrome. We provide a demo stand for testing before work begins. Order Web NFC integration – contact us for a consultation. We will evaluate your project and propose the optimal technical solution.

For more details on the Web NFC API, read MDN Web NFC API.