NDEF Specification Deep Dive

Message Structure, Record Types, Encoding

NDEF Specification Deep Dive

The NFC Data Exchange Format (ndef-message) is the universal data container that makes NFC interoperable across chips, operating systems, and applications. Defined by the NFC Forum, NDEF abstracts away the physical differences between tag types and provides a structured, extensible wire format that any conforming device can read and write.

This guide dissects the NDEF binary layout at the byte level — essential reading before you use the NDEF Encoder or NDEF Decoder in production.

NDEF Message Structure

An ndef-message is a sequence of one or more ndef-record structures packed contiguously in memory. There is no message-level header: the boundary of one message is inferred by the MB (Message Begin) and ME (Message End) flags embedded in each record's header byte.

[ Record 1: MB=1, ME=0 ][ Record 2: MB=0, ME=0 ][ Record N: MB=0, ME=1 ]

A single-record message sets both MB and ME on the same record. The minimal valid NDEF message is 3 bytes: a 1-byte header, a 1-byte type length, and a 1-byte payload length (SR flag set), with zero-length type and payload.

Record Header Flags

Each record opens with a flags byte that controls how the rest of the record is parsed:

Bit Flag Meaning when set
7 MB First record in the message
6 ME Last record in the message
5 CF This record is a chunk (chunked payload continues)
4 SR Short record — payload length is 1 byte (0–255 B)
3 IL ID Length field is present
2–0 TNF Type Name Format (3-bit field, values 0x00–0x07)

The tnf (Type Name Format) field is the most consequential: it tells the parser how to interpret the TYPE field that follows.

TLV Blocks on Tag Memory

NDEF messages are not written raw to tag memory. On Type 2 and Type 5 tags the memory uses a tlv (Tag-TLV) wrapper:

TLV Tag Name Purpose
0x00 Null Padding / reserved
0x01 Lock Control Identifies dynamic lock bytes
0x02 Memory Control Identifies reserved memory areas
0x03 NDEF Message Contains the NDEF message (length + data)
0xFE Terminator Marks end of TLV stream (single byte)

For messages ≤ 254 bytes the Length field of the NDEF TLV is a single byte. For messages from 255 to 65535 bytes the length is encoded as 0xFF followed by a 2-byte big-endian value — a detail that trips up many hand-rolled parsers.

The capability-container on Type 2 tags (bytes 0x00–0x03 of the first sector) identifies the tag's memory size and NDEF version, and must be written correctly before the TLV stream or the tag will not be recognised as NDEF-formatted by compliant readers.

NDEF Record Types

The tnf value selects the type namespace:

TNF Value Namespace Common Uses
0x00 Empty Placeholder records
0x01 NFC Forum Well-Known URI, Text, SmartPoster, Signature
0x02 MIME type text/vcard, application/json
0x03 Absolute URI Full URI as type
0x04 NFC Forum External App-defined types
0x05 Unknown Binary blobs without type info
0x06 Unchanged Continuation chunks only
0x07 Reserved Not used

Well-Known Types in Practice

  • ndef-uri record (type U, 0x55): Stores a URL. The first payload byte is an abbreviation code (0x01 = http://www., 0x04 = https://, etc.) followed by the remaining URI bytes. A URL of https://nfcfyi.com encodes as [0x04]nfcfyi.com — saving 8 bytes vs storing the full string.
  • ndef-text record (type T, 0x54): Stores human-readable text with a language tag. First payload byte encodes UTF-8/UTF-16 flag and language code length, followed by the IETF language code (en, ko) and then the text body.
  • smart-poster record (type Sp, 0x5370): A container record whose payload is itself an NDEF message containing at minimum a URI record, optionally augmented with Text (title), Action, Size, Type, and Icon records.
  • aar record (NFC Forum External type android.com:pkg): Android Application Record — ensures that when a tag is scanned on Android, the correct app opens or the Play Store launches if not installed.

Chunked Records

The CF (Chunk Flag) bit enables splitting a large payload across multiple physical records. The first chunk sets CF=1, MB=1; intermediate chunks set CF=1, MB=0, ME=0; the final chunk sets CF=0, ME=1. All chunks share the same type and ID — only the first chunk may carry a TYPE field; subsequent chunks use TNF 0x06 (Unchanged).

Chunking is rarely needed in practice because most NFC tags top out at 8 KB, well within a single SR record's reach. However, chunking is required by the spec and must be handled correctly by any conforming parser.

Encoding Workflow

  1. Determine payload: URL, vCard, JSON, or binary blob.
  2. Select record type: URI for URLs, MIME for structured data, External for proprietary formats.
  3. Compute payload bytes and set SR flag if ≤ 255 bytes.
  4. Wrap in TLV 0x03 with correct length encoding.
  5. Write capability container first on fresh Type 2 tags.
  6. Verify with the NDEF Decoder before mass encoding.

Use the NDEF Encoder to generate correct binary output from human-readable inputs, and the NDEF Decoder to inspect raw hex dumps from tag reads. For tag memory sizing, see NFC Memory Calculator.

For the broader tag landscape this format runs on, see NFC Tag Types Explained.

Terms in This Guide