Understanding NFC and the Web NFC API
Near Field Communication (NFC) enables wireless communication between two devices at close proximity, typically less than a few centimeters. Operating at 13.56 MHz, NFC is an international standard (ISO/IEC 18092) that defines an interface and protocol for simple wireless interconnection of closely coupled devices.
The Web NFC API allows web applications to interact with NFC tags, providing a powerful tool for bridging the gap between the physical and digital worlds directly from the browser. This API enables selected use cases based on NFC technology, with the current scope focused specifically on NDEF (NFC Data Exchange Format) interactions.
The technology works through magnetic induction, where the reader emits a small electric charge creating a magnetic field that powers passive devices and enables data exchange. This electromagnetic coupling allows NFC tags--which contain no power source of their own--to transmit data simply by being brought within range of a powered device.
Key Requirements for Web NFC
The API requires several important conditions for operation:
- Secure Context (HTTPS): NFC interactions must be protected from unauthorized access
- Page Visibility: The webpage must be visible when NFC interactions occur
- User Permission: Explicit consent is required before NFC operations can proceed
These requirements ensure that NFC functionality is used safely and with user awareness, preventing malicious websites from accessing NFC data without consent. Implementing these security measures is a core aspect of our secure web development practices.
The Web NFC API provides essential operations for interacting with NFC tags
Read NFC Tags
Retrieve NDEF messages from NFC tags when devices come within range, enabling access to stored information like URLs, text, or custom data formats.
Write to NFC Tags
Program NFC tags with custom data including URLs, text messages, JSON data, and smart poster records for rich content sharing.
Make Tags Read-Only
Permanently lock NFC tags against future modifications, ensuring content integrity for ticketing, authentication, and product labeling applications.
Multi-Record Support
Work with complex NDEF messages containing multiple records of different types, including embedded smart posters and custom data structures.
NDEF: The NFC Data Exchange Format
NDEF (NFC Data Exchange Format) is a lightweight binary message format standardized by the NFC Forum that enables consistent data exchange across NFC devices and tags. An NDEF message encapsulates one or more application-defined NDEF records, and these messages can be stored on NFC tags or exchanged between NFC-enabled devices.
NDEF Record Structure
Each NDEF record is a binary structure containing:
- Header Byte: Contains flags for message begin/end, chunking, short record, and ID length
- Type Length: Byte size of the type field
- Payload Length: Size of the payload (1 byte for short records, 4 bytes for normal)
- Type Field: Describes the payload type (T, U, Sp, etc.)
- ID Field: Optional record identifier
- Payload Field: The actual application data
TNF: Type Name Format Values
The TNF (Type Name Format) field indicates the format of the type name and describes the NDEF record payload type. Seven TNF values are defined, each representing a different record category:
| TNF Value | Description | Use Case |
|---|---|---|
| 0 | Empty record (no content) | Placeholder or initialization |
| 1 | NFC Forum well-known type | Text, URL, smart poster records |
| 2 | MIME type record | Binary data with MIME type |
| 3 | Absolute-URL record | Complete URL in type field |
| 4 | NFC Forum external type | Application-specific data (urn:nfc:ext:domain:type) |
| 5 | Unknown record | Opaque data without MIME type |
| 6 | Unchanged (chunk continuation) | Multi-record chunked payloads |
For most web applications, TNF value 1 (well-known types) covers common use cases like text and URL records. External types (TNF 4) are useful when you need custom data formats shared between specific applications. The empty record type (TNF 0) serves as a placeholder in multi-record messages.
| Type | Standard | Memory | Speed | Key Features |
|---|---|---|---|---|
| Type 1 | ISO/IEC 14443-3A | 96 bytes - 2 KB | 106 kbit/s | No anti-collision, rewritable |
| Type 2 | ISO/IEC 14443-3A | 48 bytes - 2 KB | 106 kbit/s | Rewritable, configurable read-only |
| Type 3 | JIS X 6319-4 (FeliCa) | 2 KB | 212/424 kbit/s | Preconfigured read-only/rewritable |
| Type 4 | ISO/IEC 14443-4 A/B | Up to 32 KB | 106/212/424 kbit/s | Variable memory, ISO-DEP support |
| Type 5 | ISO/IEC 15693 | Up to 64 KB | 26.48 kbit/s | Long range RFID compatible |
Core Web NFC API Interfaces
The Web NFC API provides three primary interfaces that form the foundation of NFC interactions in web applications.
NDEFReader Interface
The NDEFReader interface enables reading and writing NDEF messages from compatible NFC tags. This interface extends EventTarget and provides methods for initiating scans, writing data, and making tags permanently read-only.
Key Methods:
scan(options): Initiates NFC polling and returns a Promisewrite(message, options): Queues data for writing to the next NFC tagmakeReadOnly(options): Permanently locks an NFC tag
Event Handlers:
onreading: Called when an NFC tag comes within rangeonreadingerror: Called when an error occurs during reading
// NDEFReader instantiation and basic setup
const ndef = new NDEFReader();
// Set up reading event handler
ndef.onreading = (event) => {
console.log(`Tag detected: ${event.serialNumber}`);
for (const record of event.message.records) {
console.log(`Record type: ${record.recordType}`);
}
};
// Handle errors
ndef.onreadingerror = (error) => {
console.log(`NFC error: ${error.message}`);
};
NDEFMessage Interface
The NDEFMessage interface represents NDEF messages received from or sent to NFC tags. This interface exposes a frozen array of NDEFRecord objects through its records property, enabling iteration over all records in a message.
NDEFRecord Interface
The NDEFRecord interface represents individual records within NDEF messages:
recordType: The type of record (text, url, mime, etc.)mediaType: MIME type for MIME recordsid: Record identifierdata: DataView containing payload bytesencodingandlang: Text encoding and language for text recordstoRecords(): Parses nested records from payload data
1const ndef = new NDEFReader();2 3ndef.onreading = (event) => {4 console.log("NDEF message read from tag");5 6 for (const record of event.message.records) {7 console.log(`Record type: ${record.recordType}`);8 console.log(`MIME type: ${record.mediaType}`);9 10 const decoder = new TextDecoder();11 console.log(`Data: ${decoder.decode(record.data)}`);12 }13};14 15ndef.scan().then(() => {16 console.log("Scanning started successfully");17}).catch(error => {18 console.log(`Scan failed: ${error}`);19});Processing Different Record Types
Processing different record types requires identifying the record type and decoding the payload appropriately:
ndef.onreading = (event) => {
const decoder = new TextDecoder();
for (const record of event.message.records) {
switch (record.recordType) {
case "text":
const textDecoder = new TextDecoder(record.encoding);
console.log(`Text: ${textDecoder.decode(record.data)} (${record.lang})`);
break;
case "url":
console.log(`URL: ${decoder.decode(record.data)}`);
break;
case "mime":
if (record.mediaType === "application/json") {
const json = JSON.parse(decoder.decode(record.data));
console.log(`JSON: ${JSON.stringify(json)}`);
} else if (record.mediaType.startsWith("image/")) {
const blob = new Blob([record.data], { type: record.mediaType });
const img = document.createElement("img");
img.src = URL.createObjectURL(blob);
document.body.appendChild(img);
}
break;
}
}
};
Reading a Single Tag
Stop scanning after reading one tag to conserve battery:
function readOnce() {
return new Promise((resolve, reject) => {
const controller = new AbortController();
controller.signal.onabort = reject;
ndef.addEventListener("reading", (event) => {
controller.abort();
resolve(event);
}, { once: true });
ndef.scan({ signal: controller.signal }).catch(reject);
});
}
This pattern uses AbortController to automatically stop scanning once a tag is read, which is essential for battery-efficient mobile implementations.
Writing to NFC Tags
Writing NFC tags enables applications to program physical objects with digital content, from simple text messages to complex structured data.
Basic Writing Operations
const ndef = new NDEFReader();
// Writing a simple text message
ndef.write("Hello World").then(() => {
console.log("Text message written successfully");
});
// Writing a URL with explicit record type
ndef.write({
records: [{ recordType: "url", data: "https://example.com/" }]
}).then(() => {
console.log("URL written successfully");
});
Writing Structured Data
const ndef = new NDEFReader();
const encoder = new TextEncoder();
ndef.write({
records: [
{ recordType: "url", data: "https://example.com/page" },
{ recordType: "text", data: "Example Page", lang: "en" },
{
recordType: "mime",
mediaType: "application/json",
data: encoder.encode(JSON.stringify({ id: 42, timestamp: Date.now() }))
}
]
}).then(() => {
console.log("Multi-record message written");
});
Writing Smart Posters
const ndef = new NDEFReader();
const encoder = new TextEncoder();
ndef.write({
records: [{
recordType: "smart-poster",
data: {
records: [
{ recordType: "url", data: "https://example.com/content/19911" },
{ recordType: "text", data: "Content Title" },
{ recordType: ":t", data: encoder.encode("video/mp4") },
{ recordType: ":s", data: new Uint32Array([4096]) },
{ recordType: ":act", data: new Uint8Array([0]) }
]
}
}]
});
Smart poster records provide a comprehensive format for sharing web content, including URL, title, media type, size, and desired action when scanned.
Making Tags Permanently Read-Only
The makeReadOnly() method permanently locks NFC tags against future modifications, which is essential for applications where tag content should remain unchanged after initial programming. This operation is irreversible and should be used carefully.
const ndef = new NDEFReader();
// Make a tag read-only after writing content
ndef.write("Permanent content").then(async () => {
console.log("Content written");
await ndef.makeReadOnly();
console.log("Tag is now permanently read-only");
});
// Make read-only directly
ndef.makeReadOnly().then(() => {
console.log("Tag made permanently read-only");
});
The makeReadOnly operation follows similar timing patterns to write operations, requiring the tag to be scanned and verified before the lock is applied. Once locked, no further writes or makeReadOnly operations can modify the tag. This permanence makes it ideal for ticketing, authentication, and product labeling applications where content integrity is critical.
Important considerations:
- Test makeReadOnly operations on your target tag types before deployment
- Some tags may have manufacturer-specific lock mechanisms that persist beyond NDEF locking
- Always verify the lock succeeded by attempting to write after the operation
1function isWebNFCAvailable() {2 return "NDEFReader" in window;3}4 5if (isWebNFCAvailable()) {6 // Web NFC is available7 const ndef = new NDEFReader();8 // Proceed with NFC operations9} else {10 // Provide alternative experience11 alert("Please use a compatible browser with NFC support");12}Security Requirements
Secure Context (HTTPS)
The Web NFC API requires a secure context (HTTPS) to prevent unauthorized access to NFC functionality. This requirement ensures that NFC interactions are encrypted and authenticated, protecting users from potential attacks. Development over HTTP is possible on localhost for testing, but production deployments must use HTTPS.
Permission Model
Web NFC is classified as a powerful feature requiring user permission before use. The permission model varies by browser but typically involves a prompt when the page first attempts NFC operations. Users must explicitly grant permission for NFC access, and this permission can be revoked through browser settings.
Visibility-Based Access
NFC operations only occur when the page is visible, preventing background websites from accessing NFC data without user awareness. This provides an additional layer of privacy protection and ensures users know when NFC interactions are happening.
Protecting Users
These security measures work together to protect users in several ways:
- HTTPS encryption prevents eavesdropping on NFC commands
- User permission ensures explicit consent before any NFC access
- Visibility requirement prevents covert NFC scanning in background tabs
- Secure context requirement blocks NFC access from insecure iframes
Developers should communicate these protections to users, explaining that NFC access requires their explicit permission and that the website cannot access NFC when hidden or running over insecure connections. Our web development team follows these security best practices for all client projects.
Web NFC enables innovative applications across multiple industries
Interactive Marketing
NFC tags in product packaging and displays provide instant access to digital content, promotional offers, and product information without app installation.
Event Ticketing
Digital tickets on NFC-enabled passes can be scanned using web applications for seamless check-in without dedicated hardware.
Product Authentication
NFC tags embedded in products enable verification of authenticity, origin tracking, and supply chain transparency.
Gaming & Entertainment
Mobile games can use NFC tags for physical gameplay elements, unlocking content, and sharing progress through physical interactions.
Best Practices and Performance Considerations
Optimizing Tag Reading Performance
Efficient NFC implementation minimizes battery consumption while providing responsive experiences. Stop scanning after reading the required information:
function readForDuration(durationMs) {
return new Promise((resolve) => {
const controller = new AbortController();
ndef.addEventListener("reading", (event) => {
resolve(event);
controller.abort();
}, { once: true });
setTimeout(() => controller.abort(), durationMs);
ndef.scan({ signal: controller.signal });
});
}
Error Handling
ndef.onreadingerror = (event) => {
console.log("Error reading NFC tag. Try a different tag.");
};
ndef.scan().then(() => {
console.log("Ready to scan");
}).catch(error => {
if (error.name === "NotAllowedError") {
console.log("NFC permission denied");
} else if (error.name === "NotSupportedError") {
console.log("NFC not supported on this device");
}
});
User Experience Design
- Provide clear instructions for tapping NFC tags before scanning begins
- Include visual and haptic feedback for successful reads when possible
- Handle errors gracefully with actionable messages (e.g., "Try a different tag")
- Consider timing out scans to prevent battery drain on mobile devices
- Test with actual target tag types, as performance varies by hardware
Tag Programming Best Practices
When programming NFC tags for your applications, consider these guidelines:
- Use URL records with appropriate compression to maximize stored information
- Specify language tags for text records to ensure proper display across locales
- For complex data, use JSON-encoded MIME records with consistent versioning
- Test write operations on the exact tag hardware you'll deploy in production
- Document your tag data format for future maintenance and compatibility
Frequently Asked Questions
Conclusion
The Web NFC API represents a significant capability for modern web applications, enabling direct interaction with NFC tags without requiring native applications. This technology bridges the physical and digital worlds, creating opportunities for innovative user experiences across retail, events, gaming, and beyond.
While current browser support is limited primarily to Chromium-based browsers on Android, the specification continues to mature and may see broader adoption as the web platform evolves. Developers implementing Web NFC should use feature detection, provide appropriate fallbacks, and focus on use cases where the technology provides clear advantages over alternatives like QR codes or native apps.
The combination of secure context requirements, explicit user permission, and visibility-based operation ensures that Web NFC provides strong security and privacy protections. These safeguards make it suitable for sensitive applications like ticketing and authentication.
Understanding NDEF format, core interfaces, and operational patterns enables developers to build robust NFC-enabled applications that enhance user engagement through seamless physical-digital interactions. When combined with our web development services, Web NFC enables creating innovative contactless experiences that set your applications apart. Our AI automation expertise can also help integrate NFC with intelligent workflows for enhanced business automation.
Sources: