I built an auto-printer for warehouse tickets, controlled by a Raspberry Pi. It worked, but the approach had enough friction that I eventually replaced it with a browser tab.
The problem
Warehouse tickets need printing at set times each day. The manual process was: open the internal tool, select the batch, hit print. Easy to forget, and missed prints cause delays downstream.
V1: the dedicated agent
The first solution was a Node.js app on a Raspberry Pi, physically connected to the printer. It had its own document renderer, its own PDF pipeline (Puppeteer for HTML-to-PDF, CUPS for printing), and its own schedule via crontab.
It printed. But it also meant:
- A separate piece of hardware to maintain, update, and troubleshoot when the network dropped
- A duplicate rendering pipeline that could drift from the one in the web app
- No admin interface. Changing the schedule meant SSH-ing into the Pi’s Linux OS and editing a crontab
- No visibility. History was a JSON file on the Pi’s filesystem
Failures were silent - there was no alerting or batch history to check.
The insight
The warehouse operations dashboard already renders tickets and has a print button. The only thing stopping it from being automatic was the browser’s print dialog.
Chrome has a --kiosk-printing flag. When launched with this flag, window.print() sends directly to the default printer with no dialog.
V2: the browser tab
Instead of a separate system, auto-print became a feature of the existing app:
- The app checks configured schedule times every 30 seconds
- When a schedule fires, it fetches fresh data, renders documents using the same components as manual printing, and calls
window.print() - Chrome’s kiosk-printing mode handles the rest
The schedule, toggle, and history all live in an admin page. No SSH, no separate hardware.
Auto-print lock
Multiple people might have the app open. Only one should print. The app uses a simple heartbeat lock: the active tab pings every 30 seconds, the lock expires after two minutes without a heartbeat. Other tabs show a standby indicator with an option to claim the lock manually.
Kiosk detection
If someone opens the app in a normal Chrome window (without --kiosk-printing), auto-print would trigger a print dialog every time a schedule fires. Not ideal.
Before printing, the app runs a quick check: trigger window.print() in a hidden iframe and time how long it takes. In kiosk mode it completes instantly. If a dialog appears and blocks, the timer exceeds the threshold and auto-print disables itself with a warning.
What changed
The Pi did one thing: print on a schedule. But it did it with a completely different print flow - its own renderer, its own PDF conversion, its own printer integration - all of which had issues. The browser-based version does the same thing by reusing the print logic that already worked.
Less hardware to maintain, and the same output comes out of the same printer.
I built a standalone test to validate the kiosk-printing approach before integrating it into the main app.