Have you ever been frustrated by the lack of seamless, silent printing options for POS systems in web applications? Imagine running a busy store and having to click “Print” for every single receipt or label—talk about a productivity nightmare! Recently, I faced exactly this issue with a client’s project, where they needed a browser-based web app that could print receipts and labels instantly, without user prompts. Off-the-shelf solutions like JSPM and QZ Tray were tempting, but their subscription costs would have blown our budget. So, I rolled up my sleeves and thought, why not create something similar myself?
The result: PrinterWebSocket! A Python-powered, WebSocket-based framework that connects web apps directly to POS printers using Javascript. Curious how it works? Let’s dive in!
Image of a POS Software with a Thermal Printer - Dall-E |
The Challenge: Achieving True Silent Printing
Now, why was silent printing such a big deal here?
When you’re running a POS system, the last thing you want is for a print dialogue box to pop up every time you hit “Print.” You just want the receipt to print instantly, with zero interruptions. Silent printing takes away that hassle, making operations faster and smoother—crucial in high-traffic retail.
Sure, solutions like JSPM and QZ Tray offer silent printing, but they come with recurring fees. Knowing I could potentially build a free and customizable version, I set out to build an open-source alternative that could bring this feature to life for web-based POS systems.
PrinterWebSocket in Action: The Web-to-Printer Connection
Creating PrinterWebSocket meant establishing a reliable communication bridge between the web app and the printer. The solution? WebSockets! With WebSockets, we get a two-way connection that lets the client (the web app) talk to the server (our printer host) in real time.
Here’s the basic workflow:
- Establish Connection: The web app connects to the Python WebSocket server, enabling real-time communication.
- List Available Printers: With one simple WebSocket message, the client can see a list of all connected printers.
- Check Printer Status: Need to know if the printer is out of paper? Or offline? Just send a message to check its status, and PrinterWebSocket returns an update in seconds.
- Send Print Jobs (Silently): Now for the exciting part—silent printing! The web app can send a print job directly to the printer without any extra prompts, just a smooth, uninterrupted experience.
- Real-Time Monitoring with a GUI: For added control, the server features a GUI that shows connected clients, recent print jobs, and server activity. It’s like mission control for your printing needs!
And just like that, the web app now has full control over the printer, seamlessly printing receipts, labels, or whatever else the POS system requires!
Here below is the workflow of the PrinterWebSocket framework.
Here there are two major components, one is the javascript client, and the other is the Python server. The server establishes a websocket server and manages print requests and other information requests. The client connects to the websocket server and sends commands for print, status printer list, or other information.
How to Start?
To begin with this framework, you need to include the PrinterWebsocket.js in your web application or webpage.
Then we have to initialize the PrinterWebsocket Class.
// Initialize WebSocket connection and wait for it to establish PrinterWebSocket.initialize("ws://localhost:8765") .then(() => { console.log('Connected to Printer Server - ' + PrinterWebSocket.getServerAddress()); // Fetch the printers after connection is established console.log('Fetched Printer List'); return PrinterWebSocket.fetchPrinters(); }) .then((printers) => { // Populate printer dropdown with fetched printers console.log('Printer List Updated'); populatePrinterDropdown(printers); console.log("Array of printers:", printers); // Log the printer array }) .catch((error) => { console.error("Error occurred:", error); });
After a successful initialization, we are ready for printing,
var paperSize = printerPaperSelect.value; // Get selected paper size in 80*40 format (mm scale) var tsplData = ` SIZE ${paperSize.replace('*', ' mm, ')} mm GAP 3 mm, 0 mm CLS TEXT 25,60,"4",0,1,1,"26 OCT T 07" TEXT 25,120,"5",0,1,1,"105570553" TEXT 25,180,"1",0,1,1,"Liopetra" PRINT 1,1 `; PrinterWebSocket.print(printerName, tsplData);
Here in above code, I've written printer commands in TSPL which was supported by my clients printer.
The Core API: Making Web-to-Printer Interaction Simple and Fun
To make the setup user-friendly, I created a straightforward WebSocket API that the JavaScript client could call. No complicated commands—just clear instructions for each task. Here’s a sneak peek:
- Listing Printers: Sending this below message to the websocket returns a list of all available printers.
{ "call": "printers.find", "uid": "unique-id" }
- Checking Status: Need to know if a printer’s online? Send this command, and get instant feedback.
{ "call": "printerStatus", "PrinterName": "Printer1", "uid": "unique-id"}
- Sending Print Jobs: When it’s go-time, this command sends raw print commands to the printer in a silent, no-prompt fashion:
{ "call": "print",
"uid": "unique-id"
"params": { "printer": {"name": "Printer1"}, "data": ["TSPL Commands"] } }
These commands made it fun to build, test, and watch the magic of silent printing in action!
Facing the Hurdles: Reverse-Engineering QZ Tray and Solving Compatibility Issues
Every project has its hurdles, right? For PrinterWebSocket, the biggest challenges were understanding how to bypass the “permission prompt” typical of printers and getting status updates from different printer models. By examining QZ Tray’s structure, I learned a lot about secure printer communication over WebSockets.
Another challenge was handling various print commands (TSPL, ZPL, etc.), which aren’t always compatible across all printers. PrinterWebSocket currently supports TSPL, but I’m working on extending it to more formats to increase compatibility.
Working with WebSockets in Python also presented a learning curve. However, by building from scratch, I can gain full control over the server behavior, error handling, and client monitoring, giving me the freedom to improve and customize as needed over the whole system.
A Sample Implementation, working in static HTML |
Why PrinterWebSocket? An Open, Free Alternative with Room to Grow
PrinterWebSocket is more than a workaround—it’s a flexible, open-source solution that matches some features of paid alternatives. With no monthly fees or licenses, it’s a budget-friendly choice for businesses.
PrinterWebSocket is ideal for anyone looking to add printing capabilities to a web-based POS system without breaking the bank. And because it’s open-source, developers can tinker with it, extend it, and create their own custom print workflows.
What’s Next: Building on the PrinterWebSocket Foundation
I hope the journey doesn’t stop here, for this project, next on the roadmap is expanding PrinterWebSocket to support even more printer models and formats, adding extra commands, and improving compatibility with both Windows and macOS.
If you’re as excited about POS automation as I am, PrinterWebSocket could be your next DIY adventure. I'd be happy to work on that with others! Let’s see where we can take this idea together! If you are interested in contributing, drop me a line, and let’s make this more accessible for everyone.
PrinterWebSocket started as a challenge to bring silent printing to the web without subscription fees, but it’s while building it, quickly grew into a robust solution that can help streamline POS workflows. My clients were happy with the saved bucks and still had working software.
As far, as all the solutions are working from localhost, printer sharing using websocket hasn't come into my mind yet, because of the security issues. But building it taught me that there’s always room for innovation, even in seemingly small features. Plus, it’s an open invitation to developers everywhere to get involved, improve it, and make printing easier and more efficient for web applications everywhere.