A lightweight NFC card reader agent with WebSocket broadcasting capabilities. Reads and writes NDEF formatted data from NFC tags and broadcasts to connected clients in real-time. This is for use for the NFC-related functionality integrated into the Davi platform.
Hardware Readers: ACR122U, ACR1252U, and other PC/SC-compatible readers
Remote Devices: Any NFC-capable device that connects via the Device API, including:
Card Types: MIFARE Classic (incl. NDEF formatting and custom keys), DESFire, Ultralight, NTAG21x, ISO14443-4 Type 4A (experimental)
Download pre-built binaries from releases, or build from source:
git clone https://github.com/dotside-studios/davi-nfc-agent.git
cd davi-nfc-agent
go build .
./davi-nfc-agent
See the Installation Guide for platform-specific setup and troubleshooting.
./davi-nfc-agent # System tray mode (default)
./davi-nfc-agent -version # Print version information and exit
./davi-nfc-agent -device "ACS ACR122U" # Use a specific PC/SC reader by name
./davi-nfc-agent -device-port 9480 # Custom agent server port (default 9470, serves both devices and clients)
./davi-nfc-agent -api-secret mysecret # Set the API authentication secret
./davi-nfc-agent -auto-tls=false # Disable automatic TLS certificate management
./davi-nfc-agent -cert cert.pem -key key.pem # Use your own TLS certificate
./davi-nfc-agent -config-dir ./config # Override the config directory
By default the agent generates and persists a TLS certificate and an API secret
under a platform-specific config directory, so paired devices keep working
across restarts. Run ./davi-nfc-agent -help for the full list of flags.
The agent runs a single server on one port that fills both roles, plus a bootstrap helper:
/ws?mode=device) and client applications (via /ws) on the same port. The port is configurable via -device-port.Use the included client library for browser or Node.js applications.
const client = new NFCClient('http://localhost:9470');
client.on('tagData', (data) => {
console.log('Card:', data.uid, data.text);
});
await client.connect();
// Write to a card
await client.write({
records: [{ type: 'text', content: 'Hello, NFC!' }]
});
Connect to the agent’s client endpoint via WebSocket using OkHttp or similar.
val client = OkHttpClient()
val request = Request.Builder()
.url("ws://192.168.1.100:9470/ws")
.build()
val listener = object : WebSocketListener() {
override fun onMessage(webSocket: WebSocket, text: String) {
val msg = JSONObject(text)
if (msg.getString("type") == "tagData") {
val payload = msg.getJSONObject("payload")
Log.d("NFC", "Card UID: ${payload.getString("uid")}")
}
}
}
client.newWebSocket(request, listener)
See API Reference for the full WebSocket protocol.
Connect your smartphone to the agent using the NFCDeviceClient.
const device = new NFCDeviceClient('ws://192.168.1.100:9470');
device.on('registered', ({ deviceID }) => {
console.log('Registered as:', deviceID);
});
await device.connect();
// Start scanning with WebNFC (Chrome on Android)
if (NFCDeviceClient.isWebNFCSupported()) {
await device.startNFCScanning();
}
Connect directly without a client library. See API Reference for all message types.
const ws = new WebSocket('ws://localhost:9470/ws');
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === 'tagData') {
console.log('Card UID:', msg.payload.uid);
}
};
// Write request
ws.send(JSON.stringify({
type: 'writeRequest',
payload: {
records: [{ type: 'text', content: 'Hello!' }]
}
}));
The agent’s modular NFC layer supports adding custom readers and tag types beyond the built-in PC/SC and smartphone support. See Extending NFC Support to integrate your own hardware or protocols.
See CONTRIBUTING.md for development setup, cross-compilation, and guidelines.
Copyright © 2025-2026 Ned Palacios and Dotside Studios. All rights reserved.