Skip to content

Zebra and ZPL

Print ZPL to a Zebra printer from a web app.

Zebra printers speak ZPL, a text language of commands like ^XA and ^FD. Getting that text from a server in the cloud to a printer on a packing bench is the hard part. Here is how to do it with one API call, either by sending ZPL yourself or by keeping the layout in a template.

Before you start

  • A Printr account and an API token from the dashboard.
  • The Printr agent on one Windows or Mac computer at the site. It prints to Zebras on the network and to Zebras plugged into it by USB.
  • The printer's id, from GET https://api.getprintr.co.uk/v1/printers. Each printer reports its language; Zebras and compatibles report zpl.

Option 1: send raw ZPL

If your software already builds ZPL, send it as raw, from ^XA to ^XZ. Printr checks it is a complete label before printing it: a truncated one would otherwise leave the printer waiting for the rest, which looks exactly like a job that vanished. A malformed label fails with the error code payload_invalid rather than disappearing.

A shipping label with a Code 128 barcode
curl -X POST https://api.getprintr.co.uk/v1/printjobs \
  -H "Authorization: Bearer $PRINTR_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1041-label" \
  -d '{
    "printer_id": 7,
    "language": "zpl",
    "raw": "^XA^FO40,40^A0N,36^FDAcme Ltd^FS^FO40,90^A0N,28^FDSO-1041^FS^FO40,140^BCN,100,Y,N,N^FDSO-1041^FS^XZ",
    "copies": 1
  }'

language defaults to the printer's own, so it can be left out for a Zebra. Up to 2 MB of ZPL per job, and 1 to 100 copies.

Option 2: keep the layout in a template

Building ZPL by string concatenation has a trap: ^ and ~ are commands, so a customer name containing one can rewrite the rest of the label. Templates avoid that. Store the ZPL in Printr with placeholders, and send only the data. Values are stripped of ^ and ~ before they are inserted, so a surname with a caret in it prints as a surname.

The template, saved in the dashboard as shipping-label
^XA
^FO40,40^A0N,36^FD{{ customer }}^FS
^FO40,90^A0N,28^FD{{ order }}^FS
^FO40,140^BCN,100,Y,N,N^FD{{ order }}^FS
^XZ
Printing it
curl -X POST https://api.getprintr.co.uk/v1/printjobs \
  -H "Authorization: Bearer $PRINTR_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1041-label" \
  -d '{
    "printer_id": 7,
    "template": "shipping-label",
    "data": { "order": "SO-1041", "customer": "Acme Ltd" }
  }'

Every edit to a template is a new version, and each job records the version it used. A layout change goes live from the dashboard without redeploying your software, and a bad one is a click back. POST /templates/{slug}/render previews a label without printing it.

TSC and Xprinter: TSPL2

TSC and Xprinter printers speak TSPL2 rather than ZPL. Everything above works the same way with "language": "tspl2". In templates, " and \ are the characters stripped from values, because those are the ones TSPL2 treats as syntax.

When the label comes out wrong

Most Zebra problems are not errors. The job reports as printed, because from the computer's side it was, and the fault only shows on the label. The common ones:

  • It printed the code itself, a page of ^XA and ^FO. The printer is not treating the data as ZPL: it may be set to another language, or be listening on a document port rather than its raw printing port.
  • The label is the wrong size or in the wrong place. ZPL positions are in dots, so a layout drawn for a 203 dpi printer comes out smaller on a 300 dpi one. The label size in the template may not match the stock either.
  • The label is blank or faint. Usually the ribbon or media setting, the print darkness, or labels loaded face down.
  • It feeds too many labels or stops part-way. The printer needs calibrating to the label stock.

In the Printr dashboard, pick what came out wrong on the printer's page and it names the likely cause and what to change, written for whoever is standing at the printer.

Zebras can print PDFs too

A Zebra set up on the agent's computer with its driver can also take a PDF, which is useful when a courier gives you labels as PDFs rather than ZPL. See printing PDFs from a web app.

Further reading

Try it against your own printers

The free plan is 100 labels a month on one computer, with the full API. No card required. Once you are signed in, the reference fills in your own printer ids.