Printing

Printing

Keel supports direct printing to thermal label printers and standard document printers. Print shipping labels after picking, generate packing slips on demand, or print receipts at point of sale.

Printing works through QZ Tray, a small desktop app that connects your browser to local printers.

Setting up QZ Tray

QZ Tray must be installed on every workstation that needs to print.

  1. Download from qz.io/download (opens in a new tab)
  2. Run the installer for your platform
  3. Launch QZ Tray (it runs in your system tray)

QZ Tray starts automatically on login.

Connecting printers

Open the Console and go to Settings > Devices. The Console automatically detects QZ Tray and shows available printers.

Default printer

Select your default printer from the dropdown. This printer is used when no specific printer is specified in a print job. Click Test print to verify the connection.

Printer mappings

For larger deployments, define logical printer names in your flows (like "Shipping Label Printer") and map them to physical printers at each workstation. This lets different stations use different hardware while running the same flows.

Mappings appear in Settings > Devices when you have a local project running. If a print job requests an unmapped printer, it falls back to the default.

Printing from flows

Use the interactive.print component to send print jobs:

ctx.ui.interactive.print({
  title: "Shipping Label",
  jobs: [
    {
      type: "zpl",
      data: zplContent,
      printer: "Shipping Label Printer",
    }
  ],
  autoPrint: true,
});

Set autoPrint: true to print immediately when the step loads. Without it, users click a button to trigger the job.

ZPL labels

ZPL (Zebra Programming Language) is the standard for thermal label printers. Most industrial printers from Zebra, Honeywell, and SATO support it.

ctx.ui.interactive.print({
  jobs: [
    {
      type: "zpl",
      data: `^XA
^FO50,50^ADN,36,20^FD${order.reference}^FS
^FO50,100^BCN,100,Y,N,N^FD${order.trackingNumber}^FS
^XZ`,
      printer: "Shipping Label Printer",
    }
  ],
});

The ZPL playground in Settings > Devices lets you test commands and use pre-built templates before adding them to flows.

PDF documents

Print PDF content for pick lists, packing slips, or invoices:

ctx.ui.interactive.print({
  jobs: [
    {
      type: "rawPdf",
      data: pdfBase64Content,
      printer: "Document Printer",
      pageWidth: 1200,   // Width in dots
      pageHeight: 1800,  // Height in dots  
      dpi: 300,
    }
  ],
});

For a 4x6 inch label at 300 DPI: width = 4 × 300 = 1200 dots, height = 6 × 300 = 1800 dots.

Remote files

Print from URLs that are downloaded before printing:

ctx.ui.interactive.print({
  jobs: [
    {
      type: "zpl",
      url: "https://api.carrier.com/labels/12345.zpl",
      printer: "Shipping Label Printer",
    }
  ],
});

Print queue

Every print job is tracked in a queue. Click the menu on the print component to see job status:

StatusMeaning
PendingQueued, waiting to send
PrintingSent to printer
CompleteFinished successfully
ErrorFailed (printer offline, out of paper, etc.)

Troubleshooting

QZ Tray won't connect — Check it's running in your system tray. Try restarting it.

Printer not in list — The printer must be installed in your OS first. Check your system's printer settings.

Jobs stuck in queue — Check the physical printer for errors (out of labels, paper jam). Clear any stuck jobs in your OS print queue.

Labels printing wrong — Verify label dimensions match your actual labels. Run calibration from the ZPL playground.

Example: Shipping label

ctx.ui.interactive.print({
  title: "Shipping Label",
  description: `Print label for ${order.reference}`,
  jobs: [
    {
      type: "zpl",
      data: `^XA
^PW812
^LL1200
 
^FO50,50^A0N,40,40^FDYour Company^FS
^FO50,100^A0N,25,25^FD123 Warehouse Lane^FS
 
^FO50,200^A0N,35,35^FD${shipment.recipientName}^FS
^FO50,245^A0N,30,30^FD${shipment.addressLine1}^FS
^FO50,285^A0N,30,30^FD${shipment.city}, ${shipment.postalCode}^FS
 
^FO50,400^BY3,2,150^BCN,150,Y,N,N^FD${shipment.trackingNumber}^FS
 
^XZ`,
      printer: "Shipping Label Printer",
    }
  ],
  autoPrint: true,
  allowReprint: true,
});