Skip to content
All articles

What an NFC Attendance System Actually Has to Handle

8 min read

I built an NFC-based attendance system for lecturers and published the work in the International Journal of Computer Science Engineering. The premise is the easiest sell in software: replace a paper sheet passed around a room with a card and a reader. Tap, recorded, done.

The tapping part took a weekend. Everything that made it usable took the rest of the project, and almost none of it was about NFC. What follows is the part that isn't in the tutorials — because the tutorials all stop at "we read the card ID", which is the beginning of the problem rather than the end of it.

What the hardware actually gives you

NFC is short-range radio at 13.56 MHz, and short really does mean short — the system I built read reliably within about 7 cm, across roughly a 300° arc around the reader.

That range is a feature, not a limitation. A long-range system reads cards that are merely nearby: someone walking past the door, a card in a bag on the next desk. Having to deliberately present the card to the reader is what makes the record mean something — the physical constraint is doing part of your data integrity for you.

The angle matters more than people expect. If a reader only works when the card is presented flat and square, everyone learns to fumble, and a queue forms. Wide angular tolerance is the difference between a device people tap without thinking and one they resent.

The card ID is not an identity

Here is the design mistake to avoid, and it is the one nearly every tutorial walks you into.

The obvious schema is to store the card's UID in the person's record and look them up by it. It works immediately, and it means the card is the person. Then someone loses a card. Now you either edit a person's identity to fix a lost-property problem, or you re-issue the same UID, which you can't.

Model the card as a separate thing that is assigned to a person for a period of time. A card has a UID, an owner, an issued date and optionally a revoked date. Now losing a card is a two-minute operation — revoke it, assign a new one — history stays intact because past attendance records point at the person rather than the card, and a found card that was revoked last month correctly does nothing.

This is five extra minutes of schema design at the start and it is the difference between a system that survives contact with an institution and one that doesn't.

A tap is a claim, not a fact

The uncomfortable truth of any card-based attendance system: it records that a card was presented, not that a person was there. Cards can be handed to a colleague. That's not a bug you can fix in software, and pretending otherwise is how you get a system that produces confident, wrong data.

Worse, common card types are cloneable. MIFARE Classic's Crypto1 cipher has been comprehensively broken for many years, and the equipment to copy one is inexpensive and widely available. If you assume "has the card" means "is the person", the honest security level is lower than the deployment implies.

Two ways to respond, and choosing deliberately is the point. Accept it — for attendance, where the stakes are administrative and the social cost of being caught is real, a system that raises the effort of cheating from "sign a sheet" to "arrange a conspiracy" may be entirely adequate. Or add a second factor: a PIN, a reader in a location that's hard to reach without being seen, a cross-check against something else.

What you should not do is describe it as proof of presence. Whoever relies on the data deserves to know what it does and doesn't establish.

The reader will be offline

It's a device on the wall of a building. Wi-Fi drops, the switch reboots, someone unplugs it to charge a laptop.

If the reader posts each tap straight to a server and that's the whole design, then every network blip is lost attendance — and the person tapping gets no signal that anything went wrong, so they walk away believing they're recorded.

So: write locally first, sync separately. The tap is persisted on the device the moment it happens, and a background process pushes unsynced records when it can. This makes each record's own timestamp authoritative rather than its arrival time, which is correct anyway — the interesting time is when the person tapped, not when the network recovered.

Give the device a real-time clock with a battery while you're at it. A device that loses time on power failure and comes back at the epoch will happily record a full day of attendance in 1970, and you'll be reconstructing it by hand.

And make sync idempotent. A retry that half-succeeded must not create a second record — give each tap an identifier generated on the device and make the server ignore duplicates. Otherwise the fix for the network problem creates a data problem.

Feedback is the whole user experience

The person tapping cannot see your database. Their only information about whether it worked is what the device does in the next half second.

Sound is doing most of the work here — a distinct tone for accepted, a different one for rejected, audible across a room. An LED helps and isn't enough on its own, because people are already walking away. Whatever the signal, it has to distinguish accepted from read but rejected from nothing happened. Those are three different situations and the third is the one where someone should try again.

Then decide what a second tap means. Someone will double-tap, out of uncertainty or habit. Is that a check-out? A duplicate to ignore? An error? Pick one, make the feedback say which, and handle it — because otherwise every ambiguous record is a support request.

You are now holding attendance data

The output of this system is a precise, timestamped log of when identifiable individuals were physically present in a building. That's a more sensitive dataset than "attendance" makes it sound, and it's worth thinking about before it exists rather than after someone asks for an export.

Decide the retention period and enforce it in code. Decide who can query it and scope those queries — a department head seeing their own staff is a different permission from a global export, and scoping that at the query rather than in the reporting screen is what stops it leaking through the next feature. Log the exports.

The good news, relative to the biometric alternative, is that a card is revocable and a face isn't. If someone's card data is compromised you issue a new card. This is a solid reason to prefer a card over face recognition for this particular problem, and it's the conclusion I came to: the card answered the actual requirement without collecting anything irreplaceable.

The pattern

Almost everything hard here was ordinary systems work: modelling identity so it can change, being honest about what the data proves, surviving an unreliable network, telling a human what just happened, and holding sensitive records carefully.

The NFC part — the part the project is named after — was a weekend. That ratio is not unusual, and expecting it is most of what separates a demo from something an institution can actually run.