Web NFC

Draft Community Group Report

Latest editor's draft:
https://w3c.github.io/web-nfc/
Test suite:
https://wpt.fyi/web-nfc/
Editors:
Kenneth Rohde Christiansen ( Intel )
Zoltan Kis ( Intel )
François Beaufort ( Google LLC )
Former editor:
Alexander Shalamov ( Intel )
Participate:
GitHub w3c/web-nfc
File a bug
Commit history
Pull requests

Abstract

Near Field Communication (NFC) enables wireless communication between two devices at close proximity, usually less than a few centimeters. NFC is an international standard (ISO/IEC 18092) defining an interface and protocol for simple wireless interconnection of closely coupled devices operating at 13.56 MHz.

The hardware standard is defined in NFC Forum Technical Specifications .

This document defines an API to enable selected use cases based on NFC technology. The current scope of this specification is NDEF .

Low-level I/O operations (e.g. ISO-DEP, NFC-A/B, NFC-F) and Host-based Card Emulation (HCE) are not supported within the current scope.

Status of This Document

This is a preview

Do not attempt to implement this version of the specification. Do not reference this version as authoritative in any way. Instead, see https://w3c.github.io/web-nfc/ for the Editor's draft.

This specification was published by the Web NFC Community Group . It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups .

Implementers need to be aware that this specification is considered unstable. Implementers who are not taking part in the discussions will find the specification changing out from under them in incompatible ways. Vendors interested in implementing this specification before it eventually reaches the Candidate Recommendation phase should subscribe to the repository on GitHub and take part in the discussions.

1. Conformance

As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.

The key words MAY , MUST , MUST NOT , SHALL , SHOULD , and SHOULD NOT in this document are to be interpreted as described in BCP 14 [ RFC2119 ] [ RFC8174 ] when, and only when, they appear in all capitals, as shown here.

This document defines conformance criteria that apply to a single product: the UA (user agent) that implements the interfaces it contains.

2. Origin Trial

This section is non-normative.

An implementation (Chromium) of this specification is currently being tested in the wild to gather developer feedback. You can try out Web NFC in Chrome for Android by requesting an Origin Trial token and learn more about Origin Trials here .

Feel free to send your feedback via GitHub or the Origin Trial process.

The Origin Trial feedback is reshaping parts of the API and an updated specification incorporating these changes can be found here .

3. Introduction

This section is non-normative.

Web NFC user scenario is as follows: Hold a device in close proximity to a passively powered NFC tag, such as a plastic card or sticker, in order to read and/or write data.

NFC works using magnetic induction, meaning that the reader (an active, powered device) will emit a small electric charge which then creates a magnetic field. This field powers the passive device which turns it into electrical impulses to communicate data. Thus, when the devices are within range, a read is always performed (see NFC Analog Specification and NFC Digital Protocol, NFC Forum, 2006). The peer-to-peer connection works in a similar way, as the device periodically switches into a so-called initiator mode in order to scan for targets, then later to fall back into target mode. If a target is found, the data is read the same way as for tags.

As NFC is based on existing RFID standards, many NFC chipsets support reading RFID tags, but some of these are only supported by single vendors and not part of the NFC standards. As such, this document specifies ways to interact with the NFC Data Exchange Format (NDEF).

4. Terminology and conventions

The Augmented Backus-Naur Form (ABNF) notation used is specified in [ RFC5234 ].

NFC stands for Near Field Communications, a short-range wireless technology operating at 13.56 MHz which enables communication between devices at a distance less than 10 cm. The NFC communications protocols and data exchange formats, and are based on existing radio-frequency identification (RFID) standards, including ISO/IEC 14443 and FeliCa. The NFC standards include ISO/IEC 18092[5] and those defined by the NFC Forum. See NFC Forum Technical Specifications for a complete listing.

An NFC adapter is the software entity in the underlying platform which provides access to NFC functionality implemented in a given hardware element (NFC chip). A device may have multiple NFC adapters, for instance a built-in one, and one or more attached via USB.

An NFC tag is a passive NFC device that is not blocklisted . The NFC tag is powered by magnetic induction when an active NFC device is in proximity range. An NFC tag that supports NDEF contains a single NDEF message .
Note

The way of reading the message may happen through proprietary technologies, which require the reader and the tag to be of the same manufacturer. They may also expose an NDEF message.

An NFC peer is an active, powered device which can interact with other devices in order to exchange data using NFC.

As currently spec'ed, peer-to-peer is not supported.

An NFC device is either an NFC peer , or an NFC tag .

NDEF is an abbreviation for NFC Forum Data Exchange Format, a lightweight binary message format that is standardized in [ NFC-NDEF ].

An NDEF message encapsulates one or more application-defined NDEF record s. NDEF messages can be stored on an NFC tag or exchanged between NFC-enabled devices.

The term NFC content denotes all bytes sent to or received from an NFC tag . In the current API it is synonym to NDEF message .

5. The NFC Standard

This section is non-normative.

NFC is standardized in the NFC Forum and described in [ NFC-STANDARDS ].

5.1 NDEF compatible tag types

This section is non-normative.

The NFC Forum has mandated the support of five different tag types to be operable with NFC devices. The same is required on operating systems, such as Android.

In addition to that, the MIFARE Standard specifies a way for NDEF to work on top of the older MIFARE Standard , which may be optionally supported by implementers.

A note about the NDEF mapping can be found here: MIFARE Classic as NFC Type MIFARE Classic Tag .

  1. NFC Forum Type 1 : This tag is based on the ISO/IEC 14443-3A (NFC-A). The tags are rewritable and can be configured to become read-only. Memory size can be between 96 bytes and 2 Kbytes. Communication speed is 106 kbit/s. In contrast to all other types, these tags have no anti-collision protection for dealing with multiple tags within the NFC field.
  2. NFC Forum Type 2 : This tag is based on the ISO/IEC 14443-3A (NFC-A). The tags are rewritable and can be configured to become read-only. Memory size can be between 48 bytes and 2 Kbytes. Communication speed is 106 kbit/s.
  3. NFC Forum Type 3 : This tag is based on the Japanese Industrial Standard (JIS) X 6319-4 (ISO/IEC 18092), commonly known as FeliCa. The tags are preconfigured to be either rewritable or read-only. Memory is 2 kbytes. Communication speed is 212 kbit/s or 424 kbit/s.
  4. NFC Forum Type 4 : This tag is based on the ISO/IEC 14443-4 A/B (NFC A, NFC B) and thus supports either NFC-A or NFC-B for communication. On top of that the tag may optionally support ISO-DEP (Data Exchange Protocol defined in ISO/IEC 14443 (ISO/IEC 14443-4:2008 Part 4: Transmission protocol). The tags are preconfigured to be either rewritable or read-only. Variable memory, up to 32 kbytes. Supports three different communication speeds 106 or 212 or 424 kbit/s.
  5. NFC Forum Type 5 : This tag is based on ISO/IEC 15693 (NFC-V) and allows reading and writing an NDEF message on an ISO/IEC 15693 RF tag that is accessible by long range RFID readers as well. The NFC communication is limited to short distance and may use the Active Communication Mode of ISO/IEC 18092 where the sending peer generates the field which balances power consumption and improves link stability. Variable memory, up to 64 kbytes. Communication speed is 26.48 kbit/s.
  6. MIFARE Standard : This tag, often sold under the brand names MIFARE Classic or MIFARE Mini, is based on the ISO/IEC 14443-3A (also known as NFC-A, as defined in ISO/IEC 14443-3:2011, Part 3: Initialization and anticollision). The tags are rewritable and can be configured to become read-only. Memory size can be between 320 and 4 kbytes. Communication speed is 106 kbit/s.
    Note

    MIFARE Standard is not an NFC Forum type and can only be read by devices using NXP hardware. Support for reading and writing to tags based on the MIFARE Standard is thus non-nominative, but the type is included due to the popularity and use in legacy systems.

In addition to data types standardized for NDEF record s by the NFC Forum, many commercial products such as bus cards, door openers may be based on the MIFARE Standard which requires specific NFC chips (same vendor of card and reader) in order to function.

5.2 The NDEF record and fields

An NDEF record is a part of an NDEF message . Each record is a binary structure that contains a data payload, as well as associated type information. In addition to this, it includes information about how the data is structured, like payload size, whether the data is chunked over multiple records etc.

A generic record looks like the following:

Only the first three bytes (lines in figure) are mandatory. First the header byte, followed by the TYPE LENGTH field and PAYLOAD LENGTH field , both of which may be zero.

The TNF field (bit 0-2 , type name format) indicates the format of the type name and is often exposed by native NFC software stacks. The field can take binary values denoting the following NDEF record payload types:
TNF value Description
0 Empty record
1 NFC Forum well-known type record
2 MIME type record
3 Absolute-URL record
4 NFC Forum external type record
5 Unknown record
6 Unchanged record
7 Reserved for future use

The IL field (bit 3 , id length) indicates whether an ID LENGTH field is present. If the IL field is 0 , then the ID field is not present either.

The SR field (bit 4 , short record) indicates a short record, one with a payload length <= 255 bytes. Normal records can have payload lengths exceeding 255 bytes up to a maximum of 4 GB. Short records only use one byte to indicate length, whether as normal records use 4 bytes ( 2 32 -1 bytes).

The CF field (bit 5 , chunk flag) indicates whether the payload is chunked across multiple records.

Note

Web NFC turns all received chunked records into logical records and transparently chunks sent payload when that is needed.

The ME field (bit 6 , message end) indicates whether this record is the last in the NDEF message .

The MB field (bit 7 , message begin) indicates whether this record is the first of the NDEF message .

The TYPE LENGTH field is an unsigned 8-bit integer that denotes the byte size of the TYPE field .

The TYPE field is a globally unique and maintained identifier that describes the type of the PAYLOAD field in a structure, encoding and format dictated by value of the TNF field .

Note

The NFC Record Type Definition (RTD) Technical Specification requires that the TYPE field names MUST be compared in case-insensitive manner.

The ID LENGTH field is an unsigned 8-bit integer that denotes the byte size of the ID field .

The ID field is an identifier in the form of a URI reference ([ RFC3986 ]) that is unique, and can be absolute of relative (in the latter case the application must provide a base URI). Middle and terminating chunk records MUST NOT have an ID field , other records MAY have it.

The PAYLOAD LENGTH field denotes the byte size of the PAYLOAD field . If the SR field is 1 , its size is one byte, otherwise 4 bytes, representing an 8-bit or 32-bit unsigned integer, respectively.

The PAYLOAD field carries the application bytes. Any internal structure of the data is opaque to NDEF. Note that in certain cases discussed later, this field MAY contain an NDEF message as data.

5.3 NDEF Record types

5.3.1 Empty NDEF record (TNF 0)

An empty record 's' TYPE LENGTH field , ID LENGTH field and PAYLOAD LENGTH field MUST be 0 , thus the TYPE field , ID field and PAYLOAD field MUST NOT be present.

5.3.2 Well-known type records (TNF 1)

The NFC Forum has standardized a small set of useful sub record types in [ NFC-RTD ] (Resource Type Definition specifications) called well-known type record s, for instance text, URL, media and others. In addition, there are record types designed for more complex interactions, such as smart posters (containing optional embedded records for url, text, signature and actions), and handover records.

The type information stored in the TYPE field of well-known type records can be of two kinds: local types and global types .

5.3.2.1 Well-known local types

NFC Forum local type that are defined by the NFC Forum or by an application, and always start with lowercase character or a number. Those are usually short strings that are unique only within the local context of the containing record. They are used when the meaning of the types doesn't matter outside of the local context of the containing record and when storage usage is a hard constraint. See Smart poster for an example on how local types are used.

Note

A local type is thus defined in terms of a containing record type, and thus doesn't need any namespacing. For this reason the same local type name can be used within another record type with different meaning and different payload type.

5.3.3 Well-known global types

NFC Forum global type s are defined and managed by the NFC Forum and usually start with an uppercase character. Examples: " T " for text, " U " for URL, " Sp " for smart poster, " Sig " for signature, " Hc " for handover carrier, " Hr " for handover request, " Hs " for handover select, etc.

5.3.3.1 Text record
The Text record is a well-known type record that is defined in the [ NDEF-TEXT ] specification. The TNF field is 1 and the TYPE field is " T " ( 0x54 ). The first byte of the PAYLOAD field is a status byte, followed by the language tag in US-ASCII encoding. The rest of the payload is the actual text, encoded either in UTF-8 or UTF-16, as indicated by the status byte as follows:
  • Bits 0 to 5 define the length of the language tag .
  • Bit 6 is 0 .
  • If bit 7 if set, means the payload is encoded in UTF-8, otherwise in UTF-16.
5.3.3.2 URI record

URI record is defined in [ NDEF-URI ]. The TNF field is 1 and the TYPE field is " U " ( 0x55 ). The first byte of the PAYLOAD field is a URI identifier code, in fact an index in an abbreviation table where the values are prepended to the rest of the URI. For instance the value 0 denotes no prepending, 1 denotes " http://www. ", 0x04 denotes " https:// "" and so on. The rest of the payload contains the rest of the URI as a UTF-8 string (and if the first byte is 0 , then it denotes the whole URI).

The URI is defined in [ RFC3987 ] and in fact is a UTF-8 encoded IRI that can be a URN or a URL.

5.3.3.3 Smart poster record
Smart poster is defined in [ NDEF-SMARTPOSTER ] to describe a given web content as an NDEF record that contains an NDEF message as payload, including the following records:
  • A single mandatory URI record that refers to the smart poster content.
    Note

    The [ NDEF-SMARTPOSTER ] states that applications SHALL use only the smart poster record if it is present in an NDEF message that also contains other URI records .

  • Zero or more Text records that act as a title record related to the content. When there are more than one title record present, they MUST be with different language tags . Applications SHOULD select one title record for presentation to the end user.
  • Zero or more MIME type records that act as icon record related to the content. The MIME type is usually " image/jpg ", " image/png ", " image/gif ", or even " video/mpeg ". Applications SHOULD select one icon record for presentation to the end user.
  • One optional type record that has a local type name " t " specific to smart poster and the PAYLOAD field contains a UTF-8 encoded MIME type for the content referred to by the URI record .
  • One optional size record that has local type name " s " specific to smart poster and the PAYLOAD field contains a 4-byte 32 bit unsigned integer that denotes the size of the object referred to by the URL in the URI record of the smart poster .
  • One optional action record that has a local type name " act " specific to smart poster and the PAYLOAD field contains a single byte, whose value has the following meaning:
    Value Description
    0 Do the action
    1 Save for later
    2 Open for editing
    3..0xFF Reserved for future use
    There is no default action on the smart poster content if the action record is missing.
    Note

    At the time of NDEF standardization the value 0 ("do the action") was intended for use cases like send an SMS, make a call or launch browser. Similarly, the value 1 , ("save the content for later processing") was intended for use cases like store the SMS in inbox, save the URL in bookmarks, or save the phone number to contacts. Also, the value 2 ("open for editing") was meant to open the smart poster content with a default application for editing.

    Implementations don't need to implement any standardized behavior for the actions defined here. In this API it's up to the applications what actions they define (that may include the use cases above). However, Web NFC just provides the values.

  • A smart poster MAY also contain other records, which can be handled in an application specific manner.
The example below shows a smart poster record that embeds a text and a URL record.
5.3.3.4 Signature records

NDEF Signature is defined [ NDEF-SIGNATURE ]. Its TYPE field contains " Sig " ( 0x53 , 0x69 , 0x67 ) and its PAYLOAD field contains version, signature and a certificate chain.

Issue 363 : Support Signature records Enhancement

As currently spec'ed, this is not supported.

5.3.3.5 Handover records

NFC handover is defined [ NFC-HANDOVER ] and the corresponding message structure that allows negotiation and activation of an alternative communication carrier, such as Bluetooth or WiFi. The negotiated communication carrier would then be used (separately) to perform certain activities between the two devices, such as sending photos to the other device, printing to a Bluetooth printer or streaming video to a television set.

Issue 364 : Support Handover records Enhancement

As currently spec'ed, this is not supported.

5.3.4 MIME type records (TNF 2)

The MIME type record s are records that store binary data with associated MIME type .

5.3.5 Absolute-URL records (TNF 3)

In absolute-URL record s the TYPE field contains the absolute-URL string , and not the payload.

Note

NOTE: Some platforms, like Windows Phone have stored additional data in the payload, but any payload data in these records are ignored by other platforms such as Android. On Android, reading such a record, will attempt to load the URL in Chrome and it is as such not intended for client applications.

5.3.6 External type records (TNF 4)

The NFC Forum external type record s are for application specified data types and are defined in NFC Record Type Definition (RTD) Technical Specification .

The external type is a URN with the prefix "urn:nfc:ext:" followed by the name of the owner domain , adding a U+003A ( : ), then a non-zero type name, for instance "urn:nfc:ext:w3.org:atype" , stored as "w3.org:atype" in the TYPE field .

5.3.7 Unknown type records (TNF 5)

The unknown record s are records that store opaque data without associated MIME type , meaning that the application/octet-stream default MIME type MAY be assumed. The [ NFC-NDEF ] specification recommends that NDEF parsers store or forward the payload without processing it.

5.3.8 Unchanged type records (TNF 6)

The unchanged record s are record chunks of a chunked data set, and is used for any, but the first record. A chunked payload is spread across multiple NDEF record s that undergo the following rules:
  • The initial chunk record has the CF field set, its TYPE field set to the type of the whole chunked payload and its ID field MAY be set to an identifier used for the whole chunked payload. Its PAYLOAD LENGTH field denotes the size of the payload chunk in this record only.
  • The middle chunk records have the CF field set, have the same ID field as the first chunk, their TYPE LENGTH field and IL field MUST be 0 and their TNF field MUST be 6 (unchanged).
  • The terminating chunk record has this flag cleared, and in rest undergo the same rules as the middle chunk records.
  • A chunked payload MUST be contained in a single NDEF message , therefore the initial and middle chunk records cannot have the ME field set.
First record:
Intermediate record:
Last record:

Any implementation of Web NFC MUST transparently expose chunked records as single logical records.

6. Use Cases

This section is non-normative.

A few NFC user scenarios have been enumerated here and in the Web NFC Use Cases document. The rudimentary Web NFC interactions are the following.

6.1 Reading an NFC tag

Reading an NFC tag containing an NDEF message , while the Document of the top-level browsing context using Web NFC is visible . For instance, a web page instructs the user to tap an NFC tag, and then receives information from the tag.

6.2 Writing to an NFC tag

The user opens a web page which can write to an NFC tag . The write operations may be one of the following:
  1. Writing to a non-formatted NFC tag .
  2. Writing to an empty, but formatted NFC tag .
  3. Writing to an NFC tag which already contains an NDEF message .
  4. Writing to other, writable NFC tag s (i.e. overwriting a generic tag).
Note

Note that an NFC write operation to an NFC tag always involves also a read operation.

6.3 Support for multiple NFC adapters

Users may attach one or more external NFC adapter s to their devices, in addition to a built-in adapter. Users may use either NFC adapter .

7. Features

This section is non-normative.

High level features for the Web NFC specification include the following:
  1. Support devices with single or multiple NFC adapter s. If there are multiple adapters present when invoking an NFC function then the UA operates all NFC adapter s in parallel.
  2. Support communication with passive (smart cards, tags, etc.) NFC devices.
  3. Allow users to act on (e.g. read, write or transceive) discovered passive NFC devices, as well as access the payload which were read in the process as NDEF message s.
  4. Allow users to write a payload via NDEF record s to compatible devices, such as writable tags, when they come in range, as NDEF message s.

8. Examples

This section is non-normative.

This section shows how developers can make use of the various features of this specification.

8.1 Feature support

Detecting if Web NFC is supported can be done by checking NDEFReader and/or NDEFWriter objects. the Navigator object. Note that this does not guarantee that NFC hardware is available. The example checks if NDEFReader is available.

Example 1 } if ( 'NDEFWriter' in window ) { /* ... Write NDEF Tags */
if (navigator.nfc?.ndef) {
  /* ... Scan and write NDEF Tags */
}

8.2 General information about writing data

Writing data is generally straightforward, but there are a few gotcha's around how writing works with NFC.

An NFC reader works by polling, so in order to be able to write to a tag, a tag first needs to be found and read, which means that polling needs to be initialized first.

If polling is not initiated already by first calling scan() navigator.nfc.start() , then the write() navigator.nfc.ndef.write() method and navigator.nfc.ndef.read() methods will initiate it temporarily until a tag was found and read, and writing to it the operation was attempted.

This means that the flow is that first a read it performed as the tag is first found, then followed by a write. This means that if scan() is running and you have an event listener for the reading event, it will be dispatched once during a write() operation, which might not be the intended behavior. In the following sections we will discuss how you can easily deal with this behavior, but first a few simple examples.

8.3 Write a text string

Writing a text string to an NFC tag is straightforward. NFC polling is started by write() and stopped after writing.

Example 2 NDEFWriter(); writer.write(
navigator.nfc.ndef.write(
  "Hello World"
).then(() => {
  console.log("Message written.");
}).catch(error => {
  console.log(`Write failed :-( try again: ${error}.`);
});

8.4 Write a URL

In order to write an NDEF record of URL type, simply use NDEFMessage. Here we rely on async/await.

Example 3 NDEFReader(); { ndef.write({
try {
  navigator.nfc.ndef.write({

    records: [{ recordType: "url", data: "https://w3c.github.io/web-nfc/" }]
  });
} catch {
  console.log("Write failed :-( try again.");
};

8.5 Handling initial reads while writing

In order to write, a tag needs to be found and thus read. This gives you the ability to check whether it is actually a tag that you want to write to or not, by checking existing data or serial number.

For this reason, it is recommended calling write() from a reading event. The below example shows how to coordinate between a common reading handler and one used specifically for a single write.
Example 4 NDEFReader(); ; reader.onreading( { (ignoreRead) {
await navigator.nfc.start();
navigator.nfc.ontagfound(event => {
  if (event.serialNumber !== myDesiredSerial) {    console.log("We found a tag, but not the one we want!");    return;
  }
  try {    await navigator.nfc.ndef.write(data);    // read back the data;    let readData = await navigator.nfc.ndef.read();
  } catch (err) {
    console.error("Something went wrong", err);
  }
  );
}
{
  ignoreRead = ;
   {
    reader.addEventListener(, event => {
      
      reader.write(data).then(resolve, reject).finally();
    }, {  });
  });
}
 reader.scan();
 {
  );
  )
} (err) {
  , err);

}

8.6 Scheduling a write with a timeout

It can sometime be useful to set a time limit on a write operation. Like you ask the user to touch a tag, and if no tag is found within a certain amount of time, then you time out.

Example 5 NDEFReader(); reader.onreading()); {
function write(data, { timeout } = {}) {
  return new Promise((resolve, reject) => {
    const ctlr = new AbortController();
    ctlr.signal.onabort = _ => reject("Time is up, bailing out!");
    if (typeof timeout == "number") {
      setTimeout(() => ctlr.abort(), timeout);
    }
    reader.addEventListener(, event => {
      reader.write(data, { : ctlr.signal }).then(resolve, reject);

    navigator.nfc.addEventListener("tagfound", event => {
      navigator.nfc.ndef.write(data, { signal: ctlr.signal })
        .then(resolve, reject);

    }, { once: true });
  });
}
 reader.scan();

try {
  // Let's wait for 5 seconds only.
  write("Hello World", { timeout: 5_000 });}
} catch(err) {
  console.error("Something went wrong", err);
} finally {
  console.log("We wrote to a tag!");
}

8.7 Handle scanning errors

This example shows what happens when scan promise rejects and onerror navigator.nfc.onerror is fired.

Example 6 NDEFReader(); reader.scan().then( { ); reader.onerror = { );
navigator.nfc.start().then(() => {
  console.log("NFC polling started successfully.");
  navigator.nfc.onerror = event => {
    console.log("Error! NFC tag found, but is not supported " +      "or cannot be read. Try a different one?");
  };
  reader.onreading =  {
    );

  navigator.nfc.ontagfound = event => {
    console.log("NFC tag found" + event.serialNumber);
  };
}).catch(error => {
  );

  console.log(`Error! NFC polling failed to start: ${error}.`);
});

8.8 Read a single tag, once

This example show you how to easily create a convenience function that just reads a single tag and then stops polling, saving battery life by cutting unneeded work.

The example could easily be extended to time out First it is done the simplest way, using the temporary NFC polling built into the read() function, then by manually aborting NFC polling after a given amount of milliseconds. reading.

Example 7 NDEFReader();
navigator.nfc.ontagfound = event => {
  console.log("Read the NFC tag " + serialNumber);
};

const

message
=

await

navigator.nfc.ndef.read();

{

async function readOnce() {
  return new Promise((resolve, reject) => {
    const ctlr = new AbortController();
    ctlr.signal.onabort = reject;
    reader.addEventListener(, event => {
      ctlr.abort();
      resolve(event);

    await navigator.nfc.start({ signal: ctlr.signal });
    navigator.nfc.addEventListener("tagfound", event => {
      event.data = await navigator.nfc.ndef.read();
        .then(resolve(event))
        .catch(err => reject(err));
    ctlr.abort();

    }, { once: true });
    reader.scan({  reject(err));

  });
}
read().then( {
  .log(serialNumber);
})

readOnce().then(({ serialNumber }) => {
  console.log("Read the NFC tag " + serialNumber);
});


8.9 Read data from tag, and write to empty ones

This example shows reading various different kinds of data which can be stored on a tag. If the tag is unformatted or contains an empty record, a text message is written with the value "Hello World".

Example 8 9 NDEFReader(); reader.scan(); reader.onreading = { message = event.message;
await navigator.nfc.start();
navigator.nfc.ontagfound = event => {
  const message = await navigator.nfc.ndef.read();
  if (message.records.length == 0 ||     // unformatted tag
      message.records[0].recordType == 'empty' ) {  // empty record
     NDEFWriter();
    writer.write({

    navigator.nfc.ndef.write({

      records: [{ recordType: "text", data: 'Hello World' }]
    });
    return;
  }
  const decoder = new TextDecoder();
  for (const record of 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") {
          console.log(`JSON: ${JSON.parse(decoder.decode(record.data))}`);
        }
        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);
          img.onload = () => window.URL.revokeObjectURL(this.src);
          document.body.appendChild(img);
        }
        else {
          console.log(`Media not handled`);
        }
        break;
      default:
        console.log(`Record not handled`);
    }
  }
};

8.10 Save and restore game progress with an NFC tag

Filtering of relevant data sources can be done by the use of the NDEFScanOptions . Below we use the a custom record identifier identifier, in this case " my-game-progress " as a relative URL so that when ". When we read the data, we immediately update the game progress by issuing a write with a custom NDEF data layout.

Example 9 10 NDEFReader(); }); reader.onreading = event => { );
await navigator.nfc.start();
navigator.nfc.ontagfound = async event => {
  let message = await navigator.nfc.ndef.read();  if (message.id !== "my-game-progress")    return;  console.log(`Game state: ${ JSON.stringify(message.records) }`);
  const encoder = new TextEncoder();
  const newMessage = {
    records: [{
      id: "my-game-progress",
      recordType: "mime",
      mediaType: "application/json",
      data: encoder.encode(JSON.stringify({
        level: 3,
        points: 4500,
        lives: 3
      }))
    }]
  };
   NDEFWriter();
   writer.write(newMessage);

  await navigator.nfc.ndef.write(newMessage);
  console.log("Message written");
};

8.11 Write and read JSON (serialized and deserialized)

Storing and receiving JSON data is easy with serialization and deserialization.

Example 10 11 NDEFReader(); reader.scan({ }); reader.onreading = {
await navigator.nfc.start();
navigator.nfc.ontagfound = event => {
  let message = await navigator.nfc.ndef.read();
  const decoder = new TextDecoder();
   event.message.records) {

  for (const record of message.records) {
    if (record.mediaType === 'application/json') {
      const json = JSON.parse(decoder.decode(record.data));
      const article =/^[aeio]/i.test(json.title) ? "an" : "a";
      console.log(`${json.name} is ${article} ${json.title}`);
    }
  }
};
 NDEFWriter();

const encoder = new TextEncoder();
writer.write({

navigator.nfc.ndef.write({

  records: [
    {
      recordType: "mime",
      mediaType: "application/json",
      data: encoder.encode(JSON.stringify({
        name: "Benny Jensen",
        title: "Banker"
      }))
    },
    {
      recordType: "mime",
      mediaType: "application/json",
      data: encoder.encode(JSON.stringify({
        name: "Zoey Braun",
        title: "Engineer"
      }))
    }]
});

8.12 Write data and print out existing data

Writing data requires tapping an NFC tag .

Example 11 12 NDEFReader(); ndef.onreading = event => {
navigator.nfc.ontagfound = async event => {
  let message = await navigator.nfc.ndef.read();
  const decoder = new TextDecoder();
   event.message.records) {

  for (const record of message.records) {
    console.log("Record type:  " + record.recordType);
    console.log("MIME type:    " + record.mediaType);
    console.log("=== data ===\n" + decoder.decode(record.data));
  }
  try {
    );

    await navigator.nfc.ndef.write("Overriding data is fun!");
  } catch(error) {
    console.log(`Write failed :-( try again: ${error}.`);
  }
};
ndef.scan();

navigator.nfc.ndef.start();


8.13 Stop listening to NDEF messages

Read NDEF messages for 3 seconds with a timeout by using signal .

Example 12 13 NDEFReader(); AbortController(); : controller.signal }); reader.onreading = { ); };
const controller = new AbortController();
controller.signal.onabort = event => {
  console.log("We're done waiting for NDEF messages.");
};
setTimeout(

navigator.nfc.ontagfound = event => {
  console.log("NDEF message read.");
};

()
=>
controller.abort(),
3

// Wait 10 seconds for a tag, then abort.
setTimeout(() => controller.abort(), 10_000);

await


_000);

navigator.nfc.ndef.read({

signal
:
controller.signal
});


8.14 Write a smart poster message

Example 13 14 NDEFWriter(); TextEncoder(); writer.write({ : [
const encoder = new TextEncoder();
navigator.nfc.ndef.write({ records: [

  {
    recordType: "smart-poster",  // Sp
    data: { records: [
      {
        recordType: "url",  // URL record for the Sp content
        data: "https://my.org/content/19911"
      },
      {
        recordType: "text",  // title record for the Sp content
        data: "Funny dance"
      },
      {
        recordType: ":t",  // type record, a local type to Sp
        data: encoder.encode("image/gif") // MIME type of the Sp content
      },
      {
        recordType: ":s",  // size record, a local type to Sp
        data: new Uint32Array([4096]) // byte size of Sp content
      },
      {
        recordType: ":act",  // action record, a local type to Sp
        // do the action, in this case open in the browser
        data: new Uint8Array([0])
      },
      {
        recordType: "mime", // icon record, a MIME type record
        mediaType: "image/png",
        data: await (await fetch("icon1.png")).arrayBuffer()
      },
      {
        recordType: "mime", // another icon record
        mediaType: "image/jpg",
        data: await (await fetch("icon2.jpg")).arrayBuffer()
      }
    ]}
  }
]});

8.15 Read an external record with an NDEF message as payload

External type records can be used to create application defined records. These records may contain an NDEF message as payload, with its own NDEF records , including local types that are used in the context of the application.

Note that the smart poster record type also contains an NDEF message as payload.

As NDEF gives no guarantee on the ordering of records, using an external type record with an NDEF message as payload, can be useful for encapsulating related data.

This example shows how to read an external record for social posts, which contains an NDEF message , containing a text record and a record with the local type "act" (action), with definition borrowed from smart poster , but used in local application context.

Example 14 15 NDEFReader(); }); reader.onreading = { externalRecord = event.message.records.find(
await navigator.nfc.start();
navigator.nfc.ontagfound = event => {
  const message = await navigator.nfc.ndef.read();  const externalRecord = message.records.find(
    record => record.type == "example.com:smart-poster"
  );
  let action, text;
  for (const record of externalRecord.toRecords()) {
    if (record.recordType == "text") {
      const decoder = new TextDecoder(record.encoding);
      text = decoder.decode(record.data);
    } else if (record.recordType == ":act") {
      action = record.data.getUint8(0);
    }
  }
  switch (action) {
    case 0: // do the action
      console.log(`Post "${text}" to timeline`);
      break;
    case 1: // save for later
      console.log(`Save "${text}" as a draft`);
      break;
    case 2: // open for editing
      console.log(`Show editable post with "${text}"`);
      break;
  }
};

8.16 Write an external record with an NDEF message as payload

External type records can be used to create application defined records that may even contain an NDEF message as payload.

Example 15 16 NDEFWriter(); writer.write({ : [
navigator.nfc.ndef.write({ records: [
  {
    ,
    : {
      : [

    recordType: "example.game:a",
    data: {
      records: [

        {
          ,
          

          recordType: "url",
          data: "https://example.game/42"

        },
        {
          ,
          

          recordType: "text",
          data: "Game context given here"

        },
        {
          ,
          ,
          : getImageBytes(fromURL)

          recordType: "mime",
          mediaType: "image/png",
          data: getImageBytes(fromURL)

        }
      ]
    }
  }
]});

8.17 Write and read unknown records inside an external record

Unknown type records may be useful inside external type records as developers know what they represent and therefore can avoid specifying the mime type.

const encoder = new TextEncoder();
 NDEFWriter();
writer.write({ : [

navigator.nfc.ndef.write({ records: [

  {
    recordType: "example.com:shoppingItem", // External record
    data: {
      records: [
        {
          recordType: "unknown", // Shopping item name
          data: encoder.encode("Food")
        },
        {
          recordType: "unknown", // Shopping item description
          data: encoder.encode("Provide nutritional support for an organism.")
        }
      ]
    }
  }
]});

Example 17 18 NDEFReader(); }); reader.onreading = { ]; (!shoppingItemRecord) {
await navigator.nfc.start();
navigator.nfc.ontagfound = event => {
  const message = await navigator.nfc.ndef.read();  const shoppingItemRecord = message.records[0];  if (!shoppingItemRecord ||
      shoppingItemRecord.recordType !== "example.com:shoppingItem") {

    return;
  }
  const [nameRecord, descriptionRecord] = shoppingItemRecord.toRecords();
  const decoder = new TextDecoder();
  console.log("Item name: " + decoder.decode(nameRecord.data));
  console.log("Item description: " + decoder.decode(descriptionRecord.data));
};

9. Data Representation

9.1 The NDEFMessage interface

The content of any NDEF message is exposed by the NDEFMessage interface:

WebIDL[SecureContext, Exposed=Window]
interface NDEFMessage {
  constructor(NDEFMessageInit messageInit);
  readonly attribute FrozenArray<NDEFRecord> records;
};
dictionary NDEFMessageInit {
  required sequence<NDEFRecordInit> records;
};

The records property represents a list of NDEF record s defining the NDEF message .

The NDEFMessageInit dictionary is used to initialize an NDEF message .

9.2 The NDEFRecord interface

The content of any NDEF record is exposed by the NDEFRecord interface:

WebIDLtypedef (DOMString or BufferSource or NDEFMessageInit) NDEFRecordDataSource;
[SecureContext, Exposed=Window]
interface NDEFRecord {
  constructor(NDEFRecordInit recordInit);
  readonly attribute USVString recordType;
  readonly attribute USVString? mediaType;
  readonly attribute USVString? id;
  readonly attribute DataView? data;
  readonly attribute USVString? encoding;
  readonly attribute USVString? lang;
  sequence<NDEFRecord>? toRecords();
};
dictionary NDEFRecordInit {
  required USVString recordType;
  USVString mediaType;
  USVString id;
  USVString encoding;
  USVString lang;
  NDEFRecordDataSource data;
};

The mediaType property represents the MIME type of the NDEF record payload.

The recordType property represents the NDEF record types.

The id property represents the record identifier , which is an absolute or relative URL. The required uniqueness of the identifier is guaranteed only by the generator, not by this specification.
Note

The NFC NDEF specifications uses the terms "message identifier" and "payload identifier" instead of record identifier , but the identifier is tied to each record and not the message (collection of records), and it may be present when no payload is.

The encoding attribute represents the encoding name used for encoding the payload in the case it is textual data.

The lang attribute represents the language tag of the payload in the case that was encoded.

A language tag is a string that matches the production of a Language-Tag defined in the [ BCP47 ] specifications (see the IANA Language Subtag Registry for an authoritative list of possible values). That is, a language range is composed of one or more subtags that are delimited by a U+002D HYPHEN-MINUS ("-"). For example, the ' en-AU ' language range represents English as spoken in Australia, and ' fr-CA ' represents French as spoken in Canada. Language tags that meet the validity criteria of [ RFC5646 ] section 2.2.9 that can be verified without reference to the IANA Language Subtag Registry are considered structurally valid.

The data property represents the PAYLOAD field data.

The toRecords() method, when invoked, MUST return the result of running convert NDEFRecord.data bytes with the NDEF Record .

The NDEFRecordInit dictionary is used to initialize an NDEF record with its record type recordType , and optional record identifier id and payload data data .

Additionally, there are additional optional fields that are only applicable for certain record types :

The mapping from data types of an NDEFRecordInit to NDEF record types is presented in the algorithmic steps which handle the data and described in the §  10.12 12.7 Parsing content and §  10.9 12.4 Writing content The write() method sections.

To convert NDEFRecord.data bytes given a record , run these steps:

  1. Let bytes be the value of record's data attribute.
  2. Let recordType be the value of record 's recordType attribute.
  3. If the recordType value is " smart-poster ", then return the result of running parse records from bytes given bytes and "smart-poster" .
  4. If running validate external type on recordType returns true , then return the result of running parse records from bytes given bytes and "external" .
  5. Otherwise, throw a " NotSupportedError " DOMException and abort these steps.

9.3 The record type string

This string defines the allowed record types for an NDEFRecord . The §  9.4 Data mapping section describes how it is mapped to NDEF record types.

A standardized well known type name can be one of the following:

The " empty " string
The value representing an empty NDEFRecord .
The " text " string
The value representing a Text record .
The " url " string
The value representing a URI record .
The " smart-poster " string
The value representing a Smart poster record.
The " absolute-url " string
The value representing an absolute-URL record .
The " mime " string
The value representing a MIME type record .
The " unknown " string
The value representing an unknown record .

In addition to well known type names it is also possible for organizations to create a custom external type name , which is a string consisting of a domain name and a custom type name, separated by a colon U+003A ( : ).

Applications MAY also use a local type name , which is a string that MUST start with lowercase character or a number, representing a type for an NFC Forum local type . It is typically used in a record of an NDEFMessage that is the payload of a parent NDEFRecord , for instance in a smart poster . The context of the local type is the parent record whose payload is the NDEFMessage to which this record belongs and the local type name SHOULD NOT conflict with any other type names used in that context.

Any implementation of Web NFC MUST transparently expose chunked records as single logical records, therefore unchanged record s are not explicitly represented.

Two well-known type records (including any NFC Forum local type and any NFC Forum global type ) MUST be compared character by character in case-sensitive manner.

Two external types MUST be compared character by character, in case-insensitive manner.

The binary representation of any well-known type record and external type MUST be written as a relative URI (RFC 3986), omitting the namespace identifier (NID) " nfc " and namespace specific string (NSS) " wkt " and " ext ", respectively, i.e. omitting the " urn:nfc:wkt: " and " urn:nfc:ext: " prefixes. For instance, " urn:nfc:ext:company.com:a" is stored as " company.com:a`" and the well-known type records of a Text record is " urn:nfc:wkt:T ", but it is stored as " T ".

9.4 Data mapping

The mapping from data types of an NDEFRecordInit to NDEF record types, as used in the §  10.9 12.4 Writing content The write() method section is as follows:

recordType mediaType data record type TNF field TYPE field
" empty " unused unused Empty record 0 unused
" text " unused BufferSource or
DOMString
Well-known type record 1 " T "
" url " unused DOMString Well-known type record 1 " U "
" smart-poster " unused NDEFMessageInit Well-known type record 1 " Sp "
local type name prefixed by a colon U+003A ( : ), e.g., " :act ", " :s ", and " :t " unused BufferSource or NDEFMessageInit Local type record* 1 local type name , e.g., " act ", " s ", and " t "
" mime " MIME type BufferSource MIME type record 2 MIME type
" absolute-url " unused DOMString url Absolute-URL record 3 Absolute-URL
external type name unused BufferSource or
NDEFMessageInit
External type record 4 external type name
" unknown " unused BufferSource Unknown record 5 unused

* A local type record has to be embedded with the NDEFMessage payload of another record.

The mapping from NDEF record types to NDEFRecord , as used for incoming NDEF message s described in the §  10.12 12.7 Parsing content section, is as follows.

record type TNF field
TYPE field recordType mediaType
Empty record 0 unused " empty " null
Well-known type record 1 " T " " text " null
Well-known type record 1 " U " " url " null
Well-known type record 1 " Sp " " smart-poster " null
Local type record* 1 local type name , e.g., " act ", " s ", and " t " local type name prefixed by a colon U+003A ( : ), e.g., " :act ", " :s ", and " :t " null
MIME type record 2 MIME type " mime " The MIME type used in the NDEF record
Absolute-URL record 3 URL " absolute-url " null
External type record 4 external type name external type name null
Unknown record 5 unused " unknown " null

10. The NDEFReader and NDEFWriter objects Extensions to the Navigator interface

The objects provide a way for the browsing context to use NFC functionality. They allow for writing NDEF message s to NFC tag s within range, and to act on incoming NDEF message s from NFC tag s. [] interface
WebIDL[SecureContext]
partial interface Navigator {
  [SameObject]
  readonly attribute NFC nfc;
};

  
};

[] interface 11. The NFC object attribute attribute };

WebIDL[SecureContext, Exposed=Window]
interface NFC {
  readonly attribute NDEFReader ndef;
  attribute EventHandler ontagfound;
  attribute EventHandler onerror;
  Promise<undefined> start(optional NFCOptions options={});
};

[SecureContext, Exposed=Window]
interface 
  
  readonly attribute
  [
};

interface NFCTagFoundEvent : Event {
  constructor(DOMString type, NFCTagFoundEventInit tagfoundEventInitDict);
  readonly attribute DOMString serialNumber;
};

dictionary 
  
  required

dictionary NFCTagFoundEventInit : EventInit {
  DOMString? serialNumber = "";
};

The NDEFMessageSource ndef property is a union type representing argument types accepted by the an NDEFReader object that provides NFC tag read and write functionality.

The ontagfound is an EventHandler which is called to notify that an NFC tag has been detected.

The () onerror method. is an EventHandler which is called to notify that an error happened during NFC tag operations.

The NDEFReadingEvent NFCTagFoundEvent is the event being dispatched on new when an NFC readings. tag appears in NFC proximity range.

The serialNumber property represents the serial number of the device used for anti-collision and identification, or empty string in case none is available. The message is an NDEFMessage object.

NDEFReadingEventInit NFCTagFoundEventInit is used to initialize a new event with a serial number and the number. If NDEFMessageInit data via the message serialNumber member. If serialNumber is not present or is null , empty string will be used to init the event.

Note

Though most tags will have a stable unique identifier (UID), not all have one and some tags even create a random number on each read. The serial number usually consists of 4 or 7 numbers, separated by : .

The
NDEFWriter

is an object used for writing data to an 11.1 NFC tag . An NDEFWriter object has the following internal slots : Internal Slot Initial value Description ( non-normative ) [[WriteOptions]] null The NDEFWriteOptions value for writer. [[WriteMessage]] null The NDEFMessage to be written. It is initially unset. The NDEFReader is an object used for reading data when a device, such as a tag, is within the magnetic induction field. An NDEFReader object has the following internal slots : Internal Slot Initial value Description ( non-normative ) [[Id]] undefined The NDEFScanOptions . id value. [[RecordType]] undefined The NDEFScanOptions . recordType value. [[MediaType]] undefined The NDEFScanOptions . mediaType value. [[Signal]] undefined The NDEFScanOptions . signal to abort the operation. Note Note that the internal slots of NDEFReader come from the options passed to NDEFReader.scan() . Therefore there is maximum one filter associated with any given NDEFReader object and successive invocations of NDEFReader.scan() state with new options will replace existing filters. The onreading is an EventHandler which is called to notify that new reading is available.

The onerror is an EventHandler which is called to notify that an error happened during reading. 10.1 NFC state associated with the settings object The relevant settings object of the active document of a browsing context which supports NFC has an associated NFC state record with the following internal slots :

Internal Slot Initial value Description ( non-normative )
[[Suspended]] false A boolean flag indicating whether NFC functionality is suspended or not, initially false .
[[ActivatedReaderList]] [[PollingActive]] empty set false A set of Set to true when NFC polling is active, to false otherwise when it is not active and to undefined when NDEFReader start instances. [[PendingWrite]] empty A < promise , writer > tuple where promise holds a pending () has been invoked but its Promise and writer holds an NDEFWriter . is not yet settled.
Note

Internal slots are used only as a notation in this specification, and implementations do not necessarily have to map them to explicit internal properties.

The activated reader objects NFC polling is active if the value of the [[ActivatedReaderList]] [[PollingActive]] internal slot. slot is not false .

The pending write tuple NFC polling is inactive if the value of the [[PendingWrite]] [[PollingActive]] internal slot. slot is false .

NFC is suspended if the [[Suspended]] internal slot is true .

To suspend NFC , set ,set the [[Suspended]] internal slot to true .

To resume NFC , set the [[Suspended]] internal slot to false .

Note Internal slots are used only as a notation in this specification, and implementations do not necessarily have to map them to explicit internal properties.

10.2 11.2 Handling NFC adapters

Implementations MAY use multiple NFC adapter s according to the algorithmic steps described in this specification.

10.3 11.3 Obtaining permission

The Web NFC permission name is defined as " nfc ".

To obtain permission , run these steps:
  1. Run the query a permission steps for the Web NFC permission name until completion.
    1. If it resolved with " granted " (i.e. permission has been granted to the origin and global object using the Permissions API), return true .
    2. Otherwise, if it resolved with " prompt ", then optionally request permission from the user for the Web NFC permission name . If that is granted, return true .
      Issue 482 : permissions-related example in explainer encourages bad assumptions about browser behavior Origin Trial Spec issue tag-tracker

      The request permission steps are not yet clearly defined. At this point the UA asks the user about the policy to be used with the Web NFC permission name for the given origin and global object , if the user grants permission, return true .

  2. Return false .

10.4 11.4 Handling visibility change

When the user agent determines that the visibility state of the responsible document of the current settings object changes, it must run these steps:

  1. Let document be the responsible document of the current settings object .
  2. If document 's visibility state is "visible" , resume NFC and abort these steps.
  3. Otherwise, suspend NFC and attempt to abort a pending write operation .

The term suspended refers to NFC operations being suspended, which means that no NFC content is written by NDEFWriter s, written, and no received NFC content is presented to any applications while being suspended.

11.5 The start() method

Requests starting NFC polling, unless already active and unless it has been requested, but not completed yet.

11.5.1 The NFCOptions dictionary

To stop polling for NFC tags , an aborted flag can be used in the NFCOptions dictionary:

WebIDLdictionary NFCOptions {  AbortSignal signal;
};

The NDEFReader signal property allows to abort the start while being suspended. () operation.

10.5 11.5.2 Aborting pending write operation NFC polling To

When the NFC . start () method is invoked, run the start NFC polling steps:
  1. Let p be a new Promise object. Return p and run the next steps in parallel .
  2. If NFC polling is active , attempt to abort a pending write operation on NFC polling .
  3. Set [[PollingActive]] to undefined .
  4. Let options be first argument.
  5. Let signal be the options ’ dictionary member of the same name if present, or null otherwise.
  6. If signal ’s aborted flag is set, then reject p with an environment settings object , perform " AbortError " DOMException and return p .
  7. If signal is not null , then add the following steps: abort steps to signal :
    1. Attempt to abort NFC polling .
  8. If there is no pending write tuple the obtain permission tuple , steps return false , then reject p with a " NotAllowedError " DOMException and abort these steps.
  9. Request starting polling NFC on all available NFC Adapters .
  10. If tuple 's writer has already initiated an ongoing no connection can be established with any NFC data transfer, Adapter s, reject p with a " NotSupportedError " DOMException and abort these steps.
  11. Reject tuple If the UA is not allowed to access any underlying NFC Adapter (e.g. a user preference), then reject p 's promise with an a " AbortError NotReadableError " DOMException and abort these steps.
  12. If the request fails on all NFC Adapters , then reject p with an NotFoundError Note DOMException Rejecting and abort these steps.
  13. Save the promise will clear list of NFC Adapters that are polling for this browsing context as active adapter list , to be referred in the pending write tuple abort NFC polling steps.
  14. Set [[PollingActive]] to true .
  15. Resolve p .
  16. Whenever the UA detects NFC technology, run the NFC detection algorithm .

11.5.3 The NFC detection algorithm

To run the NFC detection algorithm :
  1. If NFC is suspended , abort these steps.
  2. Let serialNumber be the device identifier as a series of numbers, or null if unavailable.
  3. If serialNumber is not null , set it to the string of U+003A ( : ) concatenating each number represented as ASCII hex digit , in the same order.
  4. Fire an event named " tagfound " at |navigator.nfc| using NFCTagFoundEvent with its serialNumber attribute initialized to serialNumber .
  5. If |navigator.nfc.ndef|. [[PendingRead]] is not null , notify the NDEFReader . read algorithm to resume reading .
  6. If |navigator.nfc.ndef|. [[PendingWrite]] is not null , notify the NDEFReader . write algorithm to resume writing .

11.5.4 Aborting NFC polling

To attempt to abort NFC polling , run the following steps:
  1. Make a request to stop polling for NFC tag s on all NFC adapter s in the active adapter list
  2. Set [[PollingActive]] to false .

10.6 11.6 Releasing NFC

To release NFC on an environment settings object , perform the following steps:

  1. Suspend Attempt to abort NFC polling .
  2. Attempt to abort a pending write operation . Stop the dispatch NFC content steps. Clear the activated reader objects NDEF operations .
  3. Release the NFC resources associated with nfc on the underlying platform. browsing context .
  4. Clear all internal slots on |navigator.nfc| and |navigator.nfc.ndef|.

The UA must release NFC given the document's relevant settings object as additional unloading document cleanup steps .

12. The NDEFReader object

The NDEFReader is an object attached to |navigator.nfc| that exposes NFC functionality to the browsing context : reading NDEF messages when a device, such as a tag, is within the magnetic induction field. Also, it is used for writing NDEF messages to NFC tag s within range.

WebIDLtypedef (DOMString or BufferSource or NDEFMessageInit) NDEFMessageSource;
[SecureContext, Exposed=Window]
interface NDEFReader {
  Promise<NDEFMessage> read(optional NDEFReadOptions options={});  Promise<undefined> write(NDEFMessageSource message,
                                 optional NDEFWriteOptions options={});
};

The NDEFMessageSource is a union type representing argument types accepted by the write () method.

An NDEFReader object has the following internal slots :

Internal Slot Initial value Description ( non-normative )
[[PendingRead]] null The pending promise of a read () .
[[PendingWrite]] null The pending promise of a write () .

10.7 12.1 The NDEFWriteOptions dictionary

WebIDLdictionary NDEFWriteOptions {
  boolean overwrite = true;
  AbortSignal? signal;
};

When the value of the overwrite property is false , the write algorithm will read the NFC tag to determine if it has NDEF records on it, and if yes, it will not execute any pending write. write to it.

The signal property allows to abort the write () operation.

10.8 12.2 The NDEFScanOptions NDEFReadOptions dictionary

To describe which messages stop listening to NDEF messages, an application is interested in, aborted flag can be used in the NDEFScanOptions NDEFReadOptions dictionary is used: dictionary:

WebIDLdictionary NDEFReadOptions {
  AbortSignal signal;
};

The signal property allows to abort the scan read () operation.

The
id

12.3 Aborting NDEF operations

To attempt to abort a pending write property denotes the string value which is used for matching on reader , run the record identifier following steps:
  1. If reader . [[PendingWrite]] of each is NDEFRecord object in an NDEF message . null , abort these steps.
  2. If the dictionary member there is not present, then it will be ignored by the an ongoing NFC listen algorithm . The recordType property denotes write data transfer, request the string value which is used for matching underlying platform to cancel the record type write operation. If that is successful, reject reader . [[PendingWrite]] of each with an " NDEFRecord AbortError object in an NDEF message . If the dictionary member is not present, then it will be ignored by the NFC listen algorithm . The " mediaType DOMException .
  3. Set reader . [[PendingWrite]] to null .
To attempt to abort a pending read property denotes on reader , run the match pattern following steps:
  1. If reader . [[PendingRead]] which is used for matching the null , abort these steps.
  2. If there is an ongoing NFC write data transfer, request the underlying platform to cancel the write operation. If that is successful, reject reader . [[PendingRead]] with an " mediaType AbortError property of each " NDEFRecord DOMException object in an NDEF message . Example 18
  3. Set reader . [[PendingRead]] : Filter accepting only JSON content options = { } to null .
Example 19
To attempt to abort pending NDEF operations , run the following steps:
  1. Attempt to abort a pending write : Filter which only accepts binary content for on |navigator.nfc.ndef|.
  2. Attempt to abort a custom record identifier options = { , } pending read on |navigator.nfc.ndef|.

10.9 12.4 Writing content The write() method

This section describes how to write an NDEF message to an NFC tag when it is next time in comes into proximity range before a timer expires. range. At any time there is a maximum of one NDEF message that can be set for writing for an origin until the current message is sent or the write is aborted.

10.9.1 The write() method
The NDEFWriter.write NDEFReader.write method, when invoked, MUST run the write a message algorithm: following steps:
  1. Let p be a new Promise object. Let message be the first argument. Let options be the second argument. Let signal be the options Return p ’ dictionary member of and execute the same name if present, or null otherwise. next steps in parallel .
  2. If signal ’s aborted flag NFC is set, then suspended , reject p with an a " AbortError NotAllowedError " DOMException and return p . If signal is not null , then add the following abort steps to signal : Run the abort a pending write operation on the environment settings object . React to p : If p was settled (fulfilled or rejected), then clear the pending write tuple if it exists. these steps.
  3. Return p and run the following steps in parallel : If the obtain permission steps return false , then reject p with a " NotAllowedError " DOMException and abort these steps.
  4. If there is no underlying NFC Adapter , or if a connection cannot be established, then reject p with a " NotSupportedError " DOMException and abort these steps.
  5. If the UA is not allowed to access the underlying NFC Adapter (e.g. a user preference), then reject p with a " NotReadableError " DOMException and abort these steps.
  6. If pushing data Let startPolling be true if NFC polling is inactive and otherwise to false .
    Note

    Writing will temporarily start NFC polling if that is not supported by active, until the underlying first writing is done, when the temporary polling is aborted.

  7. React to p : If p was settled (fulfilled or rejected), then:
    1. Set |navigator.nfc.ndef|. [[PendingWrite]] to null .
    2. If startPolling is true , attempt to abort NFC Adapter , polling .
  8. If startPolling is true , start NFC polling . If that fails, reject p and abort these steps.
  9. Let message be the first argument.
  10. Let options be the second argument.
  11. Let signal be the options ’ dictionary member of the same name if present, or null otherwise.
  12. If signal ’s aborted flag is set, then reject p with a an " NotSupportedError AbortError " DOMException and return p .
  13. If signal is not null , then add the following abort these steps. steps to signal :
    1. Run the abort a pending write on |navigator.nfc.ndef|.
  14. An implementation MAY reject p with a " NotSupportedError " DOMException and abort these steps.
    Note

    The UA might abort message write at this point. The reasons for termination are implementation details. For example, the implementation might be unable to support the requested operation.

  15. Let output be the notation for the NDEF message NDEFMessage to be created by UA, as the result of invoking create NDEF message with message and "" . If this throws an exception, reject p with that exception and abort these steps.
  16. Attempt to abort a pending write operation . on |navigator.nfc.ndef|.
    Note

    A write invocation replaces all previously configured write operations.

  17. Set this .[[WriteOptions]] to options . Set this .[[WriteMessage]] to output reader . Set pending write tuple [[PendingWrite]] to ( this , p ). .
  18. Run the start the NFC write steps whenever an NFC tag device comes within communication range. Note If NFC is suspended , continue waiting Wait until promise is aborted by the user or an NFC tag comes within communication range. To start the NFC write , run these steps: Let p be the pending write tuple detection algorithm 's promise. Let writer be runs the pending write tuple resume writing 's writer. Let options be writer .[[WriteOptions]]. step.
  19. If the NFC tag in proximity range does not expose NDEF technology for NDEF formatting or writing, then reject p with a " NotSupportedError " DOMException and return p . Verify that NFC is not suspended .
  20. In case of success, run the following steps: If device is an NFC tag and if options 's overwrite is false , read the tag to check whether there are NDEF records on the tag. If yes, then reject p with a " NotAllowedError " DOMException and return p .
  21. Let output be writer .[[WriteMessage]]. Initiate data transfer to device using output as buffer, using the NFC adapter in communication range with device .
    Note

    If the NFC tag in proximity range is unformatted and NDEF -formatable, format it and write output as buffer.

    Note

    Multiple adapters should be used sequentially by users. There is very little likelihood that a simultaneous tap will happen on two or multiple different and connected NFC adapter s. If it happens, the user will likely need to repeat the taps until success, preferably one device at a time. The error here gives an indication that the operation needs to be repeated. Otherwise the user may think the operation succeeded on all connected NFC adapter s.

  22. If the transfer fails, reject p with " NetworkError " DOMException and abort these steps.
  23. When the transfer has completed, resolve p .

10.10 12.5 Creating NDEF message

To create NDEF message given a source and context , run these steps:
  1. Switch on source 's type:
    DOMString
    • Let textRecord be an NDEFrecord NDEFRecord initialized with its recordType set to " text " and data set to source .
    • Let records be the list « textRecord ».
    • Set source 's records to records .
    BufferSource
    • Let mimeRecord be an NDEFRecord initialized with its recordType set to " mime ", data set to source , and mediaType set to " application/octet-stream ".
    • Let records be the list « mimeRecord ».
    • Set source 's records to records .
    NDEFMessageInit
    unmatched type
  2. Let output be the notation for the NDEF message to be created by the UA as a result of these steps.
  3. For each record in the list source 's records, records , run the following steps:
    1. Let ndef be the result of running create NDEF record given record and context , or make sure the underlying platform provides equivalent values to ndef . If the algorithm throws an exception e , reject promise with e and abort these steps.
    2. Add ndef to output .
  4. If running check created records given output and context throw an error , reject promise with error and abort these steps.
  5. Return output .

10.10.1 12.5.1 Check created records

To check created records given records and context , run these steps:
  1. If context is "smart-poster" and records does not contain exactly one URI record , or if it contains more than one type record , size record or action record , throw TypeError and abort these steps.
  2. If context is "smart-poster" , move the URI record to the beginning of records .
Note

Web NFC currently allows writing external type and local type records in smart poster . Also, empty records are allowed. Applications MAY ignore any extra records inside the smart poster .

Note

Icon record media types could be limited to "image/" or "video/" , but the [ NDEF-SMARTPOSTER ] specification does actually allow other media type records in a smart poster , which can be treated in an application-specific manner, for instance a vCard contact card using one of its associated MIME types .

10.10.2 12.5.2 Creating NDEF record

To create NDEF record given record and context , run these steps:
  1. Let ndef be the representation of an NDEF record to be created by the UA.
  2. If record 's id is not undefined :
  3. Switching on record 's recordType , invoke the algorithm specified below with record , ndef and context and return the result. If an exception e is thrown, reject promise with e and abort these steps.
    " empty "
    " text "
    " url "
    " mime "
    " smart-poster "
    " absolute-url "
  4. If record 's recordType starts with a colon U+003A ( : ):
  5. If running validate external type on record 's recordType returns true , return map external data to NDEF given record , ndef and context . If that throws an exception e , reject promise with e and abort these steps.
  6. Otherwise, throw a TypeError and abort these steps.

10.10.3 12.5.3 Validating external type

The [ NFC-RTD ] specifies that external types MUST contain the domain name of the issuing organization, a colon U+003A ( : ) and a type name that is at least one character long, for instance " w3.org:member ".

The [ NFC-RTD ] specifies the URN prefix “ urn:nfc:ext: ” as well, but it is not stored in the NDEF record , therefore Web NFC applications SHOULD NOT specify the URN prefix when creating external type records .

Note

The [ NFC-RTD ] requires that external type names are represented with the URN prefix “ urn:nfc:ext: ”, e.g. when reading NDEF messages . However, since external type records are distinguished by having the TNF FIELD set to 0x04 , there is no risk seen for type name clashing. Also, there are W3C TAG recommendations to avoid using URNs in the Web. Therefore, Web NFC does not use the URN prefix neither when reading or writing NDEF messages .

To validate external type given input , run these steps:

  1. If input is not an ASCII string , is empty, or its length exceeds 255 bytes, return false .
  2. Let domain be the input from the start of input up to but excluding the first occurrence of U+003A ( : ), or null if that is not found.
  3. Let type be the input after the first occurrence, if any, of U+003A ( : ) up to the end of input , or null if that is not found.
  4. If domain or type is null , return false .
  5. Let asciiDomain be the result of running domain to ASCII given domain and true (as beStrict ).
  6. If asciiDomain is failure, return false .
  7. If asciiDomain contains a forbidden host code point or U+005F LOW LINE ( _ ), return false .
  8. If type contains code points that are not ASCII alphanumeric , or U+0024 ( $ ), U+0027 ( ' ), U+0028 LEFT PARENTHESIS ( ( ), U+0029 RIGHT PARENTHESIS ( ) ), U+002A ( * ), U+002B ( + ), U+002C ( , ), U+002D ( - ), U+002E ( . ), U+003B ( ; ), U+003D ( = ), U+0040 ( @ ), U+005F ( _ ), return false .
  9. Return true .

10.10.4 12.5.4 Validating local type

To validate local type given an input run these steps:

  1. Let localTypeName be the input after the first occurrence of U+003A ( : ) up to the end of input .
  2. If localTypeName is not a USVString or its length exceeds 255 bytes, return false and abort these steps.
  3. If localTypeName does not start with a lowercase character or a number, return false .
  4. If input is equal to the record type of any NDEF record defined in its containing NDEF message , return false .
  5. Return true .

10.10.5 12.5.5 Mapping empty record to NDEF

To map empty record to NDEF given a record ndef and context , run these steps:
  1. If record 's mediaType is not undefined , throw a TypeError and abort these steps.
  2. If record 's id is not undefined , throw a TypeError and abort these steps.
  3. Set the ndef 's TNF field to 0 ( empty record ).
  4. Set the ndef 's IL field to 0 .
  5. Set ndef 's TYPE LENGTH field , and PAYLOAD LENGTH field to 0 , and omit TYPE field and PAYLOAD field .
  6. Return ndef .

10.10.6 12.5.6 Mapping string to NDEF

To map text to NDEF given a record , ndef and context , run these steps:
Note

This is useful when clients specifically want to write text in a well-known type record . Other options would be to use the value " mime " with an explicit MIME type text type, which allows for better differentiation, e.g. when using " text/xml ", or " text/vcard ".

  1. If record 's mediaType is not undefined , throw a TypeError and abort these steps.
  2. If the type of record 's data is not DOMString or BufferSource , throw a TypeError and abort these steps.
  3. Let documentLanguage be the document element 's lang attribute.
  4. If documentLanguage is the empty string, set it to " en ".
  5. Let language be record 's lang if it exists , or else to documentLanguage .
  6. Switch on the type of record 's data :
    DOMString
    1. If record 's encoding is neither undefined nor " utf-8 ", throw a TypeError and abort these steps.
    2. Let encoding label be " utf-8 ".
    BufferSource
    1. Let encoding label be record 's encoding if it exists , or else " utf-8 ".
    2. If encoding label is not equal to " utf-8 ", " utf-16 ", " utf-16le " or " utf-16be " throw a TypeError and abort these steps.
  7. Let encoding name be the name obtained from encoding label .
  8. Let header be a byte constructed the following way:
    1. If encoding name is equal to UTF-8, set bit 7 to the value 0 , or else set the value to 1 .
    2. Set bit 6 to the value 0 (reserved).
    3. Let languageLength be the length of the language string .
    4. If languageLength cannot be stored in 6 bit ( languageLength > 63), throw a SyntaxError .
    5. Set bit 5 to bit 0 to languageLength .
  9. Let data be an empty byte sequence .
    1. Set the first byte (position 0) of data to header .
    2. Set position 1 (second byte ) to position languageLength of data to language .
    3. Switch on the type of record 's data :
      DOMString
      1. Let stream be the resulting byte stream of running UTF-8 encode on record 's data .
      2. Read bytes from stream into data (from position languageLength + 1) until read returns end-of-stream .
      BufferSource
      1. Set bytes from record 's data into data (from position languageLength + 1) .
  10. Set length to the length of data .
    1. Set the ndef 's TNF field to 1 ( well-known type record ).
    2. Set the ndef 's TYPE field to " T " ( 0x54 ).
    3. Set the ndef 's PAYLOAD LENGTH field to length .
    4. If length > 0 , set the ndef 's PAYLOAD field to data .
  11. Return ndef .

10.10.7 12.5.7 Mapping URL to NDEF

To map a URL to NDEF given a record , ndef and context , run these steps:
  1. If record 's mediaType is not undefined , throw a TypeError and abort these steps.
  2. If record 's data is not a DOMString , throw a TypeError and abort these steps.
  3. Let url be the result of parsing record 's data .
  4. If url is failure, throw a TypeError and abort these steps.
  5. Let serializedURL be serialization of url .
  6. Match the URI prefixes as defined in NFC Forum Technical Specifications , URI Record Type Definition specification, Section 3.2.2, against the serializedURL .
  7. Let prefixString be the matched prefix or else the empty string .
  8. Let prefixByte be the corresponding prefix number, or else 0 .
  9. Let shortenedURL be serializedURL with prefixString removed from the start of the string .
  10. Let data be an empty byte sequence .
    1. Set the first byte of data to prefixByte .
    2. Let stream be the resulting byte stream of running UTF-8 encode on shortenedURL .
    3. Read bytes from stream into data (from position 1) until read returns end-of-stream .
  11. Set length to the length of data .
  12. Set the ndef 's TNF field to 1 ( well-known type record ).
  13. Set the ndef 's TYPE field to " U " ( 0x55 ).
  14. Set the ndef 's PAYLOAD LENGTH field to length .
  15. If length > 0 , set the ndef 's PAYLOAD field to data .
  16. Return ndef .

10.10.8 12.5.8 Mapping binary data to NDEF

To map binary data to NDEF given a record , ndef and context , run these steps:
  1. If the type of a record 's data is not BufferSource , throw a TypeError and abort these steps.
  2. Let mimeType be the MIME type returned by running parse a MIME type on record 's mediaType .
  3. If mimeType is failure, let mimeTypeRecord be a new MIME type record whose type is " application ", and subtype is " octet-stream ".
  4. Set arrayBuffer to record 's data .
  5. Set length to arrayBuffer .[[ArrayBufferByteLength]].
  6. Set data to arrayBuffer .[[ArrayBufferData]].
  7. Set the ndef 's TNF field to 2 ( MIME type ).
  8. Set the ndef 's TYPE field to the result of serialize a MIME type with mimeType as the input.
  9. Set the ndef 's PAYLOAD LENGTH field to length .
  10. If length > 0 , set the ndef 's PAYLOAD field to data .
  11. Return ndef .

10.10.9 12.5.9 Mapping external data to NDEF

To map external data to NDEF given a record , ndef and context , run these steps:
  1. If record 's mediaType is not undefined , throw a TypeError and abort these steps.
  2. If the type of a record 's data is not BufferSource or NDEFMessageInit , throw a TypeError and abort these steps.
  3. Set ndef 's TNF field to 4 ( external type record ).
  4. Set the ndef 's TYPE field to record 's recordType .
  5. If the type of a record 's data is BufferSource ,
    1. Set arrayBuffer to record 's data .
    2. Set length to arrayBuffer .[[ArrayBufferByteLength]].
    3. Set data to arrayBuffer .[[ArrayBufferData]].
    4. Set the ndef 's PAYLOAD LENGTH field to length .
    5. If length > 0 , set the ndef 's PAYLOAD field to data .
  6. If the type of a record 's data is NDEFMessageInit ,
    1. Set the ndef 's PAYLOAD field to the result of running the create NDEF message given record 's data and "external" .
    2. Set the ndef 's PAYLOAD LENGTH field to the length of ndef 's PAYLOAD field .
  7. Return ndef .

10.10.10 12.5.10 Mapping local type to NDEF

To map local type to NDEF given a record , ndef and context , run these steps:
  1. If record 's mediaType is not undefined , throw a TypeError and abort these steps.
  2. If the type of a record 's data is not BufferSource or NDEFMessageInit , throw a TypeError and abort these steps.
  3. Set ndef 's TNF field to 1 ( well-known type record ).
  4. Let localTypeName be the record 's recordType after the first occurrence of U+003A ( : ) up to the end of record 's recordType .
  5. Set ndef 's TYPE field to localTypeName , representing the local type name .
  6. If context is "smart-poster" , localTypeName is " s " ( 0x73 ) and if the type of record 's data is not BufferSource or its byte length is bigger than 4, throw a TypeError and abort these steps.
  7. If context is "smart-poster" , localTypeName is " act " ( 0x61 0x63 0x74 ) and if the type of record 's data is not BufferSource or its byte length is not exactly one, throw a TypeError and abort these steps.
  8. If the type of a record 's data is BufferSource ,
    1. Set arrayBuffer to record 's data .
    2. Set length to arrayBuffer .[[ArrayBufferByteLength]].
    3. Set data to arrayBuffer .[[ArrayBufferData]].
    4. Set the ndef 's PAYLOAD LENGTH field to length .
    5. If length > 0 , set the ndef 's PAYLOAD field to data .
  9. If the type of a record 's data is NDEFMessageInit ,
    1. Set the ndef 's PAYLOAD field to the result of running the create NDEF message given record 's data and "local" .
    2. Set the ndef 's PAYLOAD LENGTH field to the length of ndef 's PAYLOAD field .
  10. Return ndef .

10.10.11 12.5.11 Mapping smart poster to NDEF

To map smart poster to NDEF , given a record ndef and context , run these steps:
  1. If record 's mediaType is not undefined , throw a TypeError and abort these steps.
  2. If the type of a record 's data is not NDEFMessageInit , throw a TypeError and abort these steps.
  3. Set ndef 's TNF field to 1 ( well-known type record ).
  4. Set ndef 's TYPE field to " Sp " ( 0x53 0x70 ).
  5. Set ndef 's PAYLOAD field to the result of running the create NDEF message given record 's data and "smart-poster" .
  6. Set ndef 's PAYLOAD LENGTH field to the length of ndef 's PAYLOAD field .
  7. Return ndef .

10.10.12 12.5.12 Mapping absolute-URL to NDEF

To map absolute-URL to NDEF given a record ndef and context , run these steps:
  1. If context is "smart-poster" , throw a TypeError and abort these steps.
    Note

    The [ NDEF-SMARTPOSTER ] specification allows only one URL in a smart poster and that MUST be a single URI record .

  2. If record 's mediaType is not undefined , throw a TypeError and abort these steps.
  3. If record 's data is not a DOMString , throw a TypeError and abort these steps.
  4. If the result of parsing record 's data is failure, throw a SyntaxError and abort these steps.
  5. Set arrayBuffer to record 's data .
  6. Set data to arrayBuffer .[[ArrayBufferData]].
  7. Set ndef 's TNF field to 3 ( absolute-URL record ).
  8. Set ndef 's TYPE field to data .
  9. Set ndef 's PAYLOAD LENGTH field to 0 and omit PAYLOAD field .
  10. Return ndef .

10.11 12.6 Listening for content The read() method

To listen for NFC content , the client MUST activate an NDEFReader instance by calling As opposed to NDEFReader.scan() NDEFReader.write . When attaching an event listener for the " reading " event on it, , which will temporarily start NFC content polling if that is accessible to the client. If there are any NDEFReader instances not active, in activated reader objects then the UA MUST order to listen for NFC content , clients should make sure to NDEF message s on all connected start NFC adapters. Each NDEFReader can accept NDEF message s based on data type, and record identifier filters. 10.11.1 Match patterns A match pattern is defined by the following ABNF: parameters ] > subtype = "*" / < VCHAR except "+" > A match pattern is a glob used for matching MIME type s, for instance the pattern " application/*+json " matches " application/calendar+json ", but does not match " application/json ". The pattern " */*json ", on the other hand, matches both. 10.11.2 The scan() method polling Incoming before being able to read NFC content is matched using NDEFReader instances. .

When the NDEFReader.scan NDEFReader.read method is invoked, the UA MUST run the following NFC listen algorithm : steps:
  1. Let p be a new Promise object. Let reader be the NDEFReader instance. Let options be first argument. For each key → value of options : If key Return p equals " signal " and value is not undefined , set reader . [[Signal]] to value . Otherwise, if key equals " id ", set reader . [[Id]] to value . Otherwise, if key equals " recordType ", set reader . [[RecordType]] to value . Otherwise, if key equals " mediaType ", set reader . [[MediaType]] to value . run the next steps in parallel .
  2. If reader . [[Signal]] 's aborted flag NFC is set, then suspended , reject p with a " AbortError NotAllowedError " DOMException and return p . If reader . [[Signal]] is not null , then add the following abort steps to reader . [[Signal]] : Remove the NDEFReader instance from the activated reader objects . If the activated reader objects is empty , then make a request to stop listening to NDEF message s on all NFC adapter s. these steps.
  3. Return p and run the following steps in parallel : If the obtain permission steps return false , then reject p with a " NotAllowedError " DOMException and abort these steps.
  4. If there is no underlying NFC Adapter , or if a connection cannot be established, then reject p with a " NotSupportedError " DOMException and abort these steps.
  5. If the UA is not allowed to access the underlying NFC Adapter (e.g. a user preference), then reject p with a " NotReadableError " DOMException and abort these steps.
  6. Add reader Let startPolling be true if NFC polling is inactive and otherwise to false .
    Note

    Reading will temporarily start NFC polling if that is not active, until the activated reader objects . first reading is done, when the temporary polling is aborted.

  7. Resolve React to p . : If p was settled (fulfilled or rejected), then:
    1. Whenever the UA Set |navigator.nfc.ndef|. [[PendingRead]] detects NFC technology, run the to null .
    2. If startPolling is true , attempt to abort NFC reading algorithm polling .
  8. 10.11.3 The
  9. If startPolling is true , start NFC reading algorithm polling . If that fails, reject p with a " NotReadableError " DOMException To receive NDEF content, run the NFC reading algorithm : If NFC is suspended , and abort these steps.
  10. If Let reader be the NFC tag in proximity range does not expose NDEF technology for reading or formatting, run |navigator.nfc.ndef| instance.
  11. Let options be first argument.
  12. Let signal be the following sub-steps: options ’ dictionary member of the same name if present, or null otherwise.
  13. For each If signal 's aborted flag is set, then reject p with a " NDEFReader AbortError " DOMException instance reader .
  14. If signal in the activated reader objects , run is not null , then add the following sub-steps: abort steps to signal :
    1. Fire an event Attempt to abort a pending read named " error " at on reader .
  15. Abort these steps. Set |navigator.nfc.ndef|. [[PendingRead]] to p .
  16. Attempt to abort a pending read on |navigator.nfc.ndef|.
    Note

    A read invocation replaces all previously started read operations.

  17. Let serialNumber be Wait until the device identifier as a series of numbers, or null if unavailable. NFC detection algorithm runs the resume reading step.
  18. If serialNumber is the NFC tag in proximity range does not expose NDEF technology for reading or formatting, reject p with a " null , set it to the string NotSupportedError of U+003A ( : " DOMException ) concatenating each number represented as ASCII hex digit , in the same order. and abort these steps.
  19. Let message be a new NDEFMessage object, with message 's records set to the empty list .
  20. If the NFC tag in proximity range is unformatted and is NDEF-formattable, let input be null . Otherwise, let input be the notation for the NDEF message which has been received.
    Note

    The UA SHOULD represent an unformatted NFC tag as an NDEF message containing no NDEF record s, i.e. an empty array for its records property.

  21. For each NDEF record which is part of input , run the following sub-steps:
    1. Let ndef be the notation for the current NDEF record with typeNameField corresponding to the TNF field and payload corresponding to the PAYLOAD field data.
    2. Let record be the result of parse an NDEF record given ndef and "" .
    3. If record is not null , append record to message 's records.
  22. If NFC is not suspended , run the dispatch NFC content steps with given serialNumber and message . 10.11.4 Dispatching NFC content To dispatch NFC content given a serialNumber of type serialNumber and a message of type NDEFMessage , run these steps: For each NDEFReader instance reader in the activated reader objects , run the following sub-steps: For each record in message , Let matched be false . If reader . [[Id]] is not undefined and is not equal to record 's id , continue . If it is equal, set matched to true . If reader . [[RecordType]] is not undefined and is not equal to record 's recordType , continue . If it is equal, set matched to true . If reader . [[MediaType]] is not undefined and is not equal to record 's mediaType , continue . If it is equal, set matched to true . If matched is true , fire an event named " reading " at reader Resolve p using NDEFReadingEvent with its serialNumber attribute initialized to serialNumber and message attribute initialized to message .
  23. Break .

10.12 12.7 Parsing content

10.12.1 12.7.1 Parsing records from bytes

To parse records from bytes given bytes and context , run these steps:
  1. If the length of bytes is 0 , return null and abort these steps.
  2. Let records be the empty list.
  3. As long as there are unread bytes of bytes , run the following sub-steps:
    1. If the remaining length of bytes is less than 3 , return null and abort these sub-steps.
    2. If any of the following steps requires reading bytes beyond the remaining length of bytes , return null and abort these sub-steps.
    3. Let ndef be the notation for the current NDEF record .
    4. Let header be the next byte of bytes .
      1. Let messageBegin ( MB field ) be the left most bit (bit 7) of header .
      2. If this is the first iteration of these sub-steps and messageBegin is false , return null and abort these sub-steps.
      3. Let messageEnd ( ME field ) be bit 6 of header .
      4. Note

        As chunked records are not allowed as sub records, ignore bit 5 ( CF field ) is ignored.

      5. Let shortRecord ( SR field ) be bit 4 of header .
      6. Let hasIdLength ( IL field ) be bit 3 of header .
      7. Let ndef 's typeNameField ( TNF field ) be the integer value of bit 2-0 of header .
    5. Let typeLength be the integer value of next byte ( TYPE LENGTH field ) of bytes .
    6. If shortRecord is true , let payloadLength be the integer value of next byte ( PAYLOAD LENGTH field ) of bytes .
    7. Otherwise, let payloadLength be the integer value of the next 4 bytes of bytes .
    8. If hasIdLength is true , let idLength be the integer value of next byte ( ID LENGTH field ) of bytes , otherwise let it be 0 .
    9. If typeLength > 0, let ndef 's type be result of running UTF-8 decode on the next typeLength ( TYPE field ) bytes, or else let type be the empty string.
    10. If idLength > 0, let ndef 's id be result of running UTF-8 decode on the next idLength ( ID field ) bytes, or else let ndef 's id be the empty string.
    11. Let ndef 's payload be the byte sequence of the last payloadLength ( PAYLOAD field ) bytes, which may be 0 bytes.
    12. Let record be the result of parse an NDEF record given ndef and context .
    13. If record is not null , append record to records .
    14. If messageEnd is true ,
      1. If check parsed records given records and context throws an error , reject promise with error and abort these steps.
      2. Otherwise abort these sub-steps (terminate the loop).
  4. Return records .

10.12.2 12.7.2 Check parsed records

To check parsed records given records and context , run these steps:
  1. If context is "smart-poster" and records does not contain exactly one URI record , or if it contains more than one type record , size record or action record , throw TypeError and abort these steps.
  2. Otherwise return true .

10.12.3 12.7.3 Parsing NDEF records

To parse an NDEF record given ndef and context into a record , run these steps:
  1. Set record 's id to ndef 's id .
  2. Set record 's lang to null .
  3. Set record 's encoding to null .
  4. If ndef 's typeNameField ( TNF field ) is 0 ( empty record ):
    1. Set record 's id to null .
    2. Set record 's recordType to " empty ".
    3. Set record 's mediaType to null .
    4. Set record 's data to null .
  5. If ndef 's typeNameField is 1 ( well-known type record ), then
    1. If ndef 's type is " T " ( 0x54 ) , set record to the result of running parse an NDEF text record on ndef .
    2. If ndef 's type is " U " ( 0x55 ) , set record to the result of running parse an NDEF URL record on ndef .
    3. If ndef 's type is " Sp " ( 0x53 0x70 ) , set record to the result of running parse an NDEF smart-poster record on ndef .
    4. If ndef 's type is " s " ( 0x73 ) and if context is equal to "smart-poster" , set record to the result of running parse a smart-poster size record on ndef .
    5. If ndef 's type is " t " ( 0x74 ) and if context is equal to "smart-poster" , set record to the result of running parse a smart-poster type record on ndef .
    6. If ndef 's type is " act " ( 0x61 0x63 0x74 ) and if context is equal to "smart-poster" , set record to the result of running parse a smart-poster action record on ndef .
    7. If running the validate local type steps on ndef 's type returns true ,
      1. If context is not "external" or "smart-poster" , throw a TypeError and abort these steps.
      2. Set record to the result of running parse a local type record on ndef .
    8. Otherwise throw a TypeError and abort these steps.
  6. If ndef 's typeNameField is 2 ( MIME type record ), then set record to the result of running parse an NDEF MIME type record on ndef , or make sure that the underlying platform provides equivalent values to the record object's properties.
  7. If ndef 's typeNameField is 3 ( absolute-URL record ), then set record to the result of running parse an NDEF absolute-URL record on ndef .
  8. If ndef 's typeNameField is 4 ( external type record ), then set record to the result of running parse an NDEF external type record on ndef , or make sure that the underlying platform provides equivalent values to the record object's properties.
  9. If ndef 's typeNameField is 5 ( unknown record ) then set record to the result of running parse an NDEF unknown record on ndef , or make sure that the underlying platform provides equivalent values to the record object's properties.
  10. Otherwise throw a TypeError and abort these steps.

10.12.4 12.7.4 Parsing NDEF well-known T records

To parse an NDEF text record given an ndefRecord into a record , run these steps:
  1. Set record 's recordType to " text ".
  2. Set record 's mediaType to null .
  3. If ndefRecord 's PAYLOAD field is not present, set record 's data to null and return record .
  4. Let header be the first byte of ndefRecord 's PAYLOAD field .
  5. Let languageLength be the value given by bit 5 to bit 0 of the header .
  6. Let language be the result of running ASCII decode on second byte to the languageLength + 1 byte, inclusive.
  7. Set record 's lang to language .
  8. Set record 's encoding be " utf-8 " if bit 7 ( MB field ) of header is equal to the value 0 , or else " utf-16be ".
  9. Let buffer be the byte sequence of ndefRecords 's PAYLOAD field .
  10. Set record 's data to buffer .
  11. Return record .
Note

10.12.5 12.7.5 Parsing NDEF well-known U records

To parse an NDEF URL record given an ndefRecord into a record , run these steps:
  1. Set record 's recordType to " url ".
  2. Set record 's mediaType to null .
  3. If ndefRecord 's PAYLOAD field is not present, set record 's data to null and return record .
  4. Let buffer be the byte sequence of ndefRecords 's PAYLOAD field .
  5. Let prefixByte be the value of the first byte of buffer .
  6. If the value of prefixByte matches the URL expansion codes in the NFC Forum Technical Specifications URI Record Type Definition specification, Section 3.2.2, Table 3, then
    1. Let prefixString be the byte sequence value corresponding to the value of prefixByte .
    2. Set record 's data to prefixString appended to buffer .
  7. Otherwise, if there is no match for prefixByte , set record 's data to buffer .
  8. Return record .

10.12.6 12.7.6 Parsing NDEF well-known Sp records

To parse an NDEF smart-poster record given an ndefRecord into a record , run these steps:
  1. Set record 's recordType to " smart-poster ".
  2. Set record 's mediaType to null .
  3. If ndefRecord 's PAYLOAD field is not present, set record 's data to null and return record .
  4. Let buffer be the byte sequence of ndefRecords 's PAYLOAD field .
  5. Set record 's data to buffer .
  6. Return record .
    Note

    Applications may call toRecords() on data to parse it to NDEF records , or may parse it themselves.

To parse a smart-poster size record given an ndefRecord into a record , run these steps:
  1. Set record 's recordType to " :s ".
  2. Set record 's mediaType to null .
  3. If ndefRecord 's PAYLOAD field has not exactly 4 bytes, throw a TypeError and abort these steps.
  4. Let buffer be the byte sequence of ndefRecords 's PAYLOAD field .
  5. Set record 's data to buffer .
    Note

    Applications can parse this value as a 32 bit unsigned integer that denotes the size of the object the URI record in the smart-poster refers to.

  6. Return record .
To parse a smart-poster type record given an ndefRecord into a record , run these steps:
  1. Set record 's recordType to " :t ".
  2. Set record 's mediaType to null .
  3. Let buffer be the byte sequence of ndefRecords 's PAYLOAD field .
    Note

    Applications can parse this value as a string that contains an [ RFC2048 ] media type that denotes the media type of the object the URI record in the smart-poster refers to.

  4. Set record 's data to buffer .
  5. Return record .
To parse a smart-poster action record given an ndefRecord into a record , run these steps:
  1. Set record 's recordType to " :act ".
  2. Set record 's mediaType to null .
  3. If ndefRecord 's PAYLOAD field has not exactly 1 byte, throw a TypeError and abort these steps.
  4. Let buffer be the byte sequence of ndefRecords 's PAYLOAD field .
  5. Set record 's data to buffer .
    Note

    Applications can parse this value as an 8 bit unsigned integer for which the values are defined here .

  6. Return record .

10.12.7 12.7.7 Parsing local type records

To parse a local type record given ndef into a record , run these steps:
  1. Set record 's recordType to " : " ( U+003A ) concatenated with ndef 's type .
  2. Set record 's mediaType to null .
  3. Let buffer be the byte sequence of ndefRecords 's PAYLOAD field .
  4. Set record 's data to buffer .
  5. Return record .

10.12.8 12.7.8 Parsing NDEF MIME type records

To parse an NDEF MIME type record given an ndefRecord into a record , run these steps:
  1. Set record 's recordType to " mime ".
  2. Set record 's mediaType to the result of serialize a MIME type with mimeType as the input.
  3. Let buffer be the byte sequence of ndefRecords 's PAYLOAD field if that exists, or otherwise null .
  4. Set record 's data to buffer .
  5. Return record .

10.12.9 12.7.9 Parsing NDEF absolute-URL records

To parse an NDEF absolute-URL record given an ndefRecord into a record , run these steps:
  1. Set record 's recordType to " absolute-url ".
  2. Set record 's mediaType to null .
  3. Let buffer be the byte sequence of ndefRecords 's TYPE field .
  4. Set record 's data to buffer .
  5. Return record .

10.12.10 12.7.10 Parsing NDEF external type records

To parse an NDEF external type record given an ndefRecord into a record , run these steps:
  1. Set record 's recordType to the value of ndefRecord 's TYPE field .
  2. Set record 's mediaType to null .
  3. Let buffer be the byte sequence of ndefRecords 's PAYLOAD field if that exists, or otherwise null .
  4. Set record 's data to buffer .
  5. Return record .

10.12.11 12.7.11 Parsing NDEF unknown type records

To parse an NDEF unknown record given an ndefRecord into a record , run these steps:
  1. Set record 's recordType to " unknown ".
  2. Set record 's mediaType to null .
  3. Let buffer be the byte sequence of ndefRecords 's PAYLOAD field if that exists, or otherwise null .
  4. Set record 's data to buffer .
  5. Return record .

11. 13. The Blocklist

This specification relies on a blocklist file to restrict the set of NFC devices a website can access.

The result of parsing the blocklist at a url is a list of historical bytes hexadecimal values, produced by the following algorithm:

  1. Fetch url , and let contents be its body, decoded as UTF-8.
  2. Let lines be contents split on "\n" .
  3. Let result be an empty list .
  4. For each line in lines , run the following sub-steps:
    1. If line is empty, continue to the next line.
    2. If line starts with "#" , continue to the next line.
    3. If line contains invalid hexadecimal values, continue to the next line.
    4. Append line to result .
  5. Return result .

The blocklist is the result of parsing the blocklist at https://github.com/w3c/web-nfc/blob/gh-pages/blocklist.txt . The UA should re-fetch the blocklist periodically, but it’s unspecified how often.

An NFC device is blocklisted if the blocklist ’s value contains the device's historical bytes hexadecimal values. In ISO 14443-4 terminology, the historical bytes are a subset of the RATS (Request for Answer To Select) response.

12. 14. Security and Privacy

12.1 14.1 Chain of trust

Implementations need to make sure that when the user authorizes a method which is part of the Web NFC API, only that action is run, without side effects.

By default, NDEF doesn't provide any way to make the content trusted beyond allowing tags to be made permanently read-only after writing data to them. This can even be done from a factory setting.

Data written by the use of this API is not signed or encrypted automatically, which follows existing native NFC APIs. In order to protect the integrity and authenticity of NDEF messages, the NFC Forum introduced [ NDEF-SIGNATURE ]. Using NDEF signature and key management is the responsibility of the application.

For trusting the confidentiality of the data exchanged via NFC, applications may use encrypted NFC content .

For trusting the integrity of the data exchanged via NFC, applications may use an NDEF signature , with key management based on Public Key Infrastructure (PKI).

Security considerations for MIME types in general are discussed in [ RFC2048 ] and [ RFC2046 ].

12.2 14.2 Privacy implications and implementation considerations

The comparison to barcodes or QR codes is appropriate because NFC tags are another non-human-readable method of exchanging data and sharing them can have unforeseen privacy and security implications. For a web site to read a QR code, a piece of interruptive UI must be used (the camera) which captures an image and makes it apparent that the contents of this image (including the QR code) will be available to the web page, making it clear to the user that scanning is being performed.

Scanning a tag with NFC requires the user to place the scanning device (e.g. phone) in close proximity to the NFC tag - usually 5-10 cm, 2-4 inches.

Scanning a tag when a Web NFC scan is not active, triggers the host OS handling. Thus launching URLs and apps from scanning a NFC tag is not handled and supported by Web NFC itself.

Furthermore, Web NFC scanning needs to be activated from a user interaction, and scanning is paused when the web site is not in focus or the device screen turns off (i.e. is not unlocked). This is put in place so that accidental scans are not likely to happen.

Web NFC further recommends that the implementation makes it very clear UX-wise to the user that data will be scanned when placing the scanning device in close proximity to a NFC tag - basically mimicking the UX flow of scanning a QR code.

There are many options for doing so, like playing back a sound or showing some persistent UI while the scanning can happen, for instance a modal dialog with the ability to cancel at any point.

An implementation could also show the data that is about to be uploaded, postpone sharing the read data until the user OK'd it and even show some UI allowing the user to select which records to share.

12.2.1 14.2.1 Reading and writing during a scan

When the user scans a tag, at that point the web application has access to read the data on the tag, and in case it is not read-only, also to write data to the tag. Consumer stickers for private usage (e.g. in the maker community) are often unlocked (read + write), whereas commercial deployment of NFC are read-only.

Note

An older protocol SNEP (Simple NDEF Exchange Protocol) allowed active devices (e.g. a phone) to receive NDEF data from another active device, but it is unsupported by Web NFC and it is currently being deprecated on supported native platforms.

Note

A newer protocol TNEP (Tag NDEF Exchange Protocol) allows bidirectional communication between a scanner device (e.g. phone) and actively powered device like an IOT device. It is currently unsupported by Web NFC, and furthermore it has restrictions on what input to accept and the IOT device must ensure that the accepted records are valid.

If the tag contains privacy sensitive data, such data will be shared with the site. Potentially, not immediately if the UX requires the user to confirm the data exchange before doing so.

In some cases it might be obvious that the tag/device contains privacy sensitive data, say in case of NFC equipped conference badgets and business cards. This would also be the case with an NFC equipped glucose meter, which can indicate that you, or someone in the close family, are a diabetes patient.

In other cases it might be less obvious that that can happen, but a user might have used an app or website to write data to a tag that unknowingly to the user encoded a user id or the like, which can later be read back by any other site.

Private and unexpected data can also be stored in files (e.g. word pressing documents, PDFs or camera images) which are uploaded using the file upload API. The mitigations associated with the Web NFC API are stronger than those associated with file upload and the data less likely to be personally identifiable.

12.2.2 14.2.2 Reading and writing during a scan

A scan of a tag might also reveal user location if the website knows how to identify the tag and know the tags location in the real world, like if it is mounted inside a museum. It might also be able to deduct it somewhat as for instance FeliCa NFC tags are mostly used in Japan, but Web NFC doesn’t reveal what tag technology is used.

This does not bring the web advertising and tracking model into the real world, because it requires an action by the user and it cannot be triggered in the background; and with proper UX it should be clear that scanning is active.

12.2.3 14.2.3 Overwriting existing data

There is also the fear that writing to a NFC tag can ruin it or “brick it”. As NFC tags were designed to be read by multiple user applications, NDEF tags have been designed with an easy way to make devices permanently read-only and can even be configured that way from a factory.

NDEF is a simple exchange format for reading and writing data and not for bi-directional communication. NFC supports multiple communications formats based on lower tech (thus not locked as read-only as NDEF) and none of these are supported by Web NFC.

12.3 14.3 Things that users should be made aware of when using NFC

This section details some of the things that users ought to be aware of when using NFC. It is recommendated that implementations help educate the users of given facts before or when related NFC actions are performed.

Data that is read is shared with site

When a site has access to read NFC content, then the data of the scanned tags is shared with the site, in a similar way to uploading files and images. As with any site, it is up to the user whether to trust that the site handles this data properly and in the intended manner.

A site may modify and overwrite data of tags that are not made read-only

Deployed NFC solutions, like tags in stores etc, should always be made read-only in order to ensure they are not modified by mistake or as part of a malicious act.

Private tags and stickers are often unlocked (writable) from the factory and the user should be aware that such tags might be overwritten/modified by scanning them.

Reading a fixed (e.g. mounted) tag may expose reading location

A fixed tag may encode its ID or location in the data, meaning that reading it exposes that information to the site that knows the physical location of the tag, which then can deduct the location the read took place. That combined with being logged into a service, can share your location data with the site.

Data written is readable by other apps and sites with granted read access Any NDEF data on a tag can be read by any app or web site with the proper access, so if that is not intended then the data should be encrypted in a secure manner that only who is supposed to read it can.

Multiple tags may be within the reading field at the same time

NFC can only read one tag at the time, but multiple tags can be detected and one of the tags can be selected as the tag to communicate with.

Use cases for this could be having multiple smart cards (NFC based) in your wallet and not wanting to take the card out.

This is mostly useful for payment cards and travel cards that are read by external hardware and thus not a use-case for Web NFC. For Web NFC, we do not allow reading when there are multiple tags available, preventing the following attack vector.

There is an attack vector, where someone places another malicious NFC tag/sticker on top of a legitimate tag, in order to load the wrong app/site, or inject wrong data into the right app/site. They can do so by cloning the data of the original tag and modifying it - either by changing the URL to load a malicious app/site, or by changing the data to inject malicious data in the right app/site. Example: the tag is supposed to take you to https://example.com but is modified to take you to https://exаmple.com (that is with a Cyrillic а) - it looks legitimate and you might now to giving sensitive data to a malicious site.

Loading web sites from a tag is outside the scope of Web NFC, but it is recommended for user agents to not auto load URLs when multiple tags are available due to the above attack vector.

By disallowing reading when there are multiple tags available, Web NFC protects well against injecting wrong/malicious data into a site as shielding the existing NFC tag is quite difficult as it requires ferrite shielding which is quite visible. Metal interferes with the magnetic field and makes tags not readable.

12.4 14.4 Assets

This section is non-normative.

Assets to be protected include the following:
  • NDEF message as a whole, NDEF records (including payload and header) in particular, either in-transfer or in-storage state, when they are being overwritten by a Web NFC triggered operation, against data disclosure and data modification. This also includes Denial of Service attacks against a solution deployed with NFC tags (e.g. a malicious actor destroying tags linked to a solution).
  • User identity or other privacy sensitive attributes that can be directly or indirectly determined by using Web NFC, by the NFC content creator, or by a web site using Web NFC. This data could be used directly or leaked forward to third parties. Examples are user location, device identifiers and user identifiers.
  • User data exposed to a web page using Web NFC. While a web page might collect user data using other means than Web NFC, it might embed this data into NDEF records and share via Web NFC.
  • Integrity of user device . A read of an NFC tag might result in a user device compromise that can further lead to loss of other web NFC or platform assets.

12.5 14.5 Attacker model

This section is non-normative.

The following attacker patterns have been considered:

12.6 14.6 Threats

This section is non-normative.

An introduction to NFC security is found here . Potential threats for Web NFC are given below.

12.6.1 14.6.1 Fingerprinting and data collection

Threat description
Malicious web page collects user data, identity or other privacy sensitive attributes (such as location) without user consent and exposes it to third parties (writing it to NFC tags).
Affected assets
User data, user identity or other privacy sensitive attributes
Actors
Malicious web page owner using Web NFC, malicious tag owner.
Mitigation, comments
The user SHOULD be able to be aware of what data can be shared using NFC from the given web page. Use permissions and user prompts for accessing personal data, minimize user data exposed to NFC. An NFC tag SHOULD NOT ever trigger a user’s device to navigate to a web site without asking permission, unless the site has been in the foreground or has been brought to the foreground and has been granted permission. User agents SHOULD take into account the security and privacy measures listed in the Geolocation API .

12.6.2 14.6.2 NFC tag modification

Threat description
An NFC tag is being modified without user consent. This might enable further attacks using a malicious tag or can be a Denial of Service attack to make one or more tags unusable.
Affected assets
NDEF message records, including payload and header in-storage.
Actors
Malicious web page creator, malicious user.
Mitigation, comments
Require permission and user prompt needed for writing tags. Or, control what tags can be written by a given web page, for instance a web page can write only a tag that can be connected to its origin . Or, allow overwriting since tags not meant to be written can be protected by making them read only. Use NDEF signature to detect a modification of NFC tags.

12.6.3 14.6.3 NDEF record modification in-transit

Threat description
NDEF record s transferred between Web NFC and the NFC adapter and user device are modified to cause various man-in-the-middle attacks or denial-of-service (DoS) attacks. Also, NDEF signature records can be removed or replaced along with changed content.
Affected assets
NDEF record s in-transfer.
Actors
Malicious man-in-the-middle user.
Mitigation, comments
This threat is out of scope for Web NFC implementations. Applications can use NDEF signature s and appropriate tools (signature algorithm, certificates, security policies) to protect the NFC content . Additionally, harden the platform stack.

12.6.4 14.6.4 NDEF record payload disclosure

Threat description
Confidential payload of NDEF record in-storage (stored on an NFC tag) or in-transfer between Web NFC and the NFC adapter are read by unauthorized parties.
Affected assets
Confidential NDEF message payload in-transfer and in-storage.
Actors
Malicious man-in-the-middle user, malicious web page creator.
Mitigation, comments
To ensure confidentiality, use payload encryption and secure communication for data exchange, authentication and authorization between Web NFC and NFC adapter s.

12.6.5 14.6.5 Active attack via malicious NFC tag

Threat description
Malicious tag may be involuntarily or voluntarily read by devices and the data read may constitute an attack vector on the user agent. For example it can attempt to trigger an action on the device, which may be a threat, for instance launching a malicious web site, or opening an image prepared for attacking the device.
Affected assets
Integrity of user device, all other Web NFC assets.
Actors
Malicious tag creator.
Mitigation, comments
This is a generic problem with all existing NFC tags. The data is considered application specific. Implementations need security hardening. Involuntary touch is low probability due to short range and critical angle for reading, and due to the focus requirements. Automatic actions for smart posters and other tags should not be allowed. The user must be made aware and given the ability to control what is happening during the NFC communication. For instance, opening content from smart poster , automatic connection to (possibly malicious) WiFi via NFC handover , etc. Do no allow actions from untrusted NFC tags, trust can be established via the NDEF signature check.

12.7 14.7 Security mechanisms for implementations

This section is non-normative.

12.7.1 14.7.1 Obtaining permission

Implementations SHOULD use a mechanism to obtain permission , for instance an explicit permission given by the user. The Permissions API is suggested to be used by UAs for implementing NFC related permissions.

Implementations MAY use per-session/ephemeral permissions.

12.7.2 14.7.2 Warning user during NFC operations

Implementations MAY show an overlay dialog whenever the NFC adapter is being accessed by the web page (e.g. there is an ongoing scan) in order to warn user.

12.8 14.8 Security mechanisms for applications

This section is non-normative.

12.8.1 14.8.1 Encrypting NFC content

For trusting the confidentiality of the data exchanged via NFC, applications may use encrypted NFC content with key management based on Public Key Infrastructure (PKI). Key management is out of the scope of Web NFC.

12.8.2 14.8.2 Signing NDEF records

For trusting the integrity of the data exchanged via NFC, user agents MAY use an NDEF signature with a Public Key Infrastructure for key management.

For tags signed with NDEF signature version 1.0 ([ NFC-SECURITY ]), the signature is applied only to the TYPE field , ID field and PAYLOAD field , leaving out the first byte of the NDEF header, allowing surface to attacks. Version 2.0 of [ NFC-SECURITY ] included tag hardware attributes in the signature and allowed for shorter certificates.

An NDEF signature covers the preceding records until another NDEF signature or the beginning of the NDEF message is reached.

In order to mitigate known vulnerabilities of NDEF signature , it is recommended that applications always sign a full NDEF message with a single NDEF signature , and use the right tool chain and security policies for creating and verifying signatures.

12.9 14.9 Security policies

This section lists the normative security policies for implementations.

12.9.1 14.9.1 Secure Context

Only secure contexts are allowed to access NFC content . Browsers MAY ignore this rule for development purposes only.

12.9.2 14.9.2 Visible document

Web NFC functionality is allowed only for the Document of the top-level browsing context , which must be visible .

This also means that UAs should block access to the NFC radio if the display is off or the device is locked. For backgrounded web pages, receiving and writing NFC content must be suspended .

12.9.3 14.9.3 Permissions controls

Making an NFC tag read-only MUST obtain permission , or otherwise fail.

Setting up listeners for reading NFC content SHOULD obtain permission .

Writing NFC content to an NFC tag MUST obtain permission . See the §  10.9 12.4 Writing content The write() method section.

All permission that are preserved beyond the current browsing session MUST be revocable.

12.9.4 14.9.4 Blocklist

Web NFC includes a blocklist of vulnerable NFC devices to prevent websites from taking advantage of them.

12.9.5 14.9.5 Warn about risk of physical location leak

When listening for and writing NFC content , the UA MAY warn the user that the given origin may be able to infer physical location.

12.9.6 14.9.6 Restrict automatic handling

When the payload data on NFC content is untrusted, it MUST NOT be used by the UA to do automatic handling of the content, such as opening a web page with a URL found in an NFC tag , or installing an application, or other actions, unless the user approves that.

12.9.7 14.9.7 Signing NFC content

The following policies are recommended to be implemented by applications.

A. IDL Index

WebIDL[SecureContext, Exposed=Window]
interface 
  
  readonly attribute

interface NDEFMessage {
  constructor(NDEFMessageInit messageInit);
  readonly attribute FrozenArray<NDEFRecord> records;

};
dictionary 

dictionary NDEFMessageInit {

  required sequence<NDEFRecordInit> records;
};
typedef (DOMString or BufferSource or NDEFMessageInit) NDEFRecordDataSource;
[SecureContext, Exposed=Window]
interface 

interface NDEFRecord {

  constructor(NDEFRecordInit recordInit);
  readonly attribute
  readonly attribute
  readonly attribute

  readonly attribute USVString recordType;
  readonly attribute USVString? mediaType;
  readonly attribute USVString? id;

  readonly attribute DataView? data;
  readonly attribute USVString? encoding;
  readonly attribute USVString? lang;
  

  sequence<NDEFRecord>? toRecords();
};
dictionary NDEFRecordInit {
  required USVString recordType;
  USVString mediaType;
  USVString id;
  USVString encoding;
  USVString lang;
  NDEFRecordDataSource data;
};
[]
interface 
  

[SecureContext]
partial interface Navigator {
  [SameObject]
  readonly attribute NFC nfc;
};

  
};

[SecureContext, Exposed=Window]
interface NFC {
  readonly attribute NDEFReader ndef;
  attribute EventHandler ontagfound;
  attribute EventHandler onerror;
  Promise<undefined> start(optional NFCOptions options={});
};

[SecureContext, Exposed=Window]
interface 
  
  attribute
  attribute

interface NFCTagFoundEvent : Event {
  constructor(DOMString type, NFCTagFoundEventInit tagfoundEventInitDict);
  readonly attribute DOMString serialNumber;
};

  
};

dictionary NFCTagFoundEventInit : EventInit {
  DOMString? serialNumber = "";
};

[]
interface 
  

dictionary NFCOptions {
  AbortSignal signal;
};

  readonly attribute
  [
};

typedef (DOMString or BufferSource or NDEFMessageInit) NDEFMessageSource;
dictionary 
  
  required

[SecureContext, Exposed=Window]
interface NDEFReader {
  Promise<NDEFMessage> read(optional NDEFReadOptions options={});  Promise<undefined> write(NDEFMessageSource message,
                                 optional NDEFWriteOptions options={});

};
dictionary NDEFWriteOptions {
  boolean overwrite = true;
  AbortSignal? signal;
};
  
  
  
  

dictionary NDEFReadOptions {
  AbortSignal signal;
};

B. Acknowledgments

The editors would like to thank Jeffrey Yasskin, Anne van Kesteren, Anssi Kostiainen, Domenic Denicola, Daniel Ehrenberg, Jonas Sicking, Don Coleman, Salvatore Iovene, Rijubrata Bhaumik, Wanming Lin, Han Leon, Ryan Sleevi, Balázs Engedy, Theodore Olsauskas-Warren, Reilly Grant, Diego González and Daniel Appelquist for their contributions to this document.

Special thanks to Luc Yriarte and Samuel Ortiz for their initial work on exposing NFC to the web platform, and for their support for the current approach. Also, special thanks to Elena Reshetova for the contributions to the Security and Privacy section.

C. References

C.1 Normative references

[BCP47]
Tags for Identifying Languages . A. Phillips; M. Davis. IETF. September 2009. IETF Best Current Practice. URL: https://tools.ietf.org/html/bcp47
[dom]
DOM Standard . Anne van Kesteren. WHATWG. Living Standard. URL: https://dom.spec.whatwg.org/
[ECMASCRIPT]
ECMAScript Language Specification . Ecma International. URL: https://tc39.es/ecma262/
[encoding]
Encoding Standard . Anne van Kesteren. WHATWG. Living Standard. URL: https://encoding.spec.whatwg.org/
[HTML]
HTML Standard . Anne van Kesteren; Domenic Denicola; Ian Hickson; Philip Jägenstedt; Simon Pieters. WHATWG. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[infra]
Infra Standard . Anne van Kesteren; Domenic Denicola. WHATWG. Living Standard. URL: https://infra.spec.whatwg.org/
[mimesniff]
MIME Sniffing Standard . Gordon P. Hemsley. WHATWG. Living Standard. URL: https://mimesniff.spec.whatwg.org/
[NDEF-SIGNATURE]
NFC Forum Signature Record Type Definition . NFC Forum. 18 November 2010. URL: http://members.nfc-forum.org/specs/spec_list/
[NFC-NDEF]
NFC Data Exchange Format (NDEF) Technical Specification . NFC Forum. 24 July 2006. URL: http://members.nfc-forum.org/specs/spec_list/
[NFC-RTD]
NFC Record Type Definition (RTD) Technical Specification . NFC Forum. 24 July 2006. URL: http://members.nfc-forum.org/specs/spec_list/
[NFC-STANDARDS]
NFC Forum Technical Specifications . NFC Forum. 24 July 2006. URL: http://members.nfc-forum.org/specs/spec_list/
[PAGE-VISIBILITY]
Page Visibility (Second Edition) . Jatinder Mann; Arvind Jain. W3C. 29 October 2013. W3C Recommendation. URL: https://www.w3.org/TR/page-visibility/
[PERMISSIONS]
Permissions . Mounir Lamouri; Marcos Caceres; Jeffrey Yasskin. W3C. 20 July 2020. W3C Working Draft. URL: https://www.w3.org/TR/permissions/
[RFC2046]
Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types . N. Freed; N. Borenstein. IETF. November 1996. Draft Standard. URL: https://tools.ietf.org/html/rfc2046
[RFC2048]
Multipurpose Internet Mail Extensions (MIME) Part Four: Registration Procedures . N. Freed; J. Klensin; J. Postel. IETF. November 1996. Best Current Practice. URL: https://tools.ietf.org/html/rfc2048
[RFC2119]
Key words for use in RFCs to Indicate Requirement Levels . S. Bradner. IETF. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[RFC5234]
Augmented BNF for Syntax Specifications: ABNF . D. Crocker, Ed.; P. Overell. IETF. January 2008. Internet Standard. URL: https://tools.ietf.org/html/rfc5234
[RFC5646]
Tags for Identifying Languages . A. Phillips, Ed.; M. Davis, Ed.. IETF. September 2009. Best Current Practice. URL: https://tools.ietf.org/html/rfc5646
[RFC8174]
Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words . B. Leiba. IETF. May 2017. Best Current Practice. URL: https://tools.ietf.org/html/rfc8174
[secure-contexts]
Secure Contexts . Mike West. W3C. 15 September 2016. W3C Candidate Recommendation. URL: https://www.w3.org/TR/secure-contexts/
[url]
URL Standard . Anne van Kesteren. WHATWG. Living Standard. URL: https://url.spec.whatwg.org/
[WebIDL]
Web IDL . Boris Zbarsky. W3C. 15 December 2016. W3C Editor's Draft. URL: https://heycam.github.io/webidl/

C.2 Informative references

[NDEF-SMARTPOSTER]
NFC Forum Smart Poster Record Type Definition . NFC Forum. 24 July 2006. URL: http://members.nfc-forum.org/specs/spec_list/
[NDEF-TEXT]
NFC Forum Text Record Type Definition . NFC Forum. 14 August 2013. URL: http://members.nfc-forum.org/specs/spec_list/
[NDEF-URI]
NFC Forum URI Record Type Definition . NFC Forum. 24 July 2006. URL: http://members.nfc-forum.org/specs/spec_list/
[NFC-HANDOVER]
NFC Forum Connection Handover Technical Specification . NFC Forum. 16 January 2014. URL: http://members.nfc-forum.org/specs/spec_list/
[NFC-SECURITY]
Web NFC Security and Privacy . W3C. 25 April 2015. URL: https://github.com/w3c/web-nfc/security-privacy.html
[RFC3986]
Uniform Resource Identifier (URI): Generic Syntax . T. Berners-Lee; R. Fielding; L. Masinter. IETF. January 2005. Internet Standard. URL: https://tools.ietf.org/html/rfc3986
[RFC3987]
Internationalized Resource Identifiers (IRIs) . M. Duerst; M. Suignard. IETF. January 2005. Proposed Standard. URL: https://tools.ietf.org/html/rfc3987
Permalink Referenced in: Not referenced in this document. Permalink Referenced in: 10.9.1 The write() method Permalink Referenced in: 10.8 The NDEFScanOptions dictionary 10.11.1 Match patterns Permalink Referenced in: 10.8 The NDEFScanOptions dictionary (2) Permalink Referenced in: 10.11.2 The scan() method Permalink Referenced in: 10.6 Releasing NFC 10.11.3 The NFC reading algorithm