Industrial Tech #ZPL#Zebra

ZPL Basics for Warehouse Labels — Understanding Zebra's Label Programming Language

What ZPL is, the essential commands you need to know, how to read a real template, and when to use Labelary vs ZebraDesigner.

J.D. Sweeney April 11, 2026 6 min read

Most people working with Zebra printers never need to look at ZPL directly. ZebraDesigner or a label template from your WMS handles it, and labels print without anyone thinking about the underlying code.

Then something breaks. A label comes out shifted two inches to the right. A barcode won’t scan. A field is truncating text. Someone emails you a raw ZPL string and asks if you can modify it. Suddenly, knowing what you’re looking at matters.

ZPL — Zebra Programming Language — is the instruction set that Zebra thermal printers natively understand. This article covers the commands you’ll encounter most often, how to read a real label template, and how to test changes without burning through a roll of labels.

What ZPL Is and When You’d Need to Know It

ZPL is a text-based page description language. When you print a label, your software (whether ZebraDesigner, Bartender, a WMS, or a custom application) generates a ZPL string and sends it directly to the printer over USB, serial, or network. The printer interprets the commands and produces the label.

You don’t need to know ZPL to use a label designer. But you’ll benefit from understanding it when:

  • Troubleshooting label problems. A misaligned field or broken barcode is much easier to diagnose when you can read the ZPL and see what it’s telling the printer to do.
  • Tweaking templates. Sometimes a template needs a minor adjustment — moving a field 5mm to the right, changing a font size — and editing the ZPL directly is faster than going back into the designer.
  • Direct printing from custom applications. If you’re building a system that sends ZPL directly to a printer (common in warehouse integrations), you need to understand the format.
  • Receiving ZPL from vendors. Some vendors supply label formats as raw ZPL strings. You’ll need to read them to verify they match your requirements before deploying.

ZPL is not difficult to learn at a working level. A handful of commands covers the vast majority of what appears in real-world label templates.

The Essential ZPL Commands

Label Start and End: ^XA and ^XZ

Every ZPL label begins with ^XA (start of label) and ends with ^XZ (end of label). Everything between those two commands defines one label. Multiple labels can be sent in one print job by including multiple ^XA...^XZ blocks.

^XA
[label contents go here]
^XZ

Field Origin: ^FO

^FO sets the X and Y coordinates where the next field will be placed. Coordinates are in dots from the top-left corner of the label. Zebra printers commonly print at 203 dpi (8 dots per mm) or 300 dpi (12 dots per mm) — always check your printer’s resolution before calculating positions.

^FO50,100

This positions the next field 50 dots from the left edge and 100 dots from the top. On a 203 dpi printer, 50 dots is about 6.25mm from the left.

Field Data: ^FD and ^FS

^FD introduces the data content of a field, and ^FS (field separator) closes it.

^FO50,100^FDHello World^FS

This prints “Hello World” starting at position (50, 100).

Font Selection: ^A

^A specifies the font for the next text field. The most common form is ^A0 for the built-in scalable font, followed by orientation (N for normal, R for 90-degree rotation, I for inverted, B for 270-degree rotation), height, and width in dots.

^A0N,30,25

Normal orientation, 30 dots tall, 25 dots wide. On a 203 dpi printer, 30 dots is about 3.75mm tall.

Default Font: ^CF

^CF sets a default font for the entire label so you don’t have to specify ^A before every text field. Format: ^CF font, height, width.

^CF0,25,20

Sets the default font to scalable font 0, 25 dots tall, 20 dots wide. Any text field that doesn’t explicitly specify a font will use this default.

Barcode Width: ^BY

^BY sets the default parameters for barcodes that follow: bar width (in dots), wide-to-narrow ratio, and height (in dots).

^BY2,3,80

Bar width of 2 dots, ratio of 3, barcode height of 80 dots. The bar width and ratio affect how dense the barcode is — narrower bars fit more data in less space but require a higher-resolution printer and scanner to read reliably.

Code 128 Barcode: ^BC

^BC generates a Code 128 barcode, which is the most common 1D barcode format in warehouse and shipping applications. Parameters: orientation, height, print interpretation line (human-readable text below the barcode), print interpretation line above, check digit.

^FO50,200^BY2,3,80^BCN,80,Y,N^FD123456789^FS

This places a Code 128 barcode at (50, 200), with the parameters from ^BY, printed normally, 80 dots tall, with the human-readable text below it. The data encoded is “123456789”.

QR Code: ^BQN

^BQN generates a QR code. Parameters include model, magnification factor (size of each module in dots), and error correction level.

^FO50,300^BQN,2,5^FDQA,https://example.com/item/12345^FS

The ^BQN,2,5 specifies model 2 (standard QR), magnification 5 (each module is 5×5 dots). The ^FD data starts with QA, followed by the actual content — the QA, prefix is required by Zebra’s QR implementation to specify data type and error correction.

Reading a Real ZPL Label Template

Here’s a complete, simple shipping label in ZPL. Read through it command by command to see how the pieces fit together.

^XA
^CF0,30,25
^FO50,30^FDShip To:^FS
^FO50,70^FDJohn Smith^FS
^FO50,105^FD123 Main Street^FS
^FO50,140^FDAnytown, CA 90210^FS
^FO50,200^BY2,3,80^BCN,80,Y,N^FD1Z999AA10123456784^FS
^FO50,310^FDOrder: 78901^FS
^FO50,345^FDSKU: WIDGET-RED-LG^FS
^XZ

Walking through it:

  • ^CF0,30,25 — sets default font to scalable, 30 dots tall, 25 wide
  • ^FO50,30^FDShip To:^FS — prints “Ship To:” at position (50, 30)
  • The next three lines print the recipient name and address, each 35 dots lower
  • ^FO50,200^BY2,3,80^BCN,80,Y,N^FD1Z999AA10123456784^FS — prints a Code 128 barcode at (50, 200) encoding the tracking number
  • The last two lines print order and SKU information below the barcode
  • ^XZ closes the label

This is a functional, minimal shipping label. Real-world labels add logo graphics (^GF), boxes and lines (^GB), and often dynamic data placeholders that get filled in by the application before printing.

Labelary: Your Most Useful Debugging Tool

Labelary is a free, browser-based ZPL previewer available at labelary.com. Paste any ZPL string into it, specify your printer’s dpi and label dimensions, and it renders a preview of what the label will look like. It also provides an API if you’re building a system that needs label preview capability.

This tool is invaluable for troubleshooting. Instead of loading labels and wasting media while adjusting positions, paste the ZPL into Labelary, make adjustments, and preview instantly. When the preview looks right, print it.

Labelary supports almost all common ZPL commands. It doesn’t perfectly replicate every printer behavior — some commands behave slightly differently across printer models and firmware versions — but for layout and positioning work, it’s accurate enough to use as your primary testing environment.

Workflow for debugging a label problem:

  1. Capture the raw ZPL being sent to the printer (most label software can log this)
  2. Paste it into Labelary with the correct printer settings
  3. If the preview looks wrong, the ZPL is the problem — edit and re-preview
  4. If the preview looks correct but the printed output doesn’t match, the issue is likely printer configuration, calibration, or media settings

When to Use ZebraDesigner vs Raw ZPL

Use ZebraDesigner (or Bartender, NiceLabel, or another label design tool) for:

  • Creating new label templates from scratch
  • Designing labels with complex layouts, images, or GS1 compliance requirements
  • Managing a library of label formats that non-technical users need to modify
  • Templates that connect to databases for dynamic data

Work directly in ZPL when:

  • Making minor adjustments to an existing template (moving a field, changing font size)
  • Troubleshooting why a label is printing incorrectly
  • Writing code that generates and sends labels programmatically
  • A vendor supplies ZPL that needs to be verified or lightly modified

ZebraDesigner produces clean ZPL output, but it also generates more verbose code than you’d write by hand — lots of comments and redundant field settings. If you’re reading designer-generated ZPL, expect more lines than strictly necessary. The logic is still the same.

A Few Practical Notes

Printer resolution matters for coordinates. A label that looks perfect on a 203 dpi printer will have all its elements in the wrong positions on a 300 dpi printer, because the dot-based coordinates don’t change but the physical size of each dot does. Always confirm printer dpi before designing or troubleshooting.

^PQ for quantity. If you’re sending a print job and want multiple copies, ^PQ followed by a number controls print quantity. ^PQ10 prints 10 copies. This goes before ^XZ.

^LL for label length. ^LL sets the label length in dots. If your label is cutting off at the wrong point, check ^LL. This should match your media length.

Escape sequences. Some characters that appear in data — the caret (^) and tilde (~) — have special meaning in ZPL. To print a literal caret, use _5E. Check Zebra’s ZPL manual for the full list of escape sequences if your data might include special characters.

ZPL’s documentation — Zebra’s ZPL II Programming Guide — is freely available as a PDF from Zebra’s website and is comprehensive. Once you understand the structure described here, the reference manual is easy to navigate when you need a command you haven’t seen before.

Related Articles