3 min read

How We Monitor a Tool Running on Multiple Physical Kiosks at Once

We extended our desktop-tool telemetry to group events by physical kiosk, and fixed a real timezone gotcha along the way.

telemetrymonitoringpostgrestimezonesengineering

Our telemetry system for client-facing desktop tools was built for a simple case: one install per client, running on a single machine. That was true for our Python-based financial reconciliation tool, the first use case for this system (we cover the details in How we automated financial reconciliation with Python and PDF). Public endpoints receive usage events and error reports, and the admin dashboard shows the state of each installation. A new client broke that assumption.

The challenge: one tool, many kiosks

The interactive 3D avatar we built for a brand activation company that operates at malls and corporate trade shows (we cover the full solution in the 3D interactive avatar case for malls and trade shows) doesn't run on a single machine. The same tool runs simultaneously on multiple physical kiosks, spread across different locations. Per-installation telemetry didn't make sense here: the same tool runs at the same time across multiple kiosks, and each kiosk needed to show up separately in the dashboard.

How we extended the existing telemetry

Instead of building a parallel system, we extended what already existed. The telemetry page in the admin dashboard now shows a Totens (N) table, grouping incoming events by kiosk identifier. This only happens when a specific tool opts into that grouping: it's a per-tool configuration flag, and today only one tool uses it.

Active days and what "delayed" means

The kiosk table exposes two pieces of information with different origins. "Active days" is self-reported: the kiosk itself counts and reports how many days it has been active, and the server just passes that number through. The "delayed" status, on the other hand, is calculated by the server from the last event seen: if more than an hour has passed without receiving any event from that kiosk, it shows up as delayed on the dashboard. It's a simple division of responsibility: the kiosk knows its own history, the server only knows whether it's still listening to that kiosk.

The gotcha: timestamp without timezone

The "delayed" calculation hid a problem that only surfaced in local development. The driver we use to connect to Neon's Postgres (over HTTP) returns timestamps without timezone information. In production, on Vercel, this causes no harm: the server runs in UTC, and a timezone-less timestamp interpreted as UTC is a genuinely correct UTC timestamp. In local development, in the Brasília timezone (UTC-3), that same timezone-less timestamp was interpreted as local time, and the "delayed" calculation came out with a 3-hour offset.

It never became a bug in production, but it was a real gotcha during local validation, the kind that only shows up when the tester's machine timezone diverges from the production server's timezone.

This is the same system that supports the interactive 3D avatar in production today, built on the same foundation that already supported financial reconciliation before it. If your operation also depends on a tool running across multiple locations at once, and you need to know with confidence when one of them stops responding, tell us about your context.

Have a validated idea, process to automate, or product to build?

Get in touch