Print a Receipt from JavaScript Without a Printer Driver
You have a Node.js backend or a browser app and a thermal receipt printer, and you want a receipt to come out when an order is placed. No print dialog, no driver on every machine, no hand-built ESC/POS byte arrays. This is the shortest path.
Why the usual approaches hurt
- window.print(): needs an OS driver for the printer on every machine, a person to click the dialog (or a kiosk flag), and gives you CSS-level control over a receipt at best.
- Raw ESC/POS from Node (node-thermal-printer, escpos): works when the server is on the same LAN as the printer. It is not, once you deploy to a cloud host. You also own encoding, image dithering, QR generation and every vendor quirk.
- Local agent with a self-signed certificate (QZ Tray style): a Java app, a trust prompt or a paid signing certificate, and a per-machine install to maintain.
How ReceiptKit does it
A free bridge (Windows, macOS or a Raspberry Pi image) sits on the printer's network and holds a push connection to ReceiptKit. Your JavaScript sends JSON: which printer, which template, and the order data. ReceiptKit renders the receipt and the bridge speaks Star, Epson or generic ESC/POS to the printer over Ethernet or USB. The only driver anywhere is Epson's APD for Epson USB printers on Windows; Star, generic ESC/POS, Raspberry Pi and macOS need none.
One-time setup: sign up, install the bridge, design a template in the dashboard (or start from the gallery), copy the printer endpoint and template id. About ten minutes. Then:
From a server (Node.js)
// Node.js, Next.js route, serverless function, etc.
// Uses your SECRET key — never ship this to a browser.
const res = await fetch("https://www.receiptkit.io/api/bridge/print", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RECEIPTKIT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
printerEndpoint: "tcp:00:11:62:32:5a:2a", // from Dashboard → Devices
templateId: "your-template-id", // from Dashboard → Templates
data: {
storeName: "Corner Cafe",
orderNumber: "1042",
items: [{ name: "Latte", qty: 2, price: "4.50" }],
total: "9.00",
},
}),
});
const result = await res.json();
if (!res.ok) throw new Error(result.error);
// result.success === true; the receipt is printing.Add waitForResult: true to block until the bridge confirms the paper moved, or drawer: "END" to kick a cash drawer after the cut. Full parameter list in the API reference.
From a browser or React app
Browser code uses the public key, which can only print, never read your account. Install the package with npm install receiptkit.
// Browser or React app, using the PUBLIC key (rk_pub_...).
import { ReceiptKitSession } from "receiptkit/http";
const session = new ReceiptKitSession({
apiKey: "rk_pub_your_public_key",
orgId: "your-org-id",
printerEndpoint: "tcp:00:11:62:32:5a:2a",
templateId: "your-template-id",
});
await session.print({
data: { storeName: "Corner Cafe", total: "9.00" },
});For live printer status (online, cover open, paper out) and sub-second push printing straight to the bridge, use the MQTT client and React hooks in the same package. See the JavaScript SDK guide.
What you do not have to handle
- ESC/POS, StarPRNT or Star Raster command sets and the differences between them.
- Fonts, alignment, bold, double-height, QR codes and barcodes: they are template properties.
- 58 mm versus 80 mm rolls: set the width per printer, or pass
dotWidth. - Printers behind NAT: the bridge connects out, nothing is opened on the router.
- Retries and a print history: every job shows in the dashboard with its result.
If you would rather keep the print dialog
For a counter PC with the printer installed as a normal Windows or Mac printer, ReceiptKit's browser printing renders the same template in the page and opens the OS print dialog, no bridge required. It ships today inside the WooCommerce plugin.