Glossary

Web NFC

Web NFC is a browser API that lets a web page read and write NFC tags, using the NDEF message format, through the NDEFReader interface. NFC stands for Near Field Communication, wireless contact at a distance of a few centimeters on 13.56 MHz. Web NFC is a W3C Community Group draft that its own text calls unstable, and it works only in secure contexts.

How it works

The entry point is the NDEFReader class. Feature detection is "NDEFReader" in window, and the spec warns that a true result does not prove NFC hardware exists. The API is a default powerful feature with the permission name "nfc", so the browser asks the user before scanning or writing.

NDEF stands for NFC Forum Data Exchange Format, a small binary message format. A message holds a list of records. In JavaScript each NDEFRecord exposes recordType, mediaType, id, encoding, lang and data. The common recordType values are "text", "url", "mime", "smart-poster" and "empty". The data property is a DataView, so you decode text with TextDecoder.

The methods map to the three jobs:

  • scan() starts polling for tags. Each tag fires a reading event with serialNumber and a message.
  • write() stores records on a tag. The overwrite option defaults to true. With false, the write is skipped if the tag already has NDEF records.
  • makeReadOnly() locks a tag permanently.

An NFC reader works by polling, and the spec points out a side effect. If you call write() or makeReadOnly() without a running scan(), the browser polls just long enough to find the tag, reads it first, and then performs the write. If scan() is already running with a reading listener, that listener fires once during the write too.

The scope is limited to NDEF. Low-level operations such as ISO-DEP and NFC-A/B/F, plus card emulation, are out of scope, and peer-to-peer is not supported. The sample below runs in Node with a simulated message shaped like a real one, because Node has no NFC.

const enc = new TextEncoder();
const bytes = enc.encode("Hello World");
const message = { records: [
  { recordType: "text", encoding: "utf-8", lang: "en", data: new DataView(bytes.buffer) },
  { recordType: "url", data: new DataView(enc.encode("https://example.com/").buffer) },
  { recordType: "empty" },
] };
for (const record of message.records) {
  switch (record.recordType) {
    case "text": console.log(`Text: ${new TextDecoder(record.encoding).decode(record.data)} (${record.lang})`); break;
    case "url": console.log(`URL: ${new TextDecoder().decode(record.data)}`); break;
    default: console.log("Record type:", record.recordType);
  }
}
console.log("supported check:", "NDEFReader" in globalThis);

Output:

Text: Hello World (en)
URL: https://example.com/
Record type: empty
supported check: false

Which browsers support Web NFC?

Web NFC is available in Chrome on Android 89 and later. MDN compatibility data shows no support in desktop Chrome, Firefox or Safari, and marks NDEFReader as experimental. A page on an iPhone or a laptop cannot read tags with it, so offer a QR code or manual entry as the fallback.

Common pitfalls

  • Treating "NDEFReader" in window as proof of hardware: it only shows the API exists. Handle the error when scan() or write() fails on a phone with NFC switched off.
  • Expecting a background read: the spec describes reading while the top-level document is visible, and the HTML Standard lists Web NFC among the specs that run steps when visibility changes. Design for a foreground tap.
  • Calling write() while scan() has a reading listener: the listener fires once during the write. Use an AbortSignal and stop the scan or ignore that event.
  • Overwriting by accident: overwrite defaults to true. Pass overwrite: false to protect tags that already hold data.
  • Decoding without the record encoding: text records carry encoding and lang. Pass record.encoding to TextDecoder instead of assuming UTF-8.
  • Planning card emulation or raw commands: both are out of scope, so use a native app for payment cards or non-NDEF tags.

Related terms

  • HTTPS — the secure context Web NFC requires
  • Permissions-Policy header — can gate powerful features in embedded frames
  • Web Bluetooth — another short-range wireless device API
  • WebUSB — the wired counterpart for custom hardware
  • DOM — the visibility and event model the API hooks into

See also

  • Term: Web Bluetooth — the closest alternative when a device speaks Bluetooth Low Energy instead of NFC