ESC/POS-Druck aus dem Browser: Ein Entwicklerhandbuch

Das Browser-Druckproblem

Wenn Sie jemals versucht haben, einen Beleg aus einer Web-App zu drucken, kennen Sie den Schmerz: window.print() öffnet einen Druckdialog, rendert die Seite als PDF und bietet keinerlei Unterstützung für ESC/POS-Befehle wie automatischen Schnitt oder benutzerdefinierte Papierbreite.

Für Thermo-Belegdrucker ist dies ein entscheidender Nachteil. Sie benötigen:

  • Lautloses Drucken – kein Dialog, keine Benutzerinteraktion
  • ESC/POS-Befehle – für automatischen Schnitt, Fettdruck, Ausrichtung, Barcodes
  • Zuverlässige Kodierung – UTF-8 zur richtigen Codepage für Ihren Drucker
  • Plattformübergreifende Unterstützung – Mac, Windows, Linux

Die Lösung ist eine lokale WebSocket-Brücke – eine kleine Hintergrund-App, die auf dem Computer des Benutzers läuft, Druckaufträge von Ihrer Web-App entgegennimmt und rohe ESC/POS-Befehle an den Drucker sendet.


Wie die WebSocket-Brücke funktioniert

Ihre Web-App  →  WebSocket (ws://localhost:8765)  →  Print Agent  →  Thermodrucker

Der Ablauf ist einfach:

  1. Ihre Web-App öffnet eine WebSocket-Verbindung zu ws://localhost:8765
  2. Sie senden eine JSON-Nutzlast, die den Beleg beschreibt
  3. Der Print Agent konvertiert sie in ESC/POS und sendet sie an den Drucker
  4. Der Drucker druckt lautlos – kein Dialog, keine Treiberinteraktion

MenuForma Print Agent implementiert diese Brücke. Er ist kostenlos, Open Source und läuft auf Mac, Windows und Linux.


API-Referenz

Verbindung

const ws = new WebSocket('ws://localhost:8765');

ws.onopen = () => {
  console.log('Print Agent verbunden');
};

ws.onerror = () => {
  console.log('Print Agent läuft nicht');
};

Agent-Status prüfen

Senden Sie einen Ping, um zu überprüfen, ob der Agent läuft:

ws.send(JSON.stringify({ type: 'ping' }));

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  if (data.type === 'pong') {
    console.log('Agent-Version:', data.version);
  }
};

Beleg drucken

const receipt = {
  type: 'print',
  printer: 'auto',   // oder spezifische IP wie '192.168.1.100'
  data: {
    storeName: 'Mein Restaurant',
    storeAddress: 'Hauptstraße 123',
    orderNumber: '#1042',
    tableNumber: 'Tisch 5',
    items: [
      { name: 'Margherita Pizza', qty: 1, price: 14.90 },
      { name: 'Sprudelwasser', qty: 2, price: 3.50 },
    ],
    subtotal: 21.90,
    tax: 1.97,
    total: 23.87,
    paymentMethod: 'Karte',
    footer: 'Vielen Dank für Ihren Besuch!',
  }
};

ws.send(JSON.stringify(receipt));

React-Integrationsbeispiel

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); // erneut versuchen
      };
      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-Integration

Für Shopify-Shops können Sie den Druck über einen Bestell-Webhook oder über eine Browser-Erweiterung auslösen:

```javascript
// In Ihrer Shopify-Storefront oder Admin-Erweiterung
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,
      }
    }));
  };
}

Drucker-Konfiguration

Das Feld "printer" in der Druck-Payload akzeptiert:

Wert Beschreibung
"auto" Verwenden Sie den in den Print Agent-Einstellungen konfigurierten Drucker
"192.168.1.100" Direktverbindung zu einem Netzwerkdrucker über IP
"USB" Verwenden Sie den ersten erkannten USB-Drucker

Fehlerbehandlung

ws.onmessage = (event) => {
  const response = JSON.parse(event.data);
  
  if (response.type === 'print_success') {
    console.log('Erfolgreich gedruckt');
  } else if (response.type === 'print_error') {
    console.error('Druck fehlgeschlagen:', response.error);
    // Fallback-UI anzeigen oder erneut versuchen
  }
};

Erkennen, ob Print Agent installiert ist

Bevor Sie die Druckfunktion in Ihrer Benutzeroberfläche anzeigen, prüfen Sie, ob der Agent ausgeführt wird:

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);
    };
  });
}

// Verwendung
const agentAvailable = await isPrintAgentAvailable();
if (!agentAvailable) {
  // Download-Aufforderung anzeigen
  window.open('/print-agent', '_blank');
}

Print Agent herunterladen

MenuForma Print Agent ist kostenlos und für Mac, Windows und Linux verfügbar. Es unterstützt USB-, Netzwerk- und Bluetooth-Thermodrucker und implementiert die vollständige WebSocket-API, die in diesem Leitfaden beschrieben wird.

Für die vollständige API-Dokumentation und den Open-Source-Code besuchen Sie die Print Agent Seite.

Related Articles

MenuForma Products