All articles

Technical

Using the Web NFC API in Android Trusted Web Activities

September 23, 2026 · 8 min read

Physical Web Interaction in Android TWAs

Near Field Communication (NFC) enables short-range wireless communication between compatible devices, such as an Android phone and an unpowered physical tag. While native Android applications have historically had exclusive access to this hardware, the Web NFC API brings this capability directly to web applications. For developers converting their Progressive Web Apps (PWAs) into native Android packages using a Trusted Web Activity (TWA), this means physical-world features can be implemented without writing complex native Kotlin or Java bridges.

Web NFC is currently supported in Chromium-based browsers on Android, making it a natural fit for TWAs. Because a TWA is rendered by the system's underlying Chrome browser engine, your converted app can interact with physical tags to support use cases like inventory management, asset tracking, museum exhibits, interactive gaming, and keycard verification. This guide covers how to implement, secure, and troubleshoot Web NFC within your Android TWA environment.

Web NFC Security and the TWA Trust Model

Accessing raw physical hardware presents potential privacy and security risks. To protect users, the Chromium project enforces strict security boundaries for Web NFC. Understanding these rules is essential to ensure your code functions properly once packaged inside a TWA.

First, Web NFC is restricted to secure contexts, meaning your PWA must be served exclusively over HTTPS. Second, Web NFC operations are only permitted in top-level browsing contexts. This means you cannot trigger NFC scans or writes inside nested iframes. Third, all NFC operations require a user gesture. Your application cannot silently listen for tags in the background immediately upon launch; the user must actively interact with your interface to start the NFC process.

When running inside a Trusted Web Activity, your PWA benefits from the established trust relationship verified by Digital Asset Links. Because Digital Asset Links link your Android package name directly to your web domain, your app operates within a verified container. This ensures that permissions requested by Chrome on behalf of your TWA feel seamless to the user.

Detecting Support and Requesting Permissions

Before attempting to interact with the device hardware, you must verify that both the browser and the system support Web NFC. Your application should gracefully handle devices that lack NFC hardware, or where the user has disabled NFC in their Android system settings.

You can check for support by verifying the existence of the NDEFReader object on the window scope. If the object is missing, you should hide NFC-related user interface elements or display an appropriate fallback message.if (typeof NDEFReader !== "undefined") { console.log("Web NFC is supported"); } else { console.log("Web NFC is not supported on this device"); }

In addition to browser-level availability, you must check the permission state. The Permissions API allows you to query the current status of NFC access without prompting the user immediately.const status = await navigator.permissions.query({ name: "nfc" }); if (status.state === "denied") { console.log("NFC access is blocked by user settings"); }

Reading NDEF Data in a TWA

NFC Data Exchange Format (NDEF) is the standard format used to encode data onto NFC tags. Reading tags requires instantiating the NDEFReader class, calling the scan method, and listening for reading events. Because the scan method requires a user gesture, you must bind this call to an action like a button click.

The following example demonstrates how to set up an NFC reader that parses text records and JSON data from scanned tags:

async function startNFCScan() { try { const reader = new NDEFReader(); await reader.scan(); reader.addEventListener("reading", ({ message, serialNumber }) => { console.log("Tag Serial Number: " + serialNumber); for (const record of message.records) { if (record.recordType === "text") { const textDecoder = new TextDecoder(record.encoding); console.log("Text Record: " + textDecoder.decode(record.data)); } else if (record.recordType === "json") { const textDecoder = new TextDecoder(); const json = JSON.parse(textDecoder.decode(record.data)); console.log("JSON Record:", json); } } }); } catch (error) { console.error("NFC scan failed: " + error); } }

When the user taps an NFC tag against their phone while your TWA is active, the reading event is fired. The message object contains an array of records, which you must decode based on their recordType. This allows you to process multiple pieces of data stored on a single physical tag.

Writing NDEF Messages to Tags

Writing data to physical tags follows a similar structural pattern using the NDEFReader write method. Writing is also subject to the user gesture rule and will fail if executed outside of an active user interaction event loop.

You can write plain text, custom URLs, JSON payloads, or external records to standard NDEF-compatible tags. Below is an implementation showing how to execute a write operation containing both a plain text message and a structured payload:

async function writeNFCTag() { try { const reader = new NDEFReader(); const payload = [ { recordType: "text", data: "PWA to TWA Integration" }, { recordType: "url", data: "https://pwatoapp.com" } ]; await reader.write({ records: payload }); console.log("Data successfully written to tag"); } catch (error) { console.error("NFC write failed: " + error); } }

The write promise will resolve only after the physical tag is successfully detected and written to. If the user moves the device away from the tag before the write completes, the promise will reject with a NetworkError. It is important to display a visual prompt instructing the user to keep their device close to the tag during the operation.

Handling Errors and Hardware Exceptions

NFC interactions are prone to hardware and environment exceptions. Your application must handle these gracefully to prevent app crashes and provide a polished user experience. Common exception types thrown by the Web NFC API include:

  • NotAllowedError: Thrown when the user denies permission to access the NFC hardware, or when the operation is not triggered by a user gesture.
  • NotSupportedError: Thrown if the device does not possess NFC hardware, or if the hardware is turned off in Android settings.
  • NetworkError: Thrown when the physical connection between the phone and the tag is broken mid-transfer.

By catching these errors specifically, you can guide the user to turn on NFC in their system settings or prompt them to try scanning again with better alignment.

NFC Compatibility Matrix

The following table outlines where Web NFC features are fully operational, helping you understand when to present alternative flows for non-Android users:

Platform and BrowserNFC Support StatusCapabilities
Android TWA (via Chrome)Fully SupportedRead and Write NDEF records
Android Chrome MobileFully SupportedRead and Write NDEF records
iOS Safari / Web ViewUnsupportedNone (Requires Native SDK)
Desktop ChromeUnsupportedNone (Requires external hardware)

Because your PWA can be built to run cross-platform, implementing Web NFC in your TWA provides native-like hardware integration for your Android users while safely falling back to standard inputs, like barcode scanners or manual typing, for users on unsupported platforms.

Ready to ship your Android app?

Paste your PWA URL, get a signed APK and a Google Play ready AAB in minutes.

Build my app