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:
- Seu aplicativo da web abre uma conexão WebSocket para ws://localhost:8765
- Você envia um payload JSON descrevendo o recibo
- O Agente de Impressão o converte para ESC/POS e o envia para a impressora
- 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
- Fim da exclusividade digital: Nova lei em São Paulo exige cardápios físicos além do QR Code
- A digitalização como diferencial: O futuro da restauração em Portugal em 2025
- Inteligência Artificial e Dados: A revolução na gestão de restaurantes brasileiros em 2026