Het Browser Afdrukprobleem
Als je ooit hebt geprobeerd een bon af te drukken vanuit een web-app, ken je de pijn: window.print() opent een afdrukvenster, rendert de pagina als een PDF en heeft geen ondersteuning voor ESC/POS-commando's zoals automatisch snijden of een aangepaste papierbreedte.
Voor thermische bonprinters is dit een dealbreaker. Je hebt nodig:
- Stil afdrukken — geen dialoogvenster, geen gebruikersinteractie
- ESC/POS-commando's — voor automatisch snijden, vetgedrukte tekst, uitlijning, barcodes
- Betrouwbare codering — UTF-8 naar de juiste codepagina voor je printer
- Cross-platform ondersteuning — Mac, Windows, Linux
De oplossing is een lokale WebSocket-brug — een kleine achtergrond-app die op de computer van de gebruiker draait, afdruktaken van je web-app accepteert en ruwe ESC/POS-commando's naar de printer stuurt.
Hoe de WebSocket-brug werkt
Your Web App → WebSocket (ws://localhost:8765) → Print Agent → Thermal Printer
De stroom is eenvoudig:
- Je web-app opent een WebSocket-verbinding met ws://localhost:8765
- Je stuurt een JSON-payload met de beschrijving van de bon
- Print Agent converteert deze naar ESC/POS en stuurt deze naar de printer
- De printer drukt stil af — geen dialoogvenster, geen driverinteractie
MenuForma Print Agent implementeert deze brug. Het is gratis, open-source en draait op Mac, Windows en Linux.
API Referentie
Verbinding
const ws = new WebSocket('ws://localhost:8765');
ws.onopen = () => {
console.log('Print Agent verbonden');
};
ws.onerror = () => {
console.log('Print Agent draait niet');
};
Agentstatus controleren
Stuur een ping om te controleren of de agent draait:
ws.send(JSON.stringify({ type: 'ping' }));
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'pong') {
console.log('Agentversie:', data.version);
}
};
Een bon afdrukken
const receipt = {
type: 'print',
printer: 'auto', // of specifiek IP zoals '192.168.1.100'
data: {
storeName: 'My Restaurant',
storeAddress: '123 Main St',
orderNumber: '#1042',
tableNumber: 'Table 5',
items: [
{ name: 'Margherita Pizza', qty: 1, price: 14.90 },
{ name: 'Sparkling Water', qty: 2, price: 3.50 },
],
subtotal: 21.90,
tax: 1.97,
total: 23.87,
paymentMethod: 'Card',
footer: 'Bedankt voor het dineren bij ons!',
}
};
ws.send(JSON.stringify(receipt));
React Integratie Voorbeeld
import { useEffect, useRef, useCallback, useState } from 'react';
function usePrintAgent() {
const wsRef = useRef(null);
const [connected, setConnected] = useState(false);
useEffect(() => {
const connect = () => {
const ws = new WebSocket('ws://localhost:8765');
ws.onopen = () => setConnected(true);
ws.onclose = () => {
setConnected(false);
setTimeout(connect, 3000); // opnieuw proberen
};
wsRef.current = ws;
};
connect();
return () => wsRef.current?.close();
}, []);
const print = useCallback((receiptData) => { if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) { throw new Error('Print Agent not connected'); } wsRef.current.send(JSON.stringify({ type: 'print', data: receiptData })); }, []);
return { connected, print }; }
---
## Shopify-integratie
Voor Shopify-winkels kunt u het afdrukken activeren via een Order-webhook of via een browserextensie:
```javascript
// In uw Shopify storefront of admin-extensie
async function printShopifyOrder(order) {
const ws = new WebSocket('ws://localhost:8765');
ws.onopen = () => {
ws.send(JSON.stringify({
type: 'print',
data: {
storeName: order.shop_name,
orderNumber: order.name,
items: order.line_items.map(item => ({
name: item.title,
qty: item.quantity,
price: parseFloat(item.price),
})),
total: parseFloat(order.total_price),
paymentMethod: order.payment_gateway,
}
}));
};
}
Printerconfiguratie
Het veld "printer" in de print-payload accepteert:
| Waarde | Beschrijving |
|---|---|
| "auto" | Gebruik de printer geconfigureerd in de Print Agent-instellingen |
| "192.168.1.100" | Maak rechtstreeks verbinding met een netwerkprinter via IP |
| "USB" | Gebruik de eerst gedetecteerde USB-printer |
Foutafhandeling
ws.onmessage = (event) => {
const response = JSON.parse(event.data);
if (response.type === 'print_success') {
console.log('Succesvol afgedrukt');
} else if (response.type === 'print_error') {
console.error('Afdrukken mislukt:', response.error);
// Toon fallback UI of probeer opnieuw
}
};
Detecteren of Print Agent is geïnstalleerd
Voordat u de printfunctie in uw gebruikersinterface toont, controleert u of de agent actief is:
async function isPrintAgentAvailable() {
return new Promise((resolve) => {
const ws = new WebSocket('ws://localhost:8765');
const timeout = setTimeout(() => {
ws.close();
resolve(false);
}, 1000);
ws.onopen = () => {
clearTimeout(timeout);
ws.close();
resolve(true);
};
ws.onerror = () => {
clearTimeout(timeout);
resolve(false);
};
});
}
// Gebruik
const agentAvailable = await isPrintAgentAvailable();
if (!agentAvailable) {
// Toon downloadprompt
window.open('/print-agent', '_blank');
}
Print Agent downloaden
MenuForma Print Agent is gratis en beschikbaar voor Mac, Windows en Linux. Het ondersteunt USB-, netwerk- en Bluetooth-thermische printers en implementeert de volledige WebSocket API die in deze handleiding wordt beschreven.
Voor volledige API-documentatie en de open-source code, bezoek de Print Agent-pagina.
Related Articles
- Personeelstekort in de Horeca tot 2040: Hoe Technologie de Druk Verlicht
- Digitalisering als Noodzaak: Waarom Nederlandse MKB-Restaurants in 2026 Moeten Innoveren
- Horeca Vooruitblik 2026: Stijgende Kosten en Schulden Vragen om Slimme Efficiëntie