Impressão ESC/POS a partir do navegador: Um guia para desenvolvedores

O Problema da Impressão no Navegador

Se você já tentou imprimir um recibo de um aplicativo da web, conhece a dor: window.print() abre uma caixa de diálogo de impressão, renderiza a página como um PDF e não tem suporte para comandos ESC/POS, como corte automático ou largura de papel personalizada.

Para impressoras térmicas de recibos, isso é um obstáculo. Você precisa:

  • Impressão silenciosa — sem diálogo, sem interação do usuário
  • Comandos ESC/POS — para corte automático, texto em negrito, alinhamento, códigos de barras
  • Codificação confiável — UTF-8 para a página de código correta da sua impressora
  • Suporte multiplataforma — Mac, Windows, Linux

A solução é uma ponte WebSocket local — um pequeno aplicativo em segundo plano que é executado no computador do usuário, aceita trabalhos de impressão do seu aplicativo da web e envia comandos ESC/POS brutos para a impressora.


Como a Ponte WebSocket Funciona

Seu Aplicativo Web → WebSocket (ws://localhost:8765) → Agente de Impressão → Impressora Térmica

O fluxo é simples:

  1. Seu aplicativo da web abre uma conexão WebSocket para ws://localhost:8765
  2. Você envia um payload JSON descrevendo o recibo
  3. O Agente de Impressão o converte para ESC/POS e o envia para a impressora
  4. A impressora imprime silenciosamente — sem diálogo, sem interação com o driver

MenuForma Print Agent implementa esta ponte. É gratuito, de código aberto e funciona em Mac, Windows e Linux.


Referência da API

Conexão

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

ws.onopen = () => {
  console.log('Agente de Impressão conectado');
};

ws.onerror = () => {
  console.log('Agente de Impressão não está em execução');
};

Verificar Status do Agente

Envie um ping para verificar se o agente está em execução:

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

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  if (data.type === 'pong') {
    console.log('Versão do Agente:', data.version);
  }
};

Imprimir um Recibo

const receipt = {
  type: 'print',
  printer: 'auto',   // ou IP específico como '192.168.1.100'
  data: {
    storeName: 'Meu Restaurante',
    storeAddress: 'Rua Principal, 123',
    orderNumber: '#1042',
    tableNumber: 'Mesa 5',
    items: [
      { name: 'Pizza Margherita', qty: 1, price: 14.90 },
      { name: 'Água com Gás', qty: 2, price: 3.50 },
    ],
    subtotal: 21.90,
    tax: 1.97,
    total: 23.87,
    paymentMethod: 'Cartão',
    footer: 'Obrigado por jantar conosco!',
  }
};

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

Exemplo de Integração React

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); // tentar novamente
      };
      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 };
}

Integração Shopify

Para lojas Shopify, você pode acionar a impressão a partir de um webhook de Pedido ou de uma extensão de navegador:

// No seu storefront Shopify ou extensão de administrador
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,
      }
    }));
  };
}

Configuração da Impressora

O campo "printer" no payload de impressão aceita:

Valor Descrição
"auto" Usar a impressora configurada nas configurações do Print Agent
"192.168.1.100" Conectar diretamente a uma impressora de rede por IP
"USB" Usar a primeira impressora USB detectada

Tratamento de Erros

ws.onmessage = (event) => {
  const response = JSON.parse(event.data);
  
  if (response.type === 'print_success') {
    console.log('Printed successfully');
  } else if (response.type === 'print_error') {
    console.error('Print failed:', response.error);
    // Mostrar UI de fallback ou tentar novamente
  }
};

Detectando se o Print Agent está Instalado

Antes de mostrar a funcionalidade de impressão na sua UI, verifique se o agente está em execução:

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

// Uso
const agentAvailable = await isPrintAgentAvailable();
if (!agentAvailable) {
  // Mostrar prompt de download
  window.open('/print-agent', '_blank');
}

Baixar Print Agent

MenuForma Print Agent é gratuito e está disponível para Mac, Windows e Linux. Ele suporta impressoras térmicas USB, de rede e Bluetooth, e implementa a API WebSocket completa descrita neste guia.

Para a documentação completa da API e o código-fonte aberto, visite a página do Print Agent.

Related Articles

MenuForma Products