Zebra Label Printers
ProxyBox treats Zebra label printers (GK420, ZD, ZT, ZQ series, and others) as raw ZPL devices first: whatever ZPL your application sends is delivered to the printer unmodified — no drivers, no rendering, no scaling. Applications that produce PDFs instead of ZPL can also print PDFs, which ProxyBox renders to ZPL on the device. Around delivery, ProxyBox adds discovery, health checks before each job, and recovery when a printer gets stuck.
Connecting
Section titled “Connecting”Network (most common). Zebra network printers accept raw ZPL over TCP port 9100. Most of them don’t advertise themselves via mDNS/Bonjour, so they usually won’t appear in auto-discovery — add them with Add Network Printer in the Printers module (IP address + port 9100). Manually added printers persist across reboots.
USB. USB-attached Zebras are auto-discovered and addressed by serial number (path usb_sn_<serial>), so the path stays stable no matter which physical port the printer is plugged into.
Once a printer is identified as a Zebra, ProxyBox marks it as a ZPL printer ("content": "zpl" in GET /printers), which enables the ZPL-specific behavior on this page: pre-flight status checks, the branded ZPL test label, and the Reset Printer button.
Sending ZPL
Section titled “Sending ZPL”The simplest form — POST the ZPL directly as the request body:
curl -X POST https://pbx-D8A4.pbxz.io/api/v1/print/tcp_192-168-86-250_9100 \ -H 'Content-Type: application/octet-stream' \ -H 'X-API-Key: ULA9WHXMFCHF' \ --data-binary @label.zplFrom JSON, use contentType: "zpl" for plain-text ZPL, zpl_base64 for base64-encoded ZPL, or raw_url to have ProxyBox fetch the ZPL from a URL. See POST /print for the full request reference.
Batching: you can send multiple labels in one request by concatenating ^XA...^XZ blocks in the body. The printer processes them in order.
PDF Printing
Section titled “PDF Printing”If your application produces PDFs rather than ZPL, send them with contentType: "pdf_base64" or "pdf_url" — ProxyBox renders the PDF to ZPL on the device and the printer never needs to understand PDF:
curl -X POST https://pbx-D8A4.pbxz.io/api/v1/print/tcp_192-168-86-250_9100 \ -H 'Content-Type: application/json' \ -H 'X-API-Key: ULA9WHXMFCHF' \ -d '{"content": "https://example.com/shipping-label.pdf", "contentType": "pdf_url"}'The PDF page size selects the label size. ProxyBox reads the first page’s dimensions and prints on a matching label — so generate your PDF pages at the label’s physical size, in points (1 inch = 72 points; a 4×6“ label is a 288×432 pt page). Supported sizes range from 36–576 pt wide (0.5–8“) and 36–3600 pt long (0.5–50“); pages outside that range are clamped to it. To force a specific media size instead, pass a paperSize option.
Rendering happens at 203 dpi, the resolution of most Zebra desktop printers.
Two things to know when choosing between ZPL and PDF:
- Only the JSON
pdf_url/pdf_base64forms are rendered. A PDF posted as a raw binary body (orraw_base64/raw_url) is passed through untouched like any other raw data — that’s the passthrough contract, and it’s what you want for Zebra models whose firmware can print PDFs natively. - ZPL is still the better choice when you can produce it — it’s smaller, faster, and uses the printer’s built-in fonts and barcodes at full crispness. PDF rendering transfers the label as a bitmap.
Sizing Your Labels
Section titled “Sizing Your Labels”ZPL positions everything in dots, and the dots-per-inch depends on the printhead — most Zebra desktop printers are 203 dpi, some models are 300 dpi (check the printer’s spec label). Convert with dots = inches × dpi.
Set the label dimensions at the top of every format:
| Command | Meaning | 4×6“ @ 203 dpi | 3×1“ @ 203 dpi |
|---|---|---|---|
^PW |
Print width in dots | ^PW812 |
^PW609 |
^LL |
Label length in dots | ^LL1218 |
^LL203 |
^MN |
Media tracking | ^MNW (die-cut, gap sensing) |
^MNW |
A complete minimal label you can send as-is to a 4×6“ printer:
^XA^MNW^PW812^LL1218^FO50,50^A0N,50,50^FDHello from ProxyBox^FS^FO50,150^BCN,100,Y,N,N^FD123456789^FS^XZPre-flight Status Check
Section titled “Pre-flight Status Check”Before sending a job to a network (TCP) Zebra printer, ProxyBox queries it with the ZPL ~HS (Host Status) command. If the printer reports a problem, the job is rejected with a 503 Service Unavailable — saving you from wasted labels and “successful” responses that print nothing.
| Condition | Description |
|---|---|
| Paper Out | The printer has run out of labels or paper. |
| Paused | The printer is paused, often needing calibration after the lid was opened/closed. |
| Head Open | The print head is currently open. |
| Ribbon Out | The ribbon has run out (thermal transfer printers). |
The 503 response body includes the specific conditions detected — see the error example in the print reference.
If the status query itself fails, ProxyBox automatically sends the reset sequence (^XZ~JA, described below) and retries the check once — this self-heals printers wedged by a half-open format block. If the printer still doesn’t answer (e.g. it’s powered off), the job is attempted anyway and normal error handling reports the failure.
Pre-flight checks apply only to network Zebras — USB Zebras skip them, since ~HS is queried over a separate TCP connection.
Resetting a Stuck Printer
Section titled “Resetting a Stuck Printer”Zebra printers can get stuck when they receive an incomplete ZPL format block — for example, a ^XA (start format) without a matching ^XZ (end format). The buffer sits waiting for the rest of the command, and every subsequent job queues behind it. Nothing prints.
Symptoms:
- Jobs send successfully (you get a
200response) but nothing comes out of the printer - The printer’s web config page may show “busy processing another request”
- Power cycling may not resolve it if the buffer is persisted in memory
Click Reset Printer in the Printers module. This sends ^XZ to close any open format block, followed by ~JA to cancel all pending formats in the receive buffer. You can do the same thing from your own code — the reset sequence is just a raw print job:
curl -X POST https://pbx-D8A4.pbxz.io/api/v1/print/tcp_192-168-86-250_9100 \ -H 'Content-Type: application/octet-stream' \ -H 'X-API-Key: ULA9WHXMFCHF' \ --data-binary '^XZ~JA'Test Prints
Section titled “Test Prints”The Test Print button (and POST /print/{target}/test) sends a branded ZPL test label with a QR code linking back to your device. The label is formatted for 4×6“ at 203 dpi — on smaller labels it will print clipped, which is fine for verifying connectivity.
ProxyBox Docs v1.0.6
