Custom NDEF Records: Beyond URL and Text
URL and Text are just two of the record types NDEF supports. Custom records — MIME and External Type — are how Smart Posters, Bluetooth pairing tags, and app-specific data actually get built. Here's what's under the hood, and how to write one yourself with NFCore.
What it is (one-paragraph answer)
A custom NDEF record is any NFC record that skips the NFC Forum's "well-known" types — no plain URL, no Text record. Instead it leans on one of two self-service mechanisms: a MIME record (tagged with a standard or invented MIME string) or an External Type record (tagged with a domain you control, like com.yourapp:sensor-reading). If you've written a URL or Wi-Fi record with NFCore before, you've already used the well-known side of NDEF. Custom records are the other half — the mechanism behind Smart Posters, Bluetooth pairing tags, and whatever app-specific data a tag needs to carry.
How it actually works
Every NDEF record opens with a header byte called the Type Name Format (TNF). It tells a reader which namespace the record's type string belongs to. For a custom record, you pick one of two TNF values:
TNF_MIME_MEDIA— the type is a MIME string, either a standard one (liketext/vcard) or one you invent for your own app.TNF_EXTERNAL_TYPE— the type is a reverse-domain string, likecom.yourapp:config, that only you're expected to use.
Android's NdefRecord class hands you createMime() and createExternal() static methods, so you never assemble the header bytes by hand — just supply the MIME string or domain:type string plus a byte payload. iOS's Core NFC does the same job with an NFCTypeNameFormat enum: .media for MIME records and .nfcExternal for External Type records. Write a record with TNF_EXTERNAL_TYPE on Android, read it back on iOS with .nfcExternal, and it round-trips fine — as long as both sides agree on the exact domain:type string. That agreement is the whole contract. No registry, no approval step.
Where you'll see it
The most common example is the Smart Poster record type, which isn't really one custom record but a small composition of well-known ones — a URI record plus Text and Action records — telling a reader whether to open a link, save it, or act on it in the background. Custom records proper show up when a product needs structured data a well-known type just can't express. A Bluetooth speaker's tap-to-pair tag, for instance, stores a MIME record with a documented type like application/vnd.bluetooth.ep.oob, so a single tap starts pairing instead of a trip through the Bluetooth settings menu. That's the same static handover mechanism the NFC Forum defined for passive tags — no power, no negotiation, just a record any reader can pick up on contact. It's a close cousin to how Apple Pay and Google Pay use NFC: a tightly specified custom payload riding on the same NFC link that also carries a plain Text record.
Tips, gotchas, and a quick how-to with NFCore
Pick an External Type domain you actually control — your app's package name, or a domain you own — rather than guessing at something generic another developer might land on too. And remember: an unencrypted tag's raw bytes, custom record included, are readable by anyone with a compatible phone. Worth a look at what's actually at risk when a tag is readable by anyone before you put anything sensitive on one.
Want to try it? Open NFCore's raw write mode, choose a custom record, enter a domain:type string you control (say, com.yourname:note), and write a short text payload. Read the tag back right away to confirm the type string and payload match what you wrote. That round-trip check is the fastest way to catch a typo in the domain:type string before it ends up on ten tags instead of one. You can grab NFCore for iOS or Android from nfcore.app if you want to test this on your own tags.
Frequently Asked Questions
What's the difference between a MIME record and an External Type record?
A MIME record's type is a standard MIME string (like application/vnd.bluetooth.ep.oob), so any app that already handles that MIME type elsewhere can claim it. An External Type record's type is a reverse-domain string you invent yourself (like com.yourapp:config), guaranteeing it won't collide with anyone else's record type.
Can I read a custom NDEF record written by an Android app on iOS, or vice versa?
Yes — TNF_EXTERNAL_TYPE on Android and .nfcExternal in Core NFC on iOS describe the same on-wire format. As long as both apps agree on the exact domain:type string, the record round-trips correctly across platforms.
Do I need NFC Forum approval to invent my own record type?
No. External Type and MIME records are both self-service — you don't register them with the NFC Forum. That's the entire point of the domain-prefix convention: own the domain or package name you're using, and no registry or approval step is required.
Conclusion
Custom NDEF records aren't some advanced, gated format — they're the same MIME or External Type mechanism every Bluetooth pairing tag and app-specific NFC feature already relies on, with nothing standing between you and writing one. Once you're comfortable building a single custom record, stacking several together — the way Smart Poster combines a URI, Text, and Action record — is just that same building block, repeated.