How to Read and Write NFC Tags
Reading and writing NFC tags requires understanding the NDEF data model, your platform's NFC API, and common failure modes. This guide covers the complete workflow from tapping a tag to persisting structured data.
Reading Tags
When an nfc-enabled-device enters reader-writer-mode, it polls for tags at 106–424 kbit/s. Once a tag responds, the reader retrieves the tag's uid and reads the NDEF memory area.
The NDEF memory contains a sequence of ndef-records wrapped in an ndef-message. Each record carries a Type Name Format (tnf), a type string, an optional ID, and a payload. Common record types:
| TNF | Type | Payload | Example |
|---|---|---|---|
| 1 (Well Known) | U |
URI | https://nfcfyi.com |
| 1 (Well Known) | T |
Text | en:Hello NFC |
| 2 (MIME) | text/vcard |
vCard blob | Contact card |
| 4 (External) | nfcfyi.com:cfg |
Custom bytes | App config |
On Android, a successful read delivers an NfcAdapter.ACTION_NDEF_DISCOVERED intent containing a NdefMessage. On iOS (Core NFC), NFCNDEFReaderSession calls readerSession(_:didDetectNDEFs:). Both platforms expose the raw NdefRecord array.
Writing Tags
Before writing, verify that the tag is not locked. Tags expose lock-bits that, once set, make the memory permanently read-only. A capability-container at the start of the NDEF area declares memory size, access conditions, and whether the tag is NDEF-formatted.
Writing workflow:
1. Authenticate if the tag has a password (PWD_AUTH for NTAG, AUTHENTICATE for DESFire).
2. Format the tag if it has no capability container (first use).
3. Construct an NdefMessage with one or more NdefRecords.
4. Write the message using the platform API (Ndef.writeNdefMessage() on Android, NFCNDEFTag.writeNDEF() on iOS).
5. Optionally set the otp lock page to protect the content.
NDEF Basics
The NDEF specification defines a compact binary encodingencodingData writing to NFC tags during manufacturing productionView full →. Each record begins with a flags byte encoding MB (Message Begin), ME (Message End), CF (Chunk Flag), SR (Short Record), IL (ID Length), and TNF. A short record stores the payload length in 1 byte (max 255 B); a normal record uses 3 bytes (max 16 MB).
The most important record types for getting started:
- ndef-uri — Encodes a URL with a 1-byte prefix abbreviation (e.g.,
0x03=https://) - ndef-text — Encodes a UTF-8 or UTF-16 string with an IANA language code
- smart-poster — Composite record combining URI + Text title + optional action
Common Errors
| Error | Cause | Fix |
|---|---|---|
TagLostException |
Tag moved before write completed | Hold steady; retry |
FormatException |
Malformed NDEF messageNDEF messageComplete data unit containing one or more NDEF recordsView full → | Validate with NDEF Decoder |
ReadOnlyException |
Lock bitsLock bitsControl bits making memory blocks permanently read-onlyView full → set | Use a different tag |
| Write returns success but read fails | Buffer too small for payload | Check user-memory with Memory Calculator |
| Auth failure | Wrong password | Reset via backdoor if available (chip-specific) |
Use the NDEF Message Encoder to construct and preview NDEF payloads before writing, and the NDEF Message Decoder to inspect raw bytes from an existing tag.
See also: Your First NFC Project and Android NFC Programming Guide.