Copyright © 2019 the Contributors to the Web NFC Specification, published by the Web NFC Community Group under the W3C Community Contributor License Agreement (CLA) . A human-readable summary is available.
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 the specification is NDEF . Other NFC technologies may be supported in the future.
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.
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 , 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.
This section is non-normative.
NFC user scenarios can be grouped as follows:
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).
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. 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 .
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 or an NFC peer . In the current API it is synonym to NDEF message .
This section is non-normative.
NFC is standardized in the NFC Forum and described in [ NFC-STANDARDS ].
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
96
bytes
and
2
Kbytes.
Communication
speed
is
106
kbit/sec.
In
contrast
to
all
other
types,
these
tags
have
no
anti-collision
protection
for
dealing
with
multiple
tags
within
the
NFC
field.
48
bytes
and
2
Kbytes.
Communication
speed
is
106
kbit/sec.
2
kbytes.
Communication
speed
is
212
kbit/sec
or
424
kbit/s.
32
kbytes.
Supports
three
different
communication
speeds
106
or
212
or
424
kbit/s.
64
kbytes.
Communication
speed
26.48
kbit/s
320
and
4
kbytes.
Communication
speed
is
106
kbit/sec.
MIFARE Standard is a 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.
Card emulation mode capabilities also depend on the NFC chip in the device. For payments, a Secure Element is often needed.
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 , which may both 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.
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 .
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.
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.
The NFC Forum has standardized a small set of useful sub record types in [ NFC-RTD ] (Resource Type Definition specifications) called well-known type s, for instance text, URL, media and opaque binary data. 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.
These sub record types can be stored in the well-known type record .
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.
NFC Forum local type that are defined by the NFC Forum or by an application, and always start with lowercase letter or a number. Those are usually short strings that are unique only within the local context of the containing record. They are used when types meaning 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.
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.
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:
0
.
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.
Smart poster is defined in [ NDEF-SMARTPOSTER ] as an NDEF record that contains an NDEF message as payload, which may contain several records: a mandatory URI record that refers to a content, and additional optional records related to the content: a title record (a Text record ), one or more icon records, a type record, a size record and an action record.
Icon records are MIME type record s. If multiple icon records are included, readers SHOULD select only one of them to display.
The
type
record
has
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.
The
size
record
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.
The
action
record
has
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 |
The action record is optional and there is no default action on the smart poster content if the action record is missing.
At
the
time
of
NDEF
standardization
the
value
0
("do
the
action")
was
meant
for
use
cases
like
send
an
SMS,
make
a
call
or
launch
browser.
Similarly,
the
value
1
,
("save
the
content
for
later
processing")
was
meant
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.
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.
In
this
version
of
the
API,
Web
NFC
only
provides
the
raw
byte
content
of
the
payload
(see
this
issue
).
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. Web NFC does not support this at the moment (see this issue .
The
MIME
type
record
s
are
records
that
store
binary
data
with
associated
MIME
type
.
In absolute-URL record s the TYPE field contains the absolute-URL string , and not the payload.
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.
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
colon,
then
a
non-zero
type
name,
for
instance
"urn:nfc:ext:w3.org:atype"
,
stored
as
"w3.org:atype"
in
the
TYPE
field
.
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.
0
and
their
TNF
field
MUST
be
6
(unchanged).
First
record:
Intermediate
record:
Last
record:
Any implementation of Web NFC MUST transparently expose chunked records as single logical records.
This section is non-normative.
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.
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.
Document
of
the
top-level
browsing
context
using
Web
NFC
is
visible
.
Document
using
Web
NFC
is
visible
.
This use case is not supported in this version of the specification.
The user opens a web page which can write an NFC tag . The write operations may be one of the following:
Note that an NFC write operation to an NFC tag always involves also a read operation.
In general, pushing data to another 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
Document
of
the
top-level
browsing
context
visible
with
active
,
then
the
content
is
delivered
to
the
page
through
the
NDEFReader
NDEFReadingEvent
.
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 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 payment 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 Web NFC, 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.
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 .
This section is non-normative.
High level features for the Web NFC specification include the following:
This specification makes a few simplifications in what use cases and data types Web NFC can handle:
This section is non-normative.
This section shows how developers can make use of the various features of this specification.
Pushing a text string to any kind of device is straightforward. Options can be left out, as they default to pushing to both tags and peers.
const writer = new NDEFWriter();
writer.push(
"Hello World"
).then(() => {
console.log("Message pushed.");
}).catch(error => {
console.log(`Push failed :-( try again: ${error}.`);
});
It is possible to restrict to which devices (tags or peers) data should be pushed. Below push is specified only to peers, and thus, no data is pushed when the user taps a tag.
const writer = new NDEFWriter();
writer.push(
"Text meant for peers only", { target: "peer" }
).then(() => {
console.log("Message pushed.");
}).catch(_ => {
console.log("Push failed :-( try again.");
});
In order to push an NDEF record of URL type, simply use NDEFMessage.
const writer = new NDEFWriter();
writer.push({
records: [{ recordType: "url", data: "https://w3c.github.io/web-nfc/" }]
}).then(() => {
console.log("Message pushed.");
}).catch(_ => {
console.log("Push failed :-( try again.");
});
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".
const reader = new NDEFReader();
await reader.scan();
reader.onreading = event => {
const message = event.message;
if (message.records.length == 0 || // unformatted tag
message.records[0].recordType == 'empty' ) { // empty record
const writer = new NDEFWriter();
writer.push({
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;
}
}
};
Filtering
of
relevant
data
sources
can
be
done
by
the
use
of
the
NDEFScanOptions
.
Below
we
accept
the
record
identifier
URL
with
"
/mypath/mygame/
"
in
its
path
from
"
mygame.com
"
domain
and
its
subdomains.
When
we
read
the
data,
we
immediately
update
the
game
progress
by
issuing
a
push
with
a
custom
NDEF
data
layout.
The example allows reading and pushing to both peers and tags, whichever one is tapped first.
const reader = new NDEFReader();
await reader.scan({ id: "https://mygame.com/mypath/mygame" });
reader.onreading = async event => {
console.log(`Game state: ${ JSON.stringify(event.message.records) }`);
const encoder = new TextEncoder();
const newMessage = {
records: [{
id: "/mypath/mygame/update",
recordType: "mime",
mediaType: "application/json",
data: encoder.encode(JSON.stringify({
level: 3,
points: 4500,
lives: 3
}))
}]
};
const writer = new NDEFWriter();
await writer.push(newMessage);
console.log("Pushed message");
};
Storing and receiving JSON data is easy with serialization and deserialization.
const reader = new NDEFReader();
await reader.scan({
mediaType: "application/*json"
});
reader.onreading = event => {
const decoder = new TextDecoder();
for (const record of event.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}`);
}
}
};
const writer = new NDEFWriter();
const encoder = new TextEncoder();
writer.push({
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"
}))
}]
});
Pushing
data
to
a
tag
requires
tapping
it.
If
existing
data
should
be
read
during
the
same
tap,
we
need
to
set
the
ignoreRead
property
to
false
.
const reader = new NDEFReader();
reader.scan().then(() => {
reader.onreading = event => {
const decoder = new TextDecoder();
for (const record of event.message.records) {
console.log("Record type: " + record.recordType);
console.log("MIME type: " + record.mediaType);
console.log("=== data ===\n" + decoder.decode(record.data));
}
};
const writer = new NDEFWriter();
return writer.push("Pushing data is fun!", { target: "tag", ignoreRead: false });
}).catch(error => {
console.log(`Push failed :-( try again: ${error}.`);
});
Read
NDEF
messages
for
3
seconds
by
using
signal
.
const reader = new NDEFReader();
const controller = new AbortController();
await reader.scan({ signal: controller.signal });
reader.onreading = event => {
console.log("NDEF message read.");
};
controller.signal.onabort = event => {
console.log("We're done waiting for NDEF messages.");
};
// Stop listening to NDEF messages after 3s.
setTimeout(
()
=>
controller.abort(),
3000
);
const writer = new NDEFWriter();
writer.push({ records: [
{
recordType: "smart-poster",
data: { records: [
{
recordType: "url",
data: "https://my.org/content/19911"
},
{
recordType: "t", // smart poster type, a local type to Sp
data: "image/gif"
},
{
recordType: "text",
data: "Funny dance"
},
{
recordType: "s", // size, a local type to Sp
data: 4096 // byte size of the content at the URL above
},
{
recordType: "act", // action, a local type to Sp
data: 0 // do the action, in this case open in the browser
}
]}
}
]});
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.
const reader = new NDEFReader();
await reader.scan({ recordType: "example.com:sp" });
reader.onreading = event => {
const socialPost = event.message.records[0];
if (!socialPost) {
return;
}
let action;
let text = "";
const decoder = new TextDecoder();
for (let record of socialPost.toRecords()) {
switch (record.recordType) {
case "text":
text = decoder.decode(record.data);
break;
case "act":
action = record.data.getUint8(0);
break;
}
}
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;
}
};
External type records can be used to create application defined records that may even contain an NDEF message as payload.
const writer = new NDEFWriter();
writer.push({ records: [
{
recordType: "example.game:a",
data: {
records: [
{
recordType: "url",
data: "https://example.game/42"
},
{
recordType: "text",
data: "Game context given here"
},
{
recordType: "mime",
mediaType: "image/png"
data: getImageBytes(fromURL);
}
]
}
}
]});
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();
const writer = new NDEFWriter();
writer.push({ 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.")
}
]
}
}
]});
const reader = new NDEFReader();
await reader.scan({ recordType: "example.com:shoppingItem" });
reader.onreading = event => {
const shoppingItemRecord = event.message.records[0];
if (!shoppingItemRecord) {
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));
};
The trust model, attacker model, threat model and possible mitigation proposals for Web NFC are presented in the Security and Privacy document. This section presents the chosen security and privacy model through normative requirements to implementations.
Web pages using Web NFC 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 record identifier , unless a prearranged trust relationship exists.
Security considerations for media types in general are discussed in [ RFC2048 ] and [ RFC2046 ].
The main threats are summarized in the Security and Privacy document.
In this specification the following threats are handled with the highest priority:
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 permission s that are preserved beyond the current browsing session MUST be revocable.
This section is non-normative.
This section summarizes the security policies which are specified as normative requirements in the respective algorithms of this specification.
Only secure contexts are allowed to access NFC content . Browsers may ignore this rule for development purposes only.
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 pushing NFC content must be suspended .
Making an NFC tag read-only must obtain permission , or otherwise fail.
Setting up listeners for reading NFC content should obtain permission .
The process of reading an NDEF message does not need to obtain permission .
Pushing NFC content to an NFC peer does not need to obtain permission , but the other rules in this section apply. See the § 10.9 Writing or pushing content section.
Pushing an NDEF message to an NFC tag does not need to obtain permission , if the existing NDEF message only contains NDEF record s without ID field s, or with ID field s matching the registrable domain of the current settings object 's origin. Otherwise the UA must obtain permission for pushing NFC content which overwrites existing information. See also the § 10.9 Writing or pushing content section.
Since all local content that a web page has access to can be shared with NFC, the user needs to be clearly aware about the permissions granted to the web page using Web NFC.
When pushing an NDEF message , the registrable domain , serialized , of the current settings object must be stored as the record identifier in each top-level NDEF Record .
When listening for and pushing NFC content , the UA may warn the user that the given origin may be able to infer physical location.
The payload data on NFC content is untrusted, and must not be used by the UA to do automatic handling such as opening a web page with a URL found in an NFC tag , unless the user approves that.
NDEFMessage
interface
The
content
of
any
NDEF
message
is
exposed
by
the
NDEFMessage
interface:
[Exposed=Window] interfaceNDEFMessage
{constructor
(NDEFMessageInit
messageInit); readonly attribute FrozenArray<NDEFRecord
>records
; }; dictionaryNDEFMessageInit
{ 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
a
NDEF
message
.
NDEFRecord
interface
The
content
of
any
NDEF
record
is
exposed
by
the
NDEFRecord
interface:
[Exposed=Window] interfaceNDEFRecord
{constructor
(NDEFRecordInit
recordInit); readonly attribute USVStringrecordType
; readonly attribute USVString?mediaType
; readonly attribute USVStringid
; readonly attribute DataView?data
; readonly attribute USVString?encoding
; readonly attribute USVString?lang
; sequence<NDEFRecord
>toRecords
(); }; dictionaryNDEFRecordInit
{ required USVStringrecordType
; USVStringmediaType
; USVStringid
; USVStringencoding
; USVStringlang
; anydata
; };
A
NDEFRecord
object
has
the
following
internal
slots
:
Internal slot | Initial value | Description ( non-normative ) |
---|---|---|
[[PayloadData]] | Empty byte sequence . | A byte sequence representing the whole or a subset of the PAYLOAD field 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
by
the
generator,
as
such
only
absolute
URLs
based
on
the
origin
of
the
browsing
content
can
be
written
using
this
specification.
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
[[PayloadData]]
bytes
of
the
NDEF
Record
.
The
toRecords()
method,
when
invoked,
MUST
return
the
result
of
running
convert
NDEFRecord.[[PayloadData]]
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 :
mediaType
.
encoding
and
language
tag
lang
.
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
Parsing
content
and
§
10.9
Writing
or
pushing
content
sections.
To convert NDEFRecord.[[PayloadData]] bytes given a record , run these steps:
recordType
attribute.
smart-poster
",
or
an
external
type
name
,
then
return
the
result
of
running
parse
records
from
bytes
on
bytes
.
Re-
throw
any
exceptions.
"
NotSupportedError
"
DOMException
and
abort
these
steps.
This
string
defines
the
allowed
record
types
for
a
NDEFRecord
.
The
§
9.4
Data
mapping
section
describes
how
it
is
mapped
to
NDEF
record
types.
A set of known standardized values exists, but it is also possible for organizations to create their own custom external type names .
NDEFRecord
.
DOMString
representing
a
custom
type
for
the
external
type
record
.
The
type
must
follow
the
external
type
name
ABNF.
ext-type = reg-name ":" custom-type
custom-type = 1*(ALPHA / DIGIT / other)
DIGIT = %x30-39
ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
other = "(" / ")" / "+" / "," / "-" / ":" / "=" /
"@"
/
";"
/
"$"
/
"_"
/
"!"
/
"*"
/
"'"
/
"."
The
reg-name
value
is
a
registrable
domain
owned
by
the
issuing
organization,
a
"
:
"
and
a
type,
e.g.
"
w3.org:member
".
And
additional
ABNF
exists
for
well-known
type
records
:
wkt-type
=
(ALPHA
/
DIGIT)
*(ALPHA
/
DIGIT
/
other)
The NFC Record Type Definition (RTD) Technical Specification defines every type in the well-known type records and external type records in terms of URNs, but only a subset of the URN is actually stored in the NDEF record 's TYPE field , which corresponds to the above two ABNFs.
DOMString
that
MUST
start
with
lowercase
letter
or
a
number,
representing
a
type
for
a
NFC
Forum
local
type
,
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.
The
value
MUST
NOT
be
equal
to
any
other
record
type
s
defined
in
this
API.
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 s (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
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
of
a
Text
record
is
"
urn:nfc:wkt:T
",
but
it
is
stored
as
"
T
".
The
mapping
from
data
types
of
an
NDEFRecordInit
to
NDEF
record
types,
as
used
in
the
§
10.9
Writing
or
pushing
content
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 |
|
Well-known type record | 1 |
"
Sp
"
|
local type name | unused |
BufferSource
|
Local type record* | 1 | local type name |
"
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
|
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
Parsing
content
section,
is
as
follows.
record type |
TNF
field
|
TYPE field |
recordType
|
mediaType
|
---|---|---|---|---|
Empty record | 0 | unused |
"
empty
"
|
undefined
|
Well-known type record | 1 |
"
T
"
|
"
text
"
|
undefined
|
Well-known type record | 1 |
"
U
"
|
"
url
"
|
undefined
|
Well-known type record | 1 |
"
Sp
"
|
"
smart-poster
"
|
undefined
|
Local type record* | 1 | local type name | local type name |
undefined
|
MIME type record | 2 | MIME type |
"
mime
"
|
The MIME type used in the NDEF record |
Absolute-URL record | 3 | URL |
"
absolute-url
"
|
undefined
|
External type record | 4 | external type name | external type name |
undefined
|
Unknown record | 5 | unused |
"
unknown
"
|
undefined
|
typedef (DOMString or BufferSource orNDEFMessageInit
)NDEFMessageSource
; [SecureContext, Exposed=Window] interfaceNDEFWriter
{constructor
(); Promise<void>push
(NDEFMessageSource
message, optionalNDEFPushOptions
options={}); }; [SecureContext, Exposed=Window] interfaceNDEFReader
: EventTarget {constructor
(); attribute EventHandleronerror
; attribute EventHandleronreading
; Promise<void>scan
(optionalNDEFScanOptions
options={}); }; [SecureContext, Exposed=Window] interfaceNDEFReadingEvent
: Event {constructor
(DOMString type,NDEFReadingEventInit
readingEventInitDict); readonly attribute DOMStringserialNumber
; [SameObject] readonly attributeNDEFMessage
message
; }; dictionaryNDEFReadingEventInit
: EventInit { DOMString?serialNumber
= ""; requiredNDEFMessageInit
message
; };
The
NDEFMessageSource
is
a
union
type
representing
argument
types
accepted
by
the
push()
method.
The
NDEFReadingEvent
is
the
event
being
dispatched
on
new
NFC
readings.
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
is
used
to
initialize
a
new
event
with
a
serial
number
and
the
NDEFMessageInit
data
via
the
message
member.
If
serialNumber
is
not
present
or
is
null
,
empty
string
will
be
used
to
init
the
event.
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
NFC
devices
such
as
tags.
An
object
has
the
following
internal
slots
:
NDEFWriter
Internal Slot | Initial value | Description ( non-normative ) |
---|---|---|
[[PushOptions]] |
null
|
The
value
for
writer.
|
[[PushMessage]] |
null
|
The
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
object
has
the
following
internal
slots
:
NDEFReader
Internal Slot | Initial value | Description ( non-normative ) |
---|---|---|
[[Id]] | An empty string . |
The
.
id
value.
|
[[RecordType]] |
undefined
|
The
.
recordType
value.
|
[[MediaType]] | An empty string . |
The
.
mediaType
value.
|
[[Signal]] |
undefined
|
The
.
signal
to
abort
the
operation.
|
Note
that
the
internal
slots
of
come
from
the
options
passed
to
NDEFReader
NDEFReader.scan()
.
Therefore
there
is
maximum
one
filter
associated
with
any
given
object
and
successive
invocations
of
NDEFReader
NDEFReader.scan()
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.
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]] | empty set |
A
set
of
instances.
|
[[PendingPush]] | empty |
A
<
promise
,
writer
>
tuple
where
promise
holds
a
pending
Promise
and
writer
holds
an
.
|
The activated reader objects is the value of the [[ActivatedReaderList]] internal slot.
The pending push tuple is the value of the [[PendingPush]] internal slot.
NFC
is
suspended
if
the
[[Suspended]]
internal
slot
is
true
.
To
suspend
NFC
,
set
the
[[Suspended]]
internal
slot
to
true
.
To
resume
NFC
,
set
the
[[Suspended]]
internal
slot
to
false
.
Internal slots are used only as a notation in this specification, and implementations do not necessarily have to map them to explicit internal properties.
When the user agent determines that the visibility state of the responsible document of the current settings object changes, it must run these steps:
"visible"
,
resume
NFC
and
abort
these
steps.
The
term
suspended
refers
to
NFC
operations
being
suspended,
which
means
that
no
NFC
content
is
pushed
by
NDEFWriter
s,
and
no
received
NFC
content
is
presented
to
any
while
being
suspended.
NDEFReader
To attempt to abort a pending push operation on an environment settings object , perform the following steps:
"
AbortError
"
DOMException
and
abort
these
steps.
Rejecting the promise will clear the pending push tuple .
To release NFC on an environment settings object , perform the following steps:
The UA must release NFC given the document's relevant settings object as additional unloading document cleanup steps .
NDEFPushOptions
dictionary
dictionary NDEFPushOptions
{
NDEFPushTarget
target
= "any";
boolean ignoreRead
= true;
boolean overwrite
= true;
AbortSignal? signal
;
};
The
target
property
denotes
the
intended
target
for
the
pending
push()
operation.
When
the
value
of
the
ignoreRead
property
is
true
,
the
push
algorithm
will
skip
invoking
the
NFC
reading
algorithm
for
an
NFC
tag
.
When
the
value
of
the
overwrite
property
is
false
,
the
push
algorithm
will
read
the
NFC
tag
regardless
of
the
ignoreRead
value
to
determine
if
it
has
NDEF
records
on
it,
and
if
yes,
it
will
not
execute
any
pending
push.
The
signal
property
allows
to
abort
the
push()
operation.
NDEFPushTarget
enum
This
enum
defines
the
set
of
intended
target
values
for
the
push()
operation.
enum NDEFPushTarget
{
"tag
",
"peer
",
"any
"
};
tag
push()
operation
to
be
a
NFC
tag
.
peer
push()
operation
to
be
a
NFC
peer
.
any
push()
operation
to
be
a
NFC
tag
or
a
NFC
peer
.
NDEFScanOptions
dictionary
To
describe
which
messages
an
application
is
interested
in,
the
NDEFScanOptions
dictionary
is
used:
dictionary NDEFScanOptions
{
USVString id
= "";
USVString recordType
;
USVString mediaType
= "";
AbortSignal? signal
;
};
The
signal
property
allows
to
abort
the
scan()
operation.
The
id
property
denotes
the
URL
pattern
which
is
used
for
matching
the
record
identifier
of
individual
NDEF
Record
s
which
are
being
read.
The
default
value
""
means
that
no
matching
is
performed.
The
recordType
property
denotes
the
string
value
which
is
used
for
matching
the
record
type
of
each
NDEFRecord
object
in
an
NDEF
message
.
If
the
dictionary
member
is
not
present
,
then
it
will
be
ignored
by
the
NFC
listen
algorithm
.
The
mediaType
property
denotes
the
match
pattern
which
is
used
for
matching
the
mediaType
property
of
each
NDEFRecord
object
in
an
NDEF
message
.
The
default
value
""
means
that
no
matching
is
performed.
const options = {
id: "https://www.w3.org/*", // any path from the domain is accepted
mediaType: "application/*json" // any JSON-based MIME type
}
const options = {
id: "https://w3.org/info/restaurant/daily-menu/",
mediaType: "application/octet-stream"
}
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 a maximum of two NDEF message s that can be set for pushing for an origin : one targeted to NFC tag s and one to NFC peer s, until the current message is sent or the push is aborted.
NDEFWriter.push
method,
when
invoked,
MUST
run
the
push
a
message
algorithm:
Promise
object.
"
NotSupportedError
"
DOMException
and
return
p
.
"
NotReadableError
"
DOMException
and
return
p
.
"
NotSupportedError
"
DOMException
and
return
p
.
"
NotAllowedError
"
DOMException
and
return
p
.
null
otherwise.
"
AbortError
"
DOMException
and
return
p
.
null
,
then
add
the
following
abort
steps
to
signal
:
"
NotSupportedError
"
DOMException
and
abort
these
steps.
The UA might abort message push at this point. The reasons for termination 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 requested operation.
A push replaces all previously configured push operations.
this
.[[PushOptions]]
to
options
.
this
.[[PushMessage]]
to
output
.
this
,
p
).
If NFC is suspended , continue waiting until promise is aborted by the user or an NFC device comes within communication range.
"
NotSupportedError
"
DOMException
and
return
p
.
tag
"
or
"
any
".
peer
"
or
"
any
".
true
,
run
the
NFC
reading
algorithm
.
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
.
null
,
or
different
than
the
serialized
host
of
the
current
settings
object
's
origin,
and
the
obtain
push
permission
steps
return
false
,
then
reject
p
with
"
NotAllowedError
"
DOMException
and
abort
these
steps.
If the NFC device in proximity range is an unformatted NFC tag that is NDEF -formatable, format it and write output as buffer.
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.
"
NetworkError
"
DOMException
and
abort
these
steps.
To obtain push permission , run these steps:
true
.
"
granted
"
(i.e.
an
expressed
permission
has
been
granted
to
the
origin
and
global
object
using
the
Permissions
API),
return
true
.
"
prompt
"
,
then
optionally
request
permission
from
the
user
for
the
Web
NFC
permission
name
.
If
that
is
granted,
return
true
.
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
.
false
.
To create NDEF message given a message run these steps:
NDEFMessageSource
union,
throw
a
TypeError
and
abort
these
steps.
NDEFMessageInit
type,
and
message
's
records
is
empty
,
throw
a
TypeError
and
abort
these
steps.
undefined
:
empty
"
text
"
url
"
mime
"
NDEFMessageInit
,
then
return
the
result
of
running
the
create
NDEF
message
given
record
's
data.
NDEFMessageInit
,
then
return
the
result
of
running
the
create
NDEF
message
given
record
's
data.
NDEFMessageInit
and
its
id
is
not
null
:
1
.
To map empty record to NDEF given a record , run these steps:
undefined
,
throw
a
TypeError
and
abort
these
steps.
0
(
empty
record
).
0
.
0
,
and
omit
TYPE
field
and
PAYLOAD
field
.
To map text to NDEF given a record , run these steps:
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
".
undefined
,
throw
a
TypeError
and
abort
these
steps.
DOMString
or
a
BufferSource
,
throw
a
TypeError
and
abort
these
steps.
en
".
utf-8
".
utf-8
",
"
utf-16
",
"
utf-16le
"
or
"
utf-16be
"
throw
a
TypeError
.
7
to
the
value
0
,
or
else
set
the
value
to
1
.
6
to
the
value
0
(reserved).
SyntaxError
.
5
to
bit
0
to
languageLength
.
DOMString
BufferSource
1
(
well-known
type
record
).
T
"
(
0x54
).
0
,
set
the
ndefRecord
's
PAYLOAD
field
to
data
.
To map a URL to NDEF given a record , run these steps:
undefined
,
throw
a
TypeError
and
abort
these
steps.
DOMString
,
throw
a
TypeError
and
abort
these
steps.
TypeError
and
abort
these
steps.
0
.
1
(
well-known
type
record
).
U
"
(
0x55
).
0
,
set
the
ndefRecord
's
PAYLOAD
field
to
data
.
To map binary data to NDEF given a record , run these steps:
BufferSource
,
throw
a
TypeError
and
abort
these
steps.
application
",
and
subtype
is
"
octet-stream
".
2
(
MIME
type
).
0
,
set
the
ndefRecord
's
PAYLOAD
field
to
data
.
To map external data to NDEF given a record , run these steps:
undefined
,
throw
a
TypeError
and
abort
these
steps.
BufferSource
,
throw
a
TypeError
and
abort
these
steps.
4
(
external
type
record
).
0
,
set
the
ndefRecord
's
PAYLOAD
field
to
data
.
To map local type to NDEF given a record , run these steps:
undefined
,
throw
a
TypeError
and
abort
these
steps.
BufferSource
,
throw
a
TypeError
and
abort
these
steps.
1
(
well-known
type
record
),
otherwise
set
ndefRecord
's
TNF
field
to
4
(
external
type
record
).
0
,
set
the
ndefRecord
's
PAYLOAD
field
to
data
.
To create a record identifier given URL string id , run these steps:
https://
"
+
host
as
the
base
URL.
TypeError
and
abort
these
steps:
"https:
".
If
there
are
any
instances
in
activated
reader
objects
then
the
UA
MUST
listen
to
NDEF
message
s.
NDEFReader
To
listen
for
NFC
content
,
the
client
MUST
activate
an
instance
by
calling
NDEFReader
NDEFReader.scan()
.
When
attaching
an
event
listener
for
the
"
reading
"
event
on
it,
NFC
content
is
accessible
to
the
client.
Each
can
accept
NDEF
message
s
based
on
data
type,
and
record
identifier
(URL)
filters.
NDEFReader
Filtering by a record identifier URL pattern, means that it will be matched against the URLs found in the NDEF record s' ID field , thus the presence of such is required.
A match pattern is defined by the following ABNF:
match-pattern = top-level-type "/" [ tree "." ] subtype [ "+" suffix ] [ ";" parameters ]
top-level-type = "*" / < VCHAR except "/" and "*" >
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.
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 record identifier |
---|---|
host |
exact
match
or
ends
with
(
URL
pattern
's
host
prepended
with
"
.
").
|
path |
If
URL
pattern
's
path
is
"
/*
",
match
any
record
identifier
path.
Otherwise,
begins
with
URL
pattern
's
path
.
|
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.
true
.
false
.
false
.
.
"
to
pattern
's
host
.
false
.
/*
",
return
true
.
true
.
false
.
Incoming
NFC
content
is
matched
using
instances.
NDEFReader
When
the
NDEFReader.scan
method
is
invoked,
the
UA
MUST
run
the
following
NFC
listen
algorithm
:
Promise
object.
NDEFReader
instance.
signal
"
and
value
is
not
undefined
,
set
reader
.
[[Signal]]
to
value
.
id
",
set
reader
.
[[Id]]
to
value
,
prepended
with
"
https://
".
recordType
",
set
reader
.
[[RecordType]]
to
value
.
mediaType
",
set
reader
.
[[MediaType]]
to
value
.
"
NotSupportedError
"
DOMException
and
return
p
.
"
NotReadableError
"
DOMException
and
return
p
.
"
NotAllowedError
"
DOMException
and
return
p
.
"
AbortError
"
DOMException
and
return
p
.
null
,
then
add
the
following
abort
steps
to
reader
.
[[Signal]]
:
NDEFReader
instance
from
the
activated
reader
objects
.
false
,
then
reject
p
with
a
"
NotAllowedError
"
DOMException
and
return
p
.
"
NotSupportedError
"
DOMException
and
return
p
.
"
SyntaxError
"
DOMException
and
return
p
.
Document
of
the
top-level
browsing
context
is
not
visible
(e.g.
the
user
navigated
to
another
page),
then
the
registered
activated
reader
objects
still
SHOULD
continue
to
exist,
but
SHOULD
become
paused,
i.e.
the
UA
SHOULD
NOT
check
and
use
them
until
the
Document
is
visible
again.
To obtain reading permission , run these steps:
true
.
scan()
as
well,
then
return
false
.
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.
true
.
Note
NDEFReader
This
means
there
is
no
reading
event
generated
when
non-
NDEF
NFC
technology
comes
in
proximity
range.
This
may
change
instance
reader
in
error
"
at
reader
.
null
if
unavailable.
null
,
set
it
to
the
string
of
U+003A
(
:
)
concatenating
each
number
represented
as
ASCII
hex
digit
,
in
the
same
order.
NDEFMessage
object,
with
message
's
records
set
to
the
empty
list
.
null
.
Otherwise,
let
input
be
the
notation
for
the
NDEF
message
which
has
been
received.
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.
null
,
append
record
to
message
's
records.
To
dispatch
NFC
content
given
a
serialNumber
of
type
serialNumber
,
message
of
type
NDEFMessage
,
run
these
steps:
NDEFReader
instance
reader
in
the
activated
reader
objects
,
run
the
following
sub-steps:
""
and
it
is
not
equal
to
any
record
's
mediaType
where
record
is
an
element
of
message
,
continue
.
reading
"
at
reader
using
NDEFReadingEvent
with
its
serialNumber
attribute
initialized
to
serialNumber
and
message
attribute
initialized
to
message
.
3
,
abort
these
sub-steps.
false
,
return
records
.
true
,
let
payloadLength
be
the
integer
value
of
next
byte
(
PAYLOAD
LENGTH
field
)
of
bytes
.
true
,
let
idLength
be
the
integer
value
of
next
byte
(
ID
LENGTH
field
)
of
bytes
,
otherwise
let
it
be
0
.
0
bytes.
null
,
append
record
to
records
.
true
,
abort
these
sub-steps.
To parse an NDEF record given ndef into a record , run these steps:
null
.
null
.
0
(
empty
record
),
then
set
record
's
recordType
to
"
empty
".
1
(
well-known
type
record
):
T
"
(
0x54
)
U
"
(
0x55
)
Sp
"
(
0x53
0x70
)
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.
3
(
absolute-URL
record
),
then
set
record
to
the
result
of
running
parse
an
NDEF
absolute-URL
record
on
ndef
.
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.
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.
T
records
To parse an NDEF text record given a ndefRecord into a record , run these steps:
text
".
text
",
subtype
"
plain
"
and
parameters
equal
to
an
empty
ordered
map.
undefined
and
return
record
.
5
to
bit
0
of
the
header
.
1
byte,
inclusive.
utf-8
"
if
bit
7
(
MB
field
)
of
header
is
equal
to
the
value
0
,
or
else
"
utf-16be
".
U
records
To parse an NDEF URL record given a ndefRecord into a record , run these steps:
url
".
undefined
and
return
record
.
Sp
records
To parse an NDEF smart-poster record given a ndefRecord into a record , run these steps:
smart-poster
".
undefined
and
return
record
.
To parse an NDEF MIME type record given a ndefRecord into a record , run these steps:
mime
".
undefined
.
To parse an NDEF absolute-URL record given a ndefRecord into a record , run these steps:
absolute-url
".
To parse an NDEF external type record given a ndefRecord into a record , run these steps:
undefined
.
To parse an NDEF unknown record given a ndefRecord into a record , run these steps:
unknown
".
undefined
.
[Exposed=Window] interfaceNDEFMessage
{constructor
(NDEFMessageInit
messageInit); readonly attribute FrozenArray<NDEFRecord
>records
; }; dictionaryNDEFMessageInit
{ required sequence<NDEFRecordInit
>records
; }; [Exposed=Window] interfaceNDEFRecord
{constructor
(NDEFRecordInit
recordInit); readonly attribute USVStringrecordType
; readonly attribute USVString?mediaType
; readonly attribute USVStringid
; readonly attribute DataView?data
; readonly attribute USVString?encoding
; readonly attribute USVString?lang
; sequence<NDEFRecord
>toRecords
(); }; dictionaryNDEFRecordInit
{ required USVStringrecordType
; USVStringmediaType
; USVStringid
; USVStringencoding
; USVStringlang
; anydata
; }; typedef (DOMString or BufferSource orNDEFMessageInit
)NDEFMessageSource
; [SecureContext, Exposed=Window] interfaceNDEFWriter
{constructor
(); Promise<void>push
(NDEFMessageSource
message, optionalNDEFPushOptions
options={}); }; [SecureContext, Exposed=Window] interfaceNDEFReader
: EventTarget {constructor
(); attribute EventHandleronerror
; attribute EventHandleronreading
; Promise<void>scan
(optionalNDEFScanOptions
options={}); }; [SecureContext, Exposed=Window] interfaceNDEFReadingEvent
: Event {constructor
(DOMString type,NDEFReadingEventInit
readingEventInitDict); readonly attribute DOMStringserialNumber
; [SameObject] readonly attributeNDEFMessage
message
; }; dictionaryNDEFReadingEventInit
: EventInit { DOMString?serialNumber
= ""; requiredNDEFMessageInit
message
; }; dictionaryNDEFPushOptions
{NDEFPushTarget
target
= "any"; booleanignoreRead
= true; booleanoverwrite
= true; AbortSignal?signal
; }; enumNDEFPushTarget
{ "tag
", "peer
", "any
" }; dictionaryNDEFScanOptions
{ USVStringid
= ""; USVStringrecordType
; USVStringmediaType
= ""; AbortSignal?signal
; };
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, and Wanming Lin 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.