18  NFC Tag Programming

rfid-nfc-uwb
apps
programming
tags

18.1 Start With the Story

Programming a tag is not done when the writer reports success. It is done when the record plan fits the tag, the bytes are written, the data is read back, locks or passwords are understood, and the release note says what should happen if a scan fails.

Use this chapter as a write-verify story. Plan the NDEF payload, choose the tool path, test the result on the intended reader, and leave evidence that the tag can be trusted only for the job it was designed to do.

In 60 Seconds

NFC tag programming is a controlled write workflow: plan the NDEF records, confirm the tag has enough writable memory, write through the chosen reader or phone API, read the tag back, then lock or protect it only after the payload and fallback path are verified. The code is usually small; the quality risk is writing the wrong record, trusting the tag as a credential, or deploying tags that fail on the final mounting surface.

18.2 Learning Objectives

By the end of this chapter, you should be able to:

  • Plan URI, Text, MIME, and external-type NDEF records for an IoT tag without storing secrets in public payloads.
  • Check tag capacity, write state, and platform support before attempting a write.
  • Implement safe write patterns for Android, Python/nfcpy, and PN532-based embedded readers.
  • Verify a written tag by reading it back and validating the payload, type, length, and application policy.
  • Diagnose common write failures caused by tag lock state, memory limits, interface wiring, antenna coupling, and mounting material.

18.3 Quick Check: NFC Tag Programming

18.4 Minimum Viable Understanding

  • Programming is not just writing bytes. A safe tag write includes record planning, capacity checks, write access checks, write, read-back verification, and a release record.
  • NDEF is public unless another layer protects it. Do not store passwords, access tokens, private keys, or one-time codes as ordinary NDEF text.
  • UIDs and NDEF records have different jobs. A UID can identify a tag, while an NDEF record can identify content or launch an app. Neither one proves authorization by itself.
  • Tag memory is tight. Small Type 2 tags work well for one URL or compact app link; larger or protected records need a tag with explicit headroom.
  • The physical install matters. Metal surfaces, wet areas, phone cases, and antenna position can turn a clean desk test into a field failure.

18.5 Programming Workflow

Start with a write record, not with code. The same workflow applies whether the writer is an Android phone, a USB reader, a Raspberry Pi, or a microcontroller with a PN532 module.

NFC tag programming workflow from record plan through capacity check, write, read-back validation, protection, and release evidence.

NFC tag programming workflow from record plan through capacity check, write, read-back validation, protection, and release evidence.
Plan the payload Choose URI, Text, MIME, or external-type records. Keep commands and sensitive policy out of public NDEF data.
Check the tag Confirm tag type, writable state, available NDEF capacity, lock bits, and whether the tag is already password-protected or read-only.
Write deliberately Use an explicit write screen or supervised station. Do not write tags in a background flow where the user can move away unnoticed.
Verify before release Read the tag back with the target device class, validate the decoded records, and record the tag batch, surface, fallback, and retest trigger.

18.6 Programming Is Records Plus Lifecycle

Writing an NFC tag has two halves that are easy to blur. First, compose the NDEF message: choose which record types encode the behavior you want. Then decide the memory lifecycle: whether the tag stays rewritable, is password-protected, or is permanently frozen read-only. A poster sticker anyone could overwrite and a tamper-resistant asset tag may use the same records but opposite lifecycle choices.

Think about a gateway maintenance rollout before writing code. The team needs 80 labels. Each tap should open one maintenance record, show a short human label, and let the app request authenticated service actions. The tag should not contain a technician password, service command, or bearer token. A safe record plan is a URI such as https://ops.example.invalid/a/gateway-041 plus a Text record such as Gateway 041 maintenance record. The tag selects context; the app and backend decide whether the current technician may do anything privileged.

That split gives you a release checklist. Before writing, estimate encoded NDEF size and compare it with the tag’s usable capacity, leaving room for a future path or version field. During writing, reject tags that are read-only, already protected, too small, or not NDEF formatted. After writing, read the tag back with the same class of phone or reader used in the field, then compare record count, type, order, host, asset identifier, and length. Only then choose the lifecycle control: leave lab tags rewritable, password-protect a staff-maintained batch, or permanently lock public poster tags whose URL must never change.

NFC write and verify release workflow showing plan, inspect, write, read back, validate, protect or lock, and record evidence.

NFC write and verify release workflow showing plan, inspect, write, read back, validate, protect or lock, and record evidence.

The most common design error is treating the write command’s success flag as the release event. It is only one command result. The release event is evidence: written payload, decoded read-back, protection state, tag batch, app version, physical surface, and replacement procedure. That evidence is what lets a maintenance team debug a future failure without guessing whether the problem is RF coupling, a bad NDEF record, an app validation rule, or a tag that was locked too early.

18.7 NDEF Record Planning

NDEF messages can contain multiple records, but a good programming workflow keeps the record set small and predictable.

NFC NDEF Message Structure: NDEF Message Container, Record 1 (MB=1), Record 2, ..., Record N (ME=1), End, NDEF Record Structure, Header, 1 byte

NFC NDEF Message Structure
URI record Use for web or app handoff. Prefer stable HTTPS links or app links that point to server-side policy instead of storing commands in the tag.
Text record Use for a short human-readable label, fallback note, or maintenance hint. Keep it concise and non-sensitive.
MIME record Use when an app owns a compact data schema. Include a version field and reject unknown schemas.
External-type record Use for a named domain format. Document the owner, expected record order, and compatibility rule.

18.8 Record Types and Validation Rules

The record type determines both the platform behavior and the validation rule. A message can hold several records, and order matters: the first record usually drives the primary action while later records act as fallbacks or hints. A “tap to open the app, or the web page if the app is missing” tag is one multi-record message, not two unrelated tags.

Record What it encodes Detail that matters
URI A link or scheme such as HTTPS, tel, or mailto Prefix bytes can abbreviate common URI starts, so measure the encoded message rather than guessing from visible characters.
Text Human-readable label, instruction, or fallback note Carries a language code and UTF-8 or UTF-16 flag; keep it short and non-sensitive.
Smart Poster A URI bundled with title, action, and optional icon Useful when the record should say both what to show and what action to prefer.
Android Application Record Android package name stored as an external type Can guide app launch or install behavior; provide a web fallback when the app is absent.
Handover Wi-Fi or Bluetooth setup material Bootstraps a faster radio and belongs in a flow with its own credential and rotation policy.

A practical maintenance tag might put the stable HTTPS URI first, a short Text label second, and an app-specific MIME or external-type record only when the app owns a documented schema. The validation rule should say what happens when records arrive in the wrong order, when an unknown MIME type appears, or when the URI host is not the approved host.

For a batch station, make the checks mechanical. Scan a blank tag, log its type and writable capacity, encode the planned records, and compare the encoded byte count with capacity before writing. A 40-character URL and a 30-character label usually fit a small Type 2 tag, but app-specific MIME records, icons, long JSON, and future version fields can push a design into a larger tag. Decide from the encoded message that the writer library will actually send, because URI abbreviation bytes, language codes, record headers, and text encoding all affect the result.

18.8.1 Capacity Rule

Before writing, estimate the encoded size and keep headroom for future revision. A simple URI tag can fit on a small Type 2 tag. A multi-record commissioning tag may need a larger Type 2, Type 4, or Type 5 tag depending on the app and reader requirements.

record_set: 1. URI = https://ops.example.invalid/a/gateway-041 2. Text = Gateway 041 maintenance record policy: public_payload: yes authorization: app and backend, not tag expected_records: URI first, optional Text second reject_if: unknown host, excessive length, unexpected MIME type, failed read-back

18.9 Android Write Pattern

Android NFC writing should happen in a foreground workflow where the user intentionally taps a tag while the app is ready to write. The app should check whether the tag already supports NDEF, whether it is writable, whether the message fits, and whether a newly formatted tag is needed.

NdefMessage buildMessage(String assetUrl, String label) {
    NdefRecord uri = NdefRecord.createUri(assetUrl);
    NdefRecord text = NdefRecord.createTextRecord("en", label);
    return new NdefMessage(new NdefRecord[] { uri, text });
}

boolean writeMessage(Tag tag, NdefMessage message) throws Exception {
    Ndef ndef = Ndef.get(tag);
    if (ndef != null) {
        ndef.connect();
        try {
            if (!ndef.isWritable()) return false;
            if (message.toByteArray().length > ndef.getMaxSize()) return false;
            ndef.writeNdefMessage(message);
            return true;
        } finally {
            ndef.close();
        }
    }

    NdefFormatable formatable = NdefFormatable.get(tag);
    if (formatable == null) return false;
    formatable.connect();
    try {
        formatable.format(message);
        return true;
    } finally {
        formatable.close();
    }
}
Android Implementation Notes
  • Use an explicit write state in the UI so the user knows when to hold the tag steady.
  • Handle TagLostException and repeat the write only after the user taps again.
  • Validate the read-back message before showing success.
  • Avoid writing credentials or secrets to NDEF records. Use the tag as a reference to authenticated app or backend policy.

18.10 Python and USB Reader Pattern

Python tools are useful for programming batches, lab stations, and maintenance tags. The writer should read the tag first, reject non-writable or undersized tags, write the records, and then read the records back.

import nfc
import ndef

RECORDS = [
    ndef.UriRecord("https://ops.example.invalid/a/gateway-041"),
    ndef.TextRecord("Gateway 041 maintenance record", language="en"),
]

def on_tag(tag):
    if not tag.ndef:
        print("Tag is not NDEF formatted")
        return False
    if not tag.ndef.is_writeable:
        print("Tag is read-only")
        return False
    encoded = b"".join(ndef.message_encoder(RECORDS))
    if len(encoded) > tag.ndef.capacity:
        print("Payload does not fit this tag")
        return False

    tag.ndef.records = RECORDS
    read_back = list(tag.ndef.records)
    if [r.type for r in read_back] != [r.type for r in RECORDS]:
        print("Read-back validation failed")
        return False

    print("Tag written and verified")
    return False

with nfc.ContactlessFrontend("usb") as reader:
    reader.connect(rdwr={"on-connect": on_tag})
Reader Connection Strings

nfc.ContactlessFrontend("usb") is common for supported USB readers. PN532 boards may require a serial or driver-specific connection string. Keep the exact station hardware and driver version in the deployment notes so batch writes are repeatable.

18.11 PN532 Embedded Reader Pattern

An embedded reader is usually better for reading and validating tags in a product flow than for mass programming. If it writes tags, keep the write flow supervised and include verification.

#include <Wire.h>
#include <PN532_I2C.h>
#include <PN532.h>
#include <NfcAdapter.h>

PN532_I2C pn532_i2c(Wire);
NfcAdapter nfc(pn532_i2c);

void setup() {
  Serial.begin(115200);
  nfc.begin();
  Serial.println("Hold a writable NDEF tag near the reader");
}

void loop() {
  if (!nfc.tagPresent()) {
    delay(250);
    return;
  }

  NfcTag tag = nfc.read();
  Serial.print("UID: ");
  Serial.println(tag.getUidString());

  if (!tag.hasNdefMessage()) {
    Serial.println("No NDEF message found");
    return;
  }

  NdefMessage message = tag.getNdefMessage();
  Serial.print("Records: ");
  Serial.println(message.getRecordCount());
}
PN532 Wiring Review
  • Set the PN532 board to the interface used by the sketch: I2C, SPI, or UART.
  • Confirm voltage compatibility for the specific breakout board before connecting it to a microcontroller.
  • Keep SDA/SCL, SPI chip select, or UART pins documented in the lab record.
  • Test one known-good formatted tag before debugging application code.

18.12 Write and Verify Loop

Write failures often look like user mistakes, but the root cause is usually a missing preflight check or a missing read-back step.

NFC write and verify loop showing detect, inspect capability, write, read back, compare expected records, protect tag, and record release evidence.

NFC write and verify loop showing detect, inspect capability, write, read back, compare expected records, protect tag, and record release evidence.
Detect Confirm a single tag is present and stable. Avoid writing while multiple tags are in the field.
Inspect Record tag type, capacity, write state, existing records, lock bits, and whether formatting is required.
Write Write only the planned NDEF message. Fail closed if the message exceeds capacity or the tag is read-only.
Read back Decode the tag after writing and compare record count, type, order, host, length, and application version.
Protect Lock or password-protect only after read-back passes and the replacement process is documented.

18.13 Folded Implementation Record

Implementation starts before the first write. Keep a short record beside each tag workflow:

Record field What it proves
Intended action The tag selects an object or workflow; privileged action still requires app policy.
NDEF schema Record type, order, version, host, length limit, encoding, and unsupported-record behavior are known before writing.
Platform path Android app, Python station, PN532 reader, or production fixture has an owner and test version.
Write result The tag was written, read back, decoded, compared with the expected record, and rejected on mismatch.
Release evidence Tag type, capacity, lock state, reader station, app version, final mounting test, and fallback are recorded.

For gateway replacement tags, fail closed on unknown host, unexpected record type, oversized payload, read-only tag, or missing asset ID. Do not store technician credentials, service commands, or private tokens in public NDEF records; use the tap to select context, then let the authenticated application authorize the action.

18.14 Tag Selection for Programming

Select tags by payload, write lifecycle, phone compatibility, environment, and security need.

Simple public link Small Type 2 tags are usually enough. Use a stable URL so content can change server-side without rewriting every tag.
Multi-record setup tag Choose a larger Type 2 or compatible tag with enough headroom for URI, text, and app-specific records.
Industrial surface Choose an on-metal or ferrite-backed construction when the tag is mounted on metal or near equipment that detunes the antenna.
Security-critical flow Do not rely on public NDEF or UID-only checks. Use cryptographic tags, secure credentials, or backend challenge-response.

18.15 Lock Bits and Password Protection on NTAG

Take the common NTAG21x family as the concrete example. NTAG213, NTAG215, and NTAG216 provide roughly 144, 504, and 888 bytes of user memory, respectively. Their memory model gives you two different write controls, and confusing them creates deployment bugs.

  • Lock bytes set individual pages to read-only. Static and dynamic lock bits are one-way; once a page is locked, it cannot be rewritten. This is how you permanently freeze a public poster tag so visitors cannot swap its URL.
  • Password protection uses a 32-bit PWD and a 16-bit PACK acknowledgement to gate writes, or sometimes reads, behind a shared secret. An authorized writer can still update the tag, so this protects an update process rather than freezing content.

“Make this tag safe” therefore has two different answers. Lock it if the content is final and must never change. Password-protect it if it must stay updatable by staff but not by the public. NTAG21x also exposes a one-way NFC counter and a Capability Container that a reader checks first to learn the memory size and whether the tag is already read-only. The Capability Container is why a careful writer inspects the tag before writing instead of blasting records at every UID it sees.

The release order matters. First inspect tag type, capacity, and write state. Then write the NDEF TLV containing the planned records. Then read back the decoded message and compare it with the plan. Only after that should you set irreversible lock bits or configure the password boundary. If a public poster tag is locked before read-back and the URL has a typo, the mistake becomes permanent.

The security boundary is narrower than many product sketches imply. A password gate on a low-cost tag is a write-control feature, not a substitute for backend authorization, and an NFC UID or public NDEF value can be copied in many practical deployments. When cloning matters, use a tag family and application protocol designed for cryptographic proof, or treat the NFC tap as a lookup key validated by an authenticated app session. Match the memory control to the consequence: lock immutable public content, password-protect supervised update batches, and move authorization out of ordinary NDEF payloads.

18.16 Check Lock Versus Password Protection

18.17 Debugging Map

When a tag does not work, isolate the failure layer before changing code.

NFC tag programming debugging map separating reader interface, RF coupling, tag capability, NDEF format, app validation, and deployment surface issues.

NFC tag programming debugging map separating reader interface, RF coupling, tag capability, NDEF format, app validation, and deployment surface issues.
  • Tag not detected. Check reader interface mode, wiring, power, antenna distance, tag orientation, and whether the tag is supported by the reader.
  • Write fails. Check read-only state, password/write protection, message size, tag formatting, and whether the user moved the tag during the write.
  • Phone opens the wrong app. Check URI scheme, app-link association, MIME type, record order, and whether the OS supports the intended record behavior.
  • Works on the bench but not installed. Retest with the final surface, enclosure, phone case, label overlay, and user tap location.
  • Security review rejects the design. Remove secrets from NDEF, move authorization to the app/backend, and add cryptographic proof where cloning matters.

18.18 Worked Example: Gateway Maintenance Tag Batch

Scenario

A plant maintenance team needs to program NFC labels for 80 gateways. A tap should open the gateway maintenance record, show a short local label, and let the app request authenticated service actions. The labels will be mounted on metal enclosures.

18.18.1 Record Plan

records: 1. URI https://ops.example.invalid/a/gateway- 2. Text Gateway maintenance record validation: host must equal ops.example.invalid asset-id must exist in backend inventory service action requires authenticated technician session physical: on-metal tag construction printed asset ID next to tag for manual fallback

18.18.2 Programming Station Checklist

Prepare batch Export the approved asset list and expected URLs from the inventory system.
Write one tag Encode the URI and Text records, then read it back with both the programming reader and a target phone.
Mount and retest Test the tag after it is installed on the actual enclosure, not only before placement.
Record release Store tag type, batch, reader station, record schema, app version, owner, and replacement process.

18.18.3 Acceptance Criteria

  • Every tag decodes to the expected host and asset ID.
  • The tag does not contain technician credentials, service commands, or private tokens.
  • The app refuses unknown hosts, unexpected record types, and oversized payloads.
  • The final installation passes tap tests with the target phone models and protective cases.
  • A printed asset ID or manual search path exists when NFC fails.

18.19 Knowledge Check

18.20 Quick Check: Safe NFC Write Workflow

18.21 Matching Quiz: Programming Decisions

18.22 Ordering Quiz: Program and Release a Tag

18.23 Summary

  • NFC tag programming is a release workflow: plan, inspect, write, read back, protect, and document.
  • Android, Python, and PN532-based readers can all support tag work, but each needs explicit capacity, write-state, and error handling.
  • NDEF records are useful for interoperability but should be treated as untrusted public input.
  • Tag selection depends on payload size, write lifecycle, environment, phone support, and security needs.
  • Production tags need field evidence from the final mounting surface and target reader devices.

18.24 Key Takeaway

Programming NFC tags requires more than writing bytes: choose the tag, NDEF structure, lock policy, validation path, and update workflow together.

18.25 What’s Next

NFC Real-World Applications Apply tag programming decisions to payment, product, access, and automation workflows.
Lab: NFC Reader Simulation Practice NDEF parsing, tag capability checks, and failure diagnosis without physical hardware.
NFC Security and Alternatives Review cloning, relay risk, secure tags, and when NFC should hand off to other technologies.