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 (see https://www.nfc-forum.org/specs/spec_list/).

This document defines an API to enable selected use-cases based on NFC technology.

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.

Significant changes to this document since last publication are documented in the Changes section.

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

Implementations that use ECMAScript to implement the APIs defined in this document MUST implement them in a manner consistent with the ECMAScript Bindings defined in the Web IDL specification [[!WEBIDL]], as this document uses that specification and terminology.

Terminology and conventions

The terms URL, URL scheme, URL host, URL path, URL record and basic URL parser are defined in [[!URL]].

The following terms are defined in [[!HTML5]]: browsing context, top-level browsing context, global object, incumbent settings object, script execution environment, Document, document base URL, Window, WindowProxy, origin, ASCII serialized origin, executing algorithms in parallel, queue a task, task source, iframe, valid MIME type.

A browsing context refers to the environment in which Document objects are presented to the user. A given browsing context has a single WindowProxy object, but it can have many Document objects, with their associated Window objects. The script execution environment associated with the browsing context identifies the entity which invokes this API, which can be a web app, a web page, or an iframe.

The term secure context is defined in [[!WEBAPPSEC]].

Inspired by the Streams specification, we use the notation x@[[\y]] to refer to internal slots of an object, instead of saying "the [[\y]] internal slot of x".

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 Augmented Backus-Naur Form (ABNF) notation used is specified in [[RFC5234]].

DOMString, ArrayBuffer, BufferSource and any are defined in [[!WEBIDL]].

DOMException, AbortError, SyntaxError, NotSupportedError, NotFoundError, NetworkError, NoModificationAllowedError, SecurityError are defined in [[!DOM4]].

Promise, JSON, JSON.stringify and JSON.parse are defined in [[!ECMASCRIPT]].

The algorithms utf-8 encode, and utf-8 decode are defined in [[!ENCODING]].

IANA media types (formerly known as MIME types) are defined in RFC2046.

Security related terms

The term expressed permission refers to an act by the user, e.g. via user interface or setting or host device platform features, using which the user approves the permission of a browsing context to access the given functionality.

The term ask for forgiveness refers to some form of unobtrusive notification that informs the user of an operation while it is running. UAs SHOULD provide the user with means to ignore similar future operations from the same origin and advertise this to the user.

The term prearranged trust relationship means that the UA has already established a trust relationship for a certain operation using a platform specific mechanism, so that an expressed permission from the user is not any more needed. See also this section in the Security and Privacy document.

The term obtain permission for a certain operation indicates that the UA has either obtained expressed permission, or asks for forgiveness, or ensured a prearranged trust relationship exists.

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

NFC specific terms

NFC stands for Near Field Communications, 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 https://www.nfc-forum.org/specs/spec_list/ 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. The NFC tag is powered by magnetic induction when an active NFC device is in proximity range. An NFC tag contains a single NDEF message.

The way of reading the message may happen through proprietary technologies, which require the reader and the tag to be of the same manufacturer. Implementations are expected to encapsulate this.

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

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

An NDEF message encapsulates one or more application-defined NDEF records. NDEF is an abbreviation for NFC Forum Data Exchange Format, a lightweight binary message format. NDEF messages can be stored on an NFC tag or exchanged between NFC-enabled devices.

The term NFC content is a synonym for NDEF message, which can originate either from an NFC tag or an NFC peer.

An NDEF record is a part of an NDEF message that has a single associated type information to its payload. It contains a Type Name Format (TNF) field, the payload size, the payload type, an optional identifier which is a URL, and a payload of maximum size of 2^32-1 bytes. The NFC Forum has standardized a small set of useful data types for use in NDEF records, for instance text, URL, and binary data such as media. In addition, there are record types designed for more complex interactions, such as Smart Poster, and handover records.

The TNF (Type Name Format) field of the NDEF record can take binary values denoting the following NDEF record payload types:

TNF value NDEF record type
0 Empty
1 NFC Forum Well-Known Type
2 Media Type
3 Absolute URI
4 NFC Forum External Type
5 Unknown
6 Unchanged
7 Reserved

NFC Forum Well-Known Type includes record types text, URI, Smart Poster (containing an URL or other data, and possible actions).

An NFC watch is a mechanism used to watch for available Web NFC messages fulfilling certain criteria. It is defined in more detail in The watch() method section.

A Web NFC message consists of a set of NDEF records, one of which is a Web NFC record.

The Web NFC message origin is an ASCII serialized origin with "https" scheme, stored in the Web NFC record. For NFC content that is not a Web NFC message, it is null.

The Web NFC Id is a URL according to [[RFC3986]], specifically the Web NFC message origin optionally followed by a URL path, stored in the Web NFC Record. This enables matching Web NFC content with URL patterns specified by NFC watches.

A Web NFC record is an NDEF record of External Type, specific to Web NFC. It indicates that the containing NDEF message is targeted for browsing contexts using this API and contains information useful for handling the NDEF message with the algorithms defined in this specification. The format of a Web NFC record is as follows:

The term Web NFC content denotes all Web NFC messages contained within an NDEF message, identified by the Web NFC Id within the NDEF message. This version of the specification supports one Web NFC message per NDEF message.

As part of the NDEF record, an NDEF Id field may be present for application specific usages. According to the [[!NFC-STANDARDS]] it contains a URL with the maximum length of 256 octets. This URL is used for identifying the NDEF record payload in an application specific way. This version of the specification does not use NDEF Id for NDEF record level payload identification, since NDEF message level identification is used.

An NFC handover defines NFC Forum Well Known Types 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.

Introduction

In general, there are following groups of user scenarios for NFC:

NFC works using magnetic induction, meaning that the reader 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 many of these are only supported by single vendors and not part of the NFC standards. Though certain devices support reading and writing to these, it is not a goal of this document to support proprietary tags or support interoperability with legacy systems.

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

  1. NFC Forum Type 1: This tag 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 96 bytes and 2 Kbytes. Communication speed is 106 kbit/sec.
  2. NFC Forum Type 2: This tag is also 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/sec. In contrast to Type 1, Type 2 has anti-collision protection for dealing with multiple tags within the NFC field.
  3. NFC Forum Type 3: This tag is based on the Japanese Industrial Standard (JIS) X 6319-4, commonly known as FeliCa. The tags are preconfigured to be either rewritable or read-only. Memory availability is variable, theoretical memory limit is 1MByte per service. Communication speed is 106 kbit/sec. Like Type 2, it supports anti-collision protection.
  4. NFC Forum Type 4 (November 2010): This tag is based on the ISO/IEC 14443 like Type 1 and 2, but it supports either NFC-A or NFC-B for communication. On top of that the tag may support the Data Exchange Protocol (aka ISO-DEP) defined in ISO/IEC 14443 (ISO/IEC 14443-4:2008 Part 4: Transmission protocol). Like Type 3, the tags are preconfigured to be either rewritable or read-only. Variable memory, up to 32 KB per service. Supports three different communication speeds 106 or 212 or 424 Kbits/s.

In addition to data types standardized for NDEF records by the NFC Forum, many commercial products such as bus cards, door openers etc use different card specific data and protocol extensions which require specific NFC chips (same vendor of card and reader) in order to function.

Card emulation mode capabilities also depend on the NFC chip in the device. For payments, a Secure Element is often needed.

This document does not aim supporting all possible use cases of NFC technology, but only a few use cases which are considered relevant to be used by web pages in browsers, using the browser security model.

Examples

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

Use Cases

A few Web NFC user scenarios are described in the Use Cases document. These user scenarios can be grouped by criteria based on security, privacy and feature categories, resulting in generic flows as follows.

Reading an NFC tag

  1. Reading an NFC tag containing a Web NFC message, when a web page using the Web NFC API is open and in focus. For instance, a web page instructs the user to tap an NFC tag, and then receives information from the tag.
  2. Reading an NFC tag containing other than Web NFC message, when a web page using the Web NFC API is open and in focus.
  3. Reading an NFC tag when no web site using the Web NFC API is open or in focus. This use case is not supported in this version of the specification, and is has low priority for future versions as well.

Writing to an NFC tag

The user opens a web page which can write an NFC tag. The write operations may be one of the following:

  1. Writing to an empty NFC tag.
  2. Writing to an NFC tag which already contains a Web NFC message with a different Web NFC message origin (i.e. overwriting a web-specific tag).
  3. Writing to an NFC tag which already contains a Web NFC message with the same Web NFC message origin (i.e. updating own tag).
  4. Writing to other, writable NFC tags (i.e. overwriting a generic tag).

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

Pushing data to an NFC peer device

In general, pushing data to another Web NFC capable device requires that on the initiating device the user would first have to navigate to a web site. The user would then touch the device against another Web NFC equipped device, and data transfer would occur. On the receiving device the UA will dispatch the content to an application registered and eligible to handle the content, and if that application is a browser which has a web page open and in focus that uses the Web NFC API and has set up a NFC watch to listen to Web NFC content, then the content is delivered to the web page through the parameters of an MessageCallback.

Handover to another wireless connection type

NFC supports handover protocols to Bluetooth or WiFi connectivity for the purpose of larger volume data transfer. The user touches another NFC capable device, and as a result configuration data is sent for a new Bluetooth or WiFi connection, which is then established between the devices. This use case is not supported in this version of the specification.

Payment scenarios

Payment scenarios with Web NFC generally do not refer to supporting the payment process itself, but associating the payment status with a web page in order to have secondary actions. For instance, the user buys goods in a store, and payments options include contactless payment using NFC technology. In general, touching the device to the point of sales terminal receiver area will result in a transaction between the secure element from the device and the point of sales terminal. With the Web NFC API, if the user navigates to a web site before paying, there may be interaction with that site regarding the payment, e.g. the user could get points and discounts, or get delivered application or service specific data (e.g. tickets, keys, etc) to the device.

This use case is not supported in this version of the specification.

Support for multiple NFC adapters

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

Features

High level features for the Web NFC specification include the following:

  1. Support devices with single or multiple NFC adapters. If there are multiple adapters present when invoking an NFC function then the UA operates all NFC adapters in parallel.
  2. Support communication with active (powered devices such as readers, phones) and passive (smart cards, tags, etc) devices.
  3. Allow users to act on (e.g. read, write or transceive) discovered NFC devices (passive and active), as well as access the payload which were read in the process as Web NFC messages.
  4. Allow users to write a payload via NDEF records to compatible devices, such as writeable tags, when they come in range, as Web NFC messages.
  5. [future] Allow manual connection for various technologies such as NFC-A and NFC-F depending on the secondary device.
  6. [future] Allow NFC handover to Bluetooth or WiFi.
  7. [future] Allow card emulation with secure element or host card emulation.

This specification makes a few simplifications in what use cases and data types the Web NFC API can handle:

Security and Privacy

The trust model, attacker model, threat model and possible mitigation proposals for the Web NFC API are presented in the Security and Privacy document. This section presents the chosen security and privacy model through normative requirements to implementations.

Chain of trust

Web pages using the Web NFC API are not trusted. This means that the user needs to be aware of exactly what a web page is intending to do with NFC at any given moment. Implementations need to make sure that when the user authorizes a method of this API, then only that action is run, without side effects, and exactly in the context and the number of times the user allows the execution of NFC related operations, according to the algorithmic steps detailed in this specification.

The integrity of NFC content SHOULD NOT be trusted when used for implementing security policies, for instance the authenticity of origins saved in the Web NFC Id, unless a prearranged trust relationship exists.

Threats

The main threats are summarized in the Security and Privacy document.

In this specification the following threats are handled with the highest priority:

Permissions and user prompts

This specification attempts to minimize user prompting and uses implicit security policies to address the threats. However, this specification does not describe, nor does it mandate specific user prompting policies. The term obtain permission is used for acquiring trust for a given operation.

The Permissions API is suggested to be used by UAs for implementing NFC related [[permissions]] in order to minimize the need for user prompting.

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

Security policies

This section summarizes the security policies which are specified as normative requirements in the respective algorithms of this specification:

Data Representation

The NFCMessage dictionary

The content of any Web NFC message is exposed by the NFCMessage dictionary:

      dictionary NFCMessage {
        sequence<NFCRecord> records;
        USVString url;
      };
    

The NFCMessage.url property represents the Web NFC Id of a received Web NFC message. When used in the NFC.push() method, it represents a URL path used for constructing the Web NFC Id of the pushed Web NFC content.

The NFCMessage.records property represents the NDEF message defining the Web NFC message.

The NFCRecord dictionary

The content of any NDEF record is exposed by the NFCRecord dictionary:

      typedef (DOMString or unrestricted double or ArrayBuffer or Dictionary) NFCRecordData;

      dictionary NFCRecord {
        NFCRecordType recordType;
        USVString mediaType;
        NFCRecordData data;
      };
    

The NFCRecordData is a union type representing data types allowed for NFCRecord.data property.

The NFCRecord.mediaType property represents the IANA media type of the NDEF record payload.

The NFCRecord.data property represents the payload data of the NDEF record with an appropriate ECMAScript type, which depends on the IANA media type.

The NFCRecord.recordType property represents the NDEF record types. The mapping from data types of an NFCRecord to and from NDEF record types is presented in the algorithmic steps which handle the data and described in the Receiving and parsing content and Writing or pushing content sections.

The NFCRecordType enum

This enum defines the set of known types for a NFCRecord. The data mapping section describes how NFCRecordType is mapped to NDEF record types.

        enum NFCRecordType {
          "empty",
          "text",
          "url",
          "json",
          "opaque"
        };
      
empty
The enum value representing empty NFCRecord.
text
The enum value representing NFCRecord of a text type.
url
The enum value representing NFCRecord of a url type.
json
The enum value representing NFCRecord of a json type.
opaque
The enum value representing NFCRecord of a opaque type.

Data mapping

A JSON compatible IANA media type is defined by the following ABNF:

      "application/" ("json" / <VCHAR except '/' and "*"> "+json")
    

The mapping from data types of an NFCRecord to NDEF record types, as used in the Writing or pushing content section is as follows:

NFCRecord recordType NFCRecord mediaType NFCRecord data NDEF record type
"empty" not used not used NFC Forum Empty Type (TNF=0)
"text" not used DOMString NFC Forum Well Known Type (TNF=1) with type Text
"url" not used DOMString NFC Forum Well Known Type (TNF=1) with type URI
"json" JSON compatible IANA media type null or DOMString or Number or Dictionary Media Type as defined in [[RFC2046]] (TNF=2) with IANA media type specified in the type attribute.
"opaque" IANA media type ArrayBuffer Media Type as defined in [[RFC2046]] (TNF=2)
"" (empty) ArrayBuffer or typed array NFC Forum External Type (TNF=4)

The mapping from NDEF record types to NFCRecord, as used for incoming NDEF messages described in the Receiving and parsing content section, is as follows:

NDEF record type NFCRecord recordType NFCRecord mediaType NFCRecord data
NFC Forum Empty Type (TNF=0) "empty" "" null
NFC Forum Well Known Type (TNF=1) with type Text "text" "text/plain" DOMString
NFC Forum Well Known Type (TNF=1) with type URI "url" "text/plain" DOMString
NFC Forum Well Known Type (TNF=1) with type Smart Poster "url" "text/plain" DOMString
Absolute URI as defined in [[RFC3986]] (TNF=3) "url" "text/plain" DOMString
Media Type as defined in [[RFC2046]] (TNF=2) with JSON compatible IANA media type "json" The IANA media type used in the NDEF record null or DOMString or Number or Dictionary
Media Type as defined in [[RFC2046]] (TNF=2) "opaque" The IANA media type used in the NDEF record ArrayBuffer
NFC Forum External Type (TNF=4) with type other than urn:nfc:ext:w3.org:webnfc* "opaque" "application/octet-stream" ArrayBuffer
Any other NDEF record type "opaque" "application/octet-stream" ArrayBuffer

The Web NFC records MUST NOT be exposed to client browsing contexts.

Extensions to the Navigator interface

The HTML document defines a Navigator interface [HTML] which this specification extends.

    partial interface Navigator {
      readonly attribute NFC nfc;
    };
  

The nfc attribute

On getting the nfc attribute, the UA MUST return the NFC object, which provides NFC related functionality.

The NFC interface

The NFC object provides a way for the browsing context to use NFC functionality. It allows for pushing Web NFC messages to NFC tags or NFC peers within range, and to set up and cancel NFC watches to handle incoming Web NFC messages either from an NFC tag or an NFC peer.
    typedef (DOMString or ArrayBuffer or NFCMessage) NFCPushMessage;

    interface NFC {
      Promise<void> push(NFCPushMessage message, optional NFCPushOptions options);
      Promise<void> cancelPush(optional NFCPushTarget target="any");
      Promise<long> watch(MessageCallback callback, optional NFCWatchOptions options);
      Promise<void> cancelWatch(optional long id);
    };

    callback MessageCallback = void (NFCMessage message);
  

The NFCPushMessage is a union type representing argument types accepted by the push() method.

The MessageCallback is a callback function that must be provided to watch() metod.

In later versions cancelPush() and cancelWatch() may be obsoleted by cancelable Promises used with push() and watch(), respectively.

Internal slots of NFC

The NFC object is created with the internal slots described in the following table:

Internal Slot Description (non-normative)
[[\suspended]] A boolean flag indicating whether NFC functionality is suspended or not, initially false.
[[\watchList]] A list of NFC watches initially set to empty list.

Handling NFC adapters

Implementations MAY use multiple NFC adapters according to the algorithmic steps described in this specification. The NFC object represents all NFC hardware devices that can read and write NFC content.

Handling Window visibility and focus

Each Window object connected to the script execution environment has a separate NFC instance. The visibility and focus state of the Window object determines the suspended state of the associated NFC instance.

The term suspended in this specification refers to NFC operations being suspended, i.e. no NFC content is pushed, and no received NFC content is presented via watches while suspended. However, platform level timers for the NFC.push() method continue running, and if they expire, the event should be recorded and handled when execution next resumes, i.e. when the focus event is fired on the Window object.

When the Window object associated with the Document using the Web NFC API becomes visible and in focus, then run the following steps:

  1. Set NFC@[[\suspended]] to false.

When the Window object associated with the Document using the Web NFC API loses focus, then run the following steps:

  1. Set NFC@[[\suspended]] to true.

Releasing NFC

If a user agent is to make disappear an NFC object nfc, run the following NFC release steps, given nfc:

  1. Set nfc@[[\suspended]] to true.
  2. Run the nfc.cancelPush() steps with "tag" as parameter.
  3. Run the nfc.cancelPush() steps with "peer" as parameter.
  4. Stop the dispatch NFC content steps.
  5. Clear nfc@[[\watchList]].
  6. Release the NFC resources associated with nfc on the underlying platform.

The UA should run the NFC release steps, given nfc, as additional steps to the unloading document cleanup steps.

The NFCPushOptions dictionary

      dictionary NFCPushOptions {
        NFCPushTarget target = "any";
        unrestricted double timeout = Infinity;
        boolean ignoreRead = true;
      };
    

The NFCPushOptions.target property denotes the intended target for the pending push() operation.

The NFCPushOptions.timeout property denotes the timeout for the pending push() operation expressed in milliseconds. The default value is implementation-dependent. The value Infinity means there is no timeout, i.e. no timer is started. After the timeout expires, the message set for pushing is cleared, an error is returned, and a new Web NFC message can be set for pushing.

When the value of the NFCPushOptions.ignoreRead property is true, the push algorithm will skip invoking the receiving and parsing steps for an NFC tag.

The NFCPushTarget enum

This enum defines the set of intended target values for the push() operation.

      enum NFCPushTarget {
        "tag",
        "peer",
        "any"
      };
    
tag
The enum value representing the intended target for the push() operation to be a NFC tag.
peer
The enum value representing the intended target for the push() operation to be a NFC peer.
any
The enum value representing the intended target for the push() operation to be a NFC tag or a NFC peer.

The NFCWatchOptions dictionary

To describe which messages an application is interested in, the NFCWatchOptions dictionary is used:

        dictionary NFCWatchOptions {
          USVString url = "";
          NFCRecordType? recordType;
          USVString mediaType = "";
          NFCWatchMode mode = "web-nfc-only";
        };
      

The NFCWatchOptions.url property denotes the URL pattern which is used for matching the Web NFC Id of Web NFC messages which are being read. The default value "" means that no matching happens.

The NFCWatchOptions.recordType property denotes the string value which is used for matching the type property of each NFCRecord object in a Web NFC message. The default value "" means that no matching happens.

The NFCWatchOptions.mediaType property denotes the match pattern which is used for matching the type property of each NFCRecord object in a Web NFC message. The default value "" means that no matching happens.

The NFCWatchOptions.mode property denotes the NFCWatchMode value telling whether only Web NFC content or any NFC content will be watched.

        var watchOptions = {
          url: "https://www.w3.org/*",  // any path from the domain is accepted
          recordType: "json",
          mediaType: "application/*+json"  // any JSON-based IANA media type
        }
      
        var watchOptions = {
          url: "https://w3.org/info/restaurant/daily-menu/",
          recordType: "opaque",
          mediaType: "application/octet-stream"
        }
      

The NFCWatchMode enum

This enum defines the set of known values denoting whether watch() operation should dispatch NFC content for Web NFC content or any NFC content

      enum NFCWatchMode {
        "web-nfc-only",
        "any"
      };
    
web-nfc-only
The "web-nfc-only" value means that only those NDEF messages are dispatched which contain a Web NFC record, i.e. which are meant for web pages.
any
The "any" value means that all NDEF messages are dispatched.

Writing or pushing content

This section describes how to write an NDEF message to an NFC tag or how to push it to an NFC peer device when it is next time in proximity range before a timer expires. At any time there is at maximum of two Web NFC messages that can be set for pushing for an origin: one targeted to NFC tags and one to NFC peers, until the current message is sent, or a timeout happens, or the push is canceled by the cancelPush() method.

The push() method

The NFC.push(message, options) method, when invoked, MUST run the push a message algorithm:

  1. Return a new Promise promise, and then continue running this algorithm in parallel.
  2. If any exception occurs while running these steps, reject promise with that exception and abort these steps.
  3. If the incumbent settings object is not a secure context, reject promise with "SecurityError" and abort these steps.
    Browsers may ignore this rule for development purposes only.
  4. An implementation MAY reject promise with "NotSupportedError" and abort these steps.
    The UA might terminate message push at this point. The reasons for terminations are implementation details. For example, the user could have has set a preference to allow a given origin only to read, write, or push data to peers. Also, the implementation might be unable to support the operation requested.
  5. Let target be options.target.
  6. Let timeout be options.timeout.
  7. If the message parameter is not of type defined by the NFCPushMessage union, reject promise with "TypeError", and abort these steps.
  8. If the message parameter is of NFCMessage type, and message.records is an empty sequence, reject promise with "TypeError" and abort these steps.
  9. If timeout value is NaN or negative, reject promise with "TypeError" and abort these steps.
  10. If timeout value is not supported by the UA, reject promise with "NotSupportedError" and abort these steps.
  11. Let output be the notation for the NDEF message to be created by UA, as the result of passing message to create Web NFC message. If this throws an exception, reject promise with that exception and abort these steps.
  12. If target is "any", run the following steps twice, once with slot set to the value "tag", and once set to the value "peer"; otherwise run the following step once, with slot set to the value of target.
    • If there are any existing instance of this algorithm running whose target is equal to slot, abort that instance of this algorithm by rejecting its promise with "AbortError".

      In other words, the current invocation of push() rejects and replaces existing running invocations handling the same slot. At any given moment there may be maximum two instances of this algorithm running: one targeting NFC tags, and another targeting NFC peers.

      Implementations are expected to clean up state on aborting these steps, e.g. stop the related timer, clear the related push message, as well as release any resources bound to NFC functionality, so that new invocations of this algorithm do not depend on previous invocations.

    • Associate output with slot.
  13. If timeout value is not equal to Infinity, start a timer timer with the timeout value set to timeout.
  14. Wait until one of the following events happens:
    • If timer expires, reject promise with "TimeoutError" and abort these steps.
    • If the cancelPush() method is called while timer is active with target or "any", then reject promise with "AbortError" and abort these steps, as described in the cancelPush() steps.
    • If an NFC device device comes within communication range, verify the following conditions:
      • if device is an NFC tag, target is "tag" or "any"
      • if device is an NFC peer, target is "peer" or "any"
      • this@[[\suspended]] is false.
      In case of success, run the following sub-steps:
      1. Stop timer if active.
      2. If device is an NFC tag,
      3. Initiate data transfer to device using output as buffer, using the NFC adapter in communication range with (connected to) device.
      4. If the transfer fails, reject promise with "NetworkError" and abort these steps.

        Multiple adapters should be used sequentially by users. There is very small likelihood that a simultaneous tap will happen on two or multiple different and connected NFC adapters. 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 adapters.

      5. When the transfer has completed, clear output associated with target, resolve promise.
    • If this@[[\suspended]] is true, continue waiting until timer expires (if set), or until cancelPush() is called, or until an NFC device comes within communication range.

Obtaining push permission

To obtain push permission, run these steps:

  1. If there is a prearranged trust relationship, return true.
  2. Run the query permission status steps for the Web NFC permission name until completion.
  3. Return false.

Creating Web NFC message

To create Web NFC message given a message run these steps:

  1. Let output be the notation for the NDEF message to be created by the UA as a result of these steps.
  2. For each NFCRecord record in the sequence message.records, run the following steps, or make sure that the underlying platform provides equivalent values to ndef:
    1. If record.recordType is undefined, then:
      1. If the type of record.data is an ArrayBuffer, then set record.recordType to "opaque".
      2. Otherwise, if the type of record.data is an Object, then set record.recordType to "json".
      3. Otherwise, if the type of record.data is UnrestrictedDouble or String, then set record.recordType to "text".
      4. Otherwise reject promise with "TypeError" and abort these steps.
    2. If record.recordType is "empty", then Let ndef be the result of passing record to map empty record to NDEF. If this throws an exception, reject promise with that exception and abort these steps.
    3. Otherwise, if record.recordType is "text", then let ndef be the result of passing record to map text to NDEF. If this throws an exception, reject promise with that exception and abort these steps.
    4. Otherwise, if record.recordType is "url", then let ndef the be result of passing record to map a URL to NDEF. If this throws an exception, reject promise with that exception and abort these steps.
    5. Otherwise, if record.recordType is "json", then let ndef the be result of passing record to map a JSON object to NDEF. If this throws an exception, reject promise with that exception and abort these steps.
    6. Otherwise, if record.recordType is "opaque", then let ndef the be result of passing record to map binary data to NDEF. If this throws an exception, reject promise with that exception and abort these steps.
    7. Add ndef to output.
  3. Let webnfc be the result of invoking create a Web NFC record given message.url. If this throws an exception, reject promise with that exception and abort these steps.
  4. Add webnfc to output.

    Implementations may choose the location of the Web NFC record within the NDEF message.

Mapping empty record to NDEF

To map empty record to NDEF given a record, run these steps:

  1. Let ndef be the notation for the NDEF record to be created by the UA.
  2. Set the ndef.TNF field to 0 (NFC Empty Type record).
  3. Set ndef.TYPE_LENGTH, ndef.ID_LENGTH and ndef.PAYLOAD_LENGTH fields to 0, and omit the associated fields from the NDEF record: ndef.TYPE, ndef.ID, ndef.PAYLOAD.
  4. Return ndef.

Mapping string to NDEF

To map text to NDEF given a record, run these steps:

This is useful when clients specifically want to write an NDEF Well Known Type Text record. Other options would be to use the value "opaque" with an explicit IANA media type text type, which allows for better differentiation, e.g. when using "text/xml", or "text/vcard".

  1. If the type of a record.data is not a String or a UnrestrictedDouble, throw a "TypeError" exception and abort these steps.
  2. If record.mediaType is an empty string, then set record.mediaType to "text/plain".
  3. Otherwise, if record.mediaType is not an empty string that doesn't start with "text/", then throw a "SyntaxError" exception and abort these steps. In addition, UAs MAY check that record.mediaType is an IANA registered media type for text. If not, then the UA MAY throw a "SyntaxError" exception and abort these steps.
  4. Let language be "en". If record.mediaType includes a lang= parameter, detailing the language encoding (e.g. "text/plain; lang=fr"), then set language to the language code extracted from record.mediaType. If language is not one of the language codes listed in the IANA language registry (or [[ISO-639.2]]), then UAs MAY throw a "SyntaxError" exception and abort these steps.

    Note that lang= is not standard parameter to IANA media types, but it is used in this specification in order to maintain compatibility with [[!NFC-STANDARDS]].

  5. Let ndef be the notation for the NDEF record to be created by the UA.
  6. Set the ndef.TNF field to 1 (NFC Well Known Type).
  7. Set the def.TYPE field to "T" (value 0x54 following NFC binary encoding).
  8. Set the ndef.PAYLOAD field to record.data encoded according to the [[NFC-STANDARDS]], NFC Forum Text Record Type Definition specification:
    1. The first octet is a status byte containing bit flags.
      1. If record.mediaType contains the parameter "charset=UTF-8" (e.g. "text/plain; charset=UTF-8;"), then set bit 7 (MSB) to 0 (UTF-8 encoding), otherwise to 1 (UTF-16 encoding).
      2. Set bit 6 to 0.
      3. Set bits 5 to 0 to the length of the language string.
    2. Set the consecutive octets of ndef.PAYLOAD to the value of language encoded as US-ASCII.
    3. Set the consecutive payload octets to record.data in the encoding set by the MSB bit of the first payload octet (by default UTF-16, or UTF-8 on special request).
  9. Return ndef.

Mapping URL to NDEF

To map a URL to NDEF given a record, run these steps:

  1. If the type of a record.data is not a String, throw a "TypeError" exception and abort these steps.
  2. If the record.data is not a valid URL, throw a "SyntaxError" exception and abort these steps.
  3. Let ndef be the notation for the NDEF record to be created by the UA.
  4. Set the ndef.TNF field to 1 (Well Known Type).
  5. Set the ndef.TYPE field to "U" (0x55 following NFC binary encoding).
  6. Set the ndef.PAYLOAD field to record.data encoded according to the [[NFC-STANDARDS]], NFC Forum URI Record Type Definition specification: set the first octet according to the applicable scheme abbreviation, and set the rest of the payload bytes to record.data in UTF-8 encoding.
  7. Return ndef.

Mapping JSON to NDEF

To map a JSON object to NDEF given a record, run these steps:

  1. If the type of a record.data is not an Object, throw a "TypeError" exception and abort these steps.
  2. If record.mediaType is an empty string, then set record.mediaType to "application/json".
  3. Otherwise, if record.mediaType is not an empty string that doesn't match "application/json", or any other IANA media type for JSON (starting with "application/" and ending with "+json"), throw a "SyntaxError" exception and abort these steps.
  4. Let data be the result of serializing record.data and if that throws, throw a "SyntaxError" exception and abort these steps.
  5. Let ndef be the notation for the NDEF record to be created by the UA.
  6. Set the ndef.TNF field to 2 (Media Type).
  7. Set the ndef.TYPE field to record.mediaType.
  8. Set the ndef.PAYLOAD field to data according to the [[NFC-STANDARDS]], i.e. as an opaque octet stream.
  9. Return ndef.

Mapping binary data to NDEF

To map binary data to NDEF given a record, run these steps:

  1. If the type of a record.data is not an ArrayBuffer, throw a "TypeError" exception and abort these steps.
  2. If record.mediaType is an empty string, set record.mediaType to "application/octet-stream".
  3. Otherwise, if record.mediaType is not an empty string, the UA MAY check if record.mediaType is a valid IANA registered type. If not, then the UA MAY throw a "SyntaxError" exception and abort these steps.
  4. Let ndef be the notation for the NDEF record to be created by the UA.
  5. Set the ndef.TNF field to 2 (Media Type).
  6. Set the ndef.TYPE field to record.mediaType.
  7. Set the ndef.PAYLOAD field to record.data according to the [[NFC-STANDARDS]], i.e. as an opaque octet stream.
  8. Return ndef.

Creating a Web NFC record

To create a Web NFC record given url, run these steps:

  1. Let ndef be the notation for the NDEF record to be created by the UA.
  2. Set ndef.TNF to 4 (NDEF External Type).
  3. Set ndef.TYPE to "urn:nfc:ext:w3.org:webnfc".
  4. Let payload be the result of invoking create a Web NFC Id given url. If this throws an exception, re-throw it.
  5. Set ndef.PAYLOAD to the URL path of the browsing context, encoded as UTF-16. This is going to be used by NFC watch filters.

    In future versions a list of "allowed-origins" may be supported. It is still up for discussions due to security issues. See the Security and Privacy document.

  6. Return ndef.

Creating a Web NFC Id

To create a Web NFC Id given url, run these steps:

  1. Let id be the ASCII serialized origin of the browsing context, appended with url.
  2. If id is a not a valid URL, throw a "SyntaxError" exception and abort these steps.

    This means url should be a valid URL path.

  3. Return id, encoded in UTF-16.

The cancelPush() method

The NFC.cancelPush(target) method, when invoked, MUST run cancel push algorithm:

  1. Return a new Promise promise and then continue running this algorithm in parallel.
  2. If the incumbent settings object is not a secure context, reject promise with "SecurityError" and abort these steps.
    Browsers may ignore this rule for development purposes only.
  3. If there is an instance of the NFC.push() algorithm running with its options.target equal to target or "any", then
    1. Stop the instance's timer if it is active.
    2. If the instance has already initiated NFC data transfer, reject promise with "NoModificationAllowedError" and abort these steps.
    3. Reject the instance's pending promise with "AbortError" and abort the steps of the instance.
  4. Resolve promise.

The cancelPush() method does not interrupt ongoing transfers, it only cancels pushing before an NFC device comes in range.

Watching for content

In order to receive NFC content, the client needs to call the NFC.watch() to opt into content of interest.

Match patterns

A match pattern is defined by the following ABNF:

          match-pattern       = top-level type name "/" [ tree "." ] subtype name [ "+" suffix ] [ ";" parameters ]
          top-level type name = "*" / <VCHAR except '/' and "*">
          subtype name        = "*" / <VCHAR except '+'>
        
A match pattern is a glob used for matching IANA media types, 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.

URL patterns

A URL pattern is a URL record that can be used to match the Web NFC Id of a Web NFC message. A valid URL pattern is a valid URL record whose scheme component is equal to "https".

A URL pattern's scheme, host and path components that are used by the URL pattern match algorithm have the following matching rules:

URL pattern component Matching rule for Web NFC Id
scheme exact match
host exact match or ends with (URL pattern's host String prepended with ".") String
path If URL pattern's path is "/*", match any Web NFC Id path. Otherwise, begins with URL pattern's path String

For example, 'https://mydomain.com/*' will match 'https://service.mydomain.com/myapp/' and 'https://info.mydomain.com/general/', while 'https://app.mydomain.com/contacts' will match 'https://app.mydomain.com/contacts' and 'https://app.mydomain.com/contacts/all' The '*' is a valid character for the URL path component, therefore, 'https://www.mydomain.com/*' pattern will match both 'https://www.mydomain.com/*' and 'https://www.mydomain.com/service' URLs.

URL pattern match algorithm

To match Web NFC Id with URL pattern for a given Web NFC Id and URL pattern, run these steps:
  1. Let id be a Web NFC Id passed to this algorithm.
  2. Let pattern be a URL pattern passed to this algorithm.
  3. If id and pattern are empty Strings, return true and abort these steps.
  4. Let id_url be the result of invoking the basic URL parser algorithm with id as an input. If the basic URL parser algorithm returns failure, return false and abort these steps.
  5. Let pattern_url be the result of invoking the basic URL parser algorithm with pattern as an input. If the basic URL parser algorithm returns failure, return false and abort these steps.
  6. If id_url's scheme String does not match pattern_url's scheme String, return false and abort these steps.
  7. Let subdomain_pattern be the result of prepending "." String to pattern_url's host String.
  8. If id_url's host String does not end with subdomain_pattern String and id_url's host String is not equal to pattern_url's host String, return false and abort these steps.
  9. If pattern_url's path String equal to "/*", return true and abort these steps.
  10. If id_url's path String begins with pattern_url's path String, return true and abort these steps.
  11. Otherwise, return false.

The watch() method

This method enables listening to incoming NDEF messages. The NFC content to which clients listen can be filtered based on its data type, and based on the URL path of the browsing context which has been saved to the Web NFC record of the NFC content. The latter is matched against URL patterns used in NFC watches.

An NFC watch is referring to a NFCWatchOptions filter saved together with the NFC instance it belongs to, and a locally unique identifier which is used for cancellation. The section Receiving and parsing content uses NFC watches to match incoming NFC content.

Multiple consecutive calls to the watch() method from the same origin create filters which are in OR relationship.

When the NFC.watch(callback, options) method is invoked, the UA MUST run the following NFC watch algorithm:

  1. Let promise be a new Promise object.
  2. Return promise and continue the following steps in parallel.
  3. If any exception occurs while running these steps, reject promise with that exception and abort these steps.
  4. If the incumbent settings object is not a secure context, reject promise with "SecurityError" and abort these steps.
    Browsers may ignore this rule for development purposes only.
  5. If there is no support for the functionality of receiving data from an NFC peer or NFC tag in proximity range, reject promise with "NotSupportedError" and abort these steps.
  6. If the obtain watch permission steps return false, then reject promise with "SecurityError" and abort these steps.
  7. If this is the first watch being set up, then make a request to all NFC adapters to listen to NDEF messages.
  8. If the request fails, reject promise with "NotSupportedError" and abort these steps.
  9. If the options.url is not an empty String and it is not a valid URL pattern, throw "SyntaxError" exception and abort these steps.
  10. Let watchId be a number that will identify this NFC watch.
  11. Add watchId, options, and callback together as an NFC watch to this@[[\watchList]].
  12. Resolve promise with watchId.
  13. If the browsing context loses focus (e.g. the user navigated to another page), then the registered watches still SHOULD continue to exist, but SHOULD become paused, i.e. the UA SHOULD NOT check and use them until the focus is regained.

To obtain watch permission, run these steps:

  1. If there is a prearranged trust relationship, return true.
  2. Otherwise, if the user has earlier denied permission for the calling origin for all future calls of watch() as well, then return false.
  3. Otherwise, UAs SHOULD ask for forgiveness with relevant information displayed to the user.

    The ask for forgiveness interaction might show choices like "block now" or "block forever", etc. If the user has chosen to "block forever" the given origin, it is the responsibility of the UA to remember these user choices for each origin, regardless of which NFC adapter is used, and consult them on later invocations.

    In this step UAs are advised to notify users about that reading NFC content may indirectly reveal the physical location of the user. In addition, if "any" NFCWatchMode is used, then also include in this information that the origin is requesting to read not only NFC content meant for web pages, but any NFC content.

  4. Return true.

The cancelWatch() method

When the NFC.cancelWatch(id) method is invoked, the UA MUST return a Promise promise and run the following steps in parallel.

  1. If the incumbent settings object is not a secure context, reject promise with "SecurityError" and abort these steps.
    Browsers may ignore this rule for development purposes only.
  2. If the parameter id is undefined, then remove all watches and filters set by successive calls of the NFC watch() method on all NFC adapters.
  3. Otherwise, if the parameter id matches the local identifier of one of the previously set up watches, remove the corresponding watch.
  4. Otherwise, reject promise with "NotFoundError" and abort these steps.
  5. If there are no more watches, then make a request to stop listening to NDEF messages on all NFC adapters.
  6. Resolve promise.

Receiving and parsing content

If there are any NFC watches set up in NFC@[[\watchList]], then UAs MUST listen to NDEF messages, according to step 7 of the NFC watch algorithm.

The NDEF parsing algorithm

When the UA is to receive an NDEF message it MUST run the following algorithm:

The UA SHOULD represent an unformatted NFC tag as an NDEF message containing a single empty NDEF record.

  1. If NFC@[[\suspended]] is true, abort these steps.
  2. Let message be a new NFCMessage object, with message.url set to null and message.records set to empty sequence.
  3. Let input be the notation for the NDEF message which has been received.
  4. For each NDEF record which is part of input, run the following sub-steps for parsing NDEF record:
    1. Let ndef be the notation for the current NDEF record. The fields of ndef are described by the [[NFC-STANDARDS]].
    2. Let record be a new NFCRecord object.
    3. If ndef.TNF is 0 (NFC Empty Record), then set record.recordType to "empty" and set record.mediaType to "".
    4. If ndef.TNF is 1 (NFC Well Known Type Record), and ndef.TYPE is "T" (value 0x54 following NFC binary encoding), then run the following sub-steps for parsing NDEF Text record, or ensure that the underlying platform provides equivalent values to the record object properties:
      1. Set record.recordType to "text".
      2. Set record.mediaType to "text/plain".
      3. Read the first octet of ndef.PAYLOAD. Let offset be the value given by bits 5 to 0 of the first payload octet.
      4. Let language be the string defined by the consecutive offset number of octets, converted from US-ASCII encoding. Append ";lang=" and then the value of language to record.mediaType.
      5. Set record.data to the string created from the consecutive ndef.PAYLOAD octets, converted to UTF-16 encoding.
    5. If ndef.TNF is 1 (NFC Well Known Type Record), and ndef.TYPE is "U" (value 0x55 in NFC binary encoding), then run the following sub-steps for parsing NDEF URL record, or make sure that the underlying platform provides equivalent values to the record object properties:
      1. Set record.recordType to "url".
      2. Set record.mediaType to "text/plain".
      3. Let scheme be the value of the first octet of ndef.PAYLOAD.
      4. If scheme is not 0, then set record.data to the string obtained from mapping the value of scheme to the URL scheme as specified in the [[NFC-STANDARDS]] URI Record Type Definition specification, Section 3.2.2.
      5. Set record.data to the UTF-16 string converted from the octets of ndef.PAYLOAD except the first octet.
    6. If ndef.TNF is 3 (NFC Absolute URI Type record), then set record.recordType to "url", set record.mediaType to "text/plain" and set record.data to the string converted from ndef.PAYLOAD.
    7. If ndef.TNF is 2 (NFC Media Type record), then run the following sub-steps for parsing NDEF Media record, or make sure that the underlying platform provides equivalent values to the record object properties:
      1. If ndef.TYPE matches the match pattern "application/*json", then
        1. Set record.recordType to "json".
        2. Set record.mediaType to ndef.TYPE.
        3. Let payload be ndef.PAYLOAD converted to UTF-16, and set record.data to the result of parsing payload. If parsing throws an error, skip to the next NDEF record.
      2. Otherwise,
        1. Set record.recordType to "opaque".
        2. Set record.mediaType to ndef.TYPE.
        3. Set record.data to a new ArrayBuffer object constructed from the octets of ndef.PAYLOAD.
    8. If ndef.TNF is 4 (NFC External Type record), and ndef.TYPE is urn:nfc:ext:w3.org:webnfc, then set message.url to the value decoded from ndef.PAYLOAD in UTF-16.
    9. Otherwise, if ndef.TNF is 4 (NFC External Type record), or 5 (NFC Unknown Type record) then run the following sub-steps, or make sure that the underlying platform provides equivalent values to the record object properties:
      1. Set record.recordType to "opaque".
      2. If ndef.TYPE is defined, then set record.mediaType to that string value, otherwise to "application/octet-stream".
      3. Set record.data to a new ArrayBuffer object constructed from the octets of ndef.PAYLOAD.
    10. Otherwise, skip to the next NDEF record in input.
    11. Add record to message.records.
  5. If NFC@[[\suspended]] is false and message.records is not empty, run the dispatch NFC content steps given message.

Dispatching NFC content

To dispatch NFC content given a message of type NFCMessage run these steps:

  1. For each NFC watch watch that has been registered using the watch() method in this@[[\watchList]], run the following sub-steps:
    1. Let options be the NFCWatchOptions saved with watch, and let callback be the registered callback function.
    2. If options.mode is "web-nfc-only" and message.url is null, skip to the next NFC watch.
    3. Otherwise, if options.mode is "any", set options.url to "".
    4. If the URL pattern options.url is not an empty String invoke URL pattern match algorithm, providing options.url as a URL pattern and message.url as a Web NFC Id. If URL pattern match algorithm returns false, skip to the next NFC watch.
    5. If options.recordType is not "" and it is not equal to any record.recordType where record is an element of message, skip to the next NFC watch.
    6. If options.mediaType is not "" and it is not equal to any record.mediaType where record is an element of message, skip to the next NFC watch.
    7. Queue a task using the Web NFC task source to invoke the MessageCallback callback with message as its argument.

Changes

The following is a list of substantial changes to the document. For a complete list of changes, see the change log on Github. You can also view the recently closed bugs.

Open issues

The following problems are being discussed and need most attention:

This version addresses the issues above, and also other issues.

Acknowledgements

The editors would like to thank Jeffrey Yasskin, Anne van Kesteren, Anssi Kostiainen, Domenic Denicola, Jonas Sicking, Don Coleman, Salvatore Iovene and Rijubrata Bhaumik for their contributions to this document. Special thanks goes to the former editors Luc Yriarte and Samuel Ortiz for their initial work on exposing NFC to the Web Platform, and for their supports for our new approach.