If you work with Zebra thermal printers, you've probably heard of ZPL — Zebra Programming Language. It's the native command language that tells Zebra printers exactly what to print: text, barcodes, shapes, images, and more. Every label that comes out of a Zebra printer is ultimately rendered from ZPL commands, whether you write them by hand or a software tool generates them for you.
Understanding ZPL gives you complete control over your label output. You can create highly customized labels, debug printing issues, integrate label printing into your own applications, and optimize print speed. This tutorial takes you from zero ZPL knowledge to writing real, functional label code — with practical examples you can copy, modify, and send to your printer today.
What Is ZPL and Why Learn It?
ZPL (Zebra Programming Language) is a page-description language developed by Zebra Technologies. When you "print" a label to a Zebra printer, the software sends a block of ZPL text commands to the printer over USB, Wi-Fi, Bluetooth, or a serial/parallel connection. The printer interprets these commands and renders the label in real time. ZPL has been the standard for Zebra printers since the late 1990s, and virtually every Zebra printer manufactured in the last 25 years supports it.
Why Learn ZPL?
There are several compelling reasons to understand ZPL, even if you normally use a visual label design tool like LabelInn:
- Debugging: When a label doesn't print correctly — misaligned elements, wrong barcodes, garbled text — understanding the ZPL commands lets you diagnose the problem at the code level.
- Integration: If you're building an application that needs to print labels (an inventory system, a shipping platform, a POS system), you'll likely generate ZPL code programmatically. Understanding the language is essential.
- Performance: ZPL commands rendered natively on the printer are faster and crisper than image-based printing. Understanding ZPL helps you optimize print speed for high-volume environments.
- Customization: Some label requirements are easier to achieve by editing ZPL directly — dynamic field positioning, conditional printing, firmware-level fonts, and advanced barcode parameters.
- Troubleshooting: When your Zebra printer software generates unexpected output, reading the ZPL code reveals exactly what the printer was told to do.
Prefer visual design? LabelInn generates ZPL automatically — no coding needed
Download LabelInn Free →Basic ZPL Structure
Every ZPL label starts with ^XA (start format) and ends with ^XZ (end format). Everything between these two commands defines the contents of one label. Here's the simplest possible ZPL label — one that prints a single line of text:
^XA
^FO50,50
^A0N,40,40
^FDHello World^FS
^XZ
Let's break down each command:
^XA— Start Format. Tells the printer "a new label definition begins here." Every label must start with this command.^FO50,50— Field Origin. Sets the position (x,y) of the next element, in dots from the top-left corner. On a 203 DPI printer, 50 dots = about 6.3mm. On a 300 DPI printer, 50 dots = about 4.2mm.^A0N,40,40— Font selection.^Ais the font command.0is the font name (font 0 is the default scalable font).Nis the orientation (Normal).40,40is the height and width in dots.^FDHello World— Field Data. The actual text content to print.^FS— Field Separator. Marks the end of one field definition.^XZ— End Format. Tells the printer "label definition is complete — print it."
That's it. Six commands, one label. Every ZPL label you'll ever write is built from this same pattern: start format, position elements, define content, end format. The complexity comes from the variety of elements you can position — text, barcodes, shapes, images — and the parameters you can control for each one.
Positioning Elements with ^FO
The ^FO (Field Origin) command is the most frequently used ZPL command. It sets the x,y coordinates for the next element on the label. The coordinate system starts at the top-left corner of the label, with x increasing to the right and y increasing downward. All measurements are in dots (pixels), and the dot density depends on your printer's resolution:
| Printer DPI | Dots per mm | Dots per inch | 1mm = |
|---|---|---|---|
| 203 DPI | 8 dots | 203 dots | 8 dots |
| 300 DPI | 11.8 dots | 300 dots | ~12 dots |
| 600 DPI | 23.6 dots | 600 dots | ~24 dots |
For example, to place text 25mm from the left edge and 10mm from the top on a 203 DPI printer: ^FO200,80 (25mm × 8 dots = 200, 10mm × 8 dots = 80). When designing labels, it's helpful to sketch out positions on paper first, converting millimeters to dots for your specific printer DPI.
Positioning Tips
- Leave at least 2-3mm margin (16-24 dots at 203 DPI) from all label edges to avoid elements being cut off.
- When stacking elements vertically, account for the height of each element plus a gap. A 40-dot-tall text followed by a 10-dot gap means the next element starts 50 dots below.
- Use consistent x-coordinates for left-aligned elements to create clean columns.
Skip the math — LabelInn's visual editor handles positioning automatically
Download LabelInn Free →Text Formatting with ^A
The ^A command controls font selection, orientation, and size. The full syntax is:
^Afo,h,w
Where:
f— Font name.0is the default scalable font. Other built-in fonts includeAthroughZ(bitmap fonts of various sizes) and custom fonts you can download to the printer.o— Orientation.N= Normal,R= Rotated 90° clockwise,I= Inverted (180°),B= Bottom-up (270°).h,w— Height and width in dots. For the scalable font (0), these can be any value. For bitmap fonts, these select the nearest available size.
Font Examples
^XA
^FO50,30
^A0N,60,60
^FDLarge Title^FS
^FO50,110
^A0N,35,35
^FDMedium subtitle^FS
^FO50,160
^A0N,25,25
^FDSmall body text^FS
^FO50,210
^A0R,40,40
^FDRotated 90 degrees^FS
^XZ
This label prints four text lines at different sizes, with the last line rotated 90 degrees clockwise. Notice how each text element follows the same pattern: ^FO (position), ^A (font), ^FD (data), ^FS (end field).
International Characters
ZPL supports international character sets through the ^CI (Change International Font) command. For UTF-8 encoding (which covers most languages), use ^CI28 at the beginning of your ZPL code. This enables characters like ä, ö, ü, é, ñ, ş, ğ, and other accented or non-Latin characters. Place ^CI28 right after ^XA and before any text fields.
Barcode Generation
Barcodes are the most critical element in most label applications. ZPL supports dozens of barcode formats natively — the printer renders them from data, meaning they're always sharp and scannable (unlike image-based barcodes which can suffer from resolution issues). Here are the most commonly used barcode commands.
Code 128 — ^BC
Code 128 is the most versatile and widely used barcode format. It supports all 128 ASCII characters and is compact. Here's how to generate a Code 128 barcode in ZPL:
^XA
^FO50,50
^BY3
^BCN,100,Y,N,N
^FD123456789^FS
^XZ
^BY3— Bar code field default. Sets the module (narrow bar) width to 3 dots. Larger values = bigger barcode. Range: 1-10.^BCN,100,Y,N,N— Code 128 barcode.N= Normal orientation.100= bar height in dots.Y= print human-readable text below the barcode. The last twoNparameters control UCC check digit and mode.^FD123456789— The data to encode in the barcode.
QR Code — ^BQ
QR codes are increasingly popular for warehouse labels, asset tracking, and product labels because they can store more data and scan from any angle. Here's the ZPL for a QR code:
^XA
^FO50,50
^BQN,2,6
^FDQA,https://www.labelinn.com^FS
^XZ
^BQN,2,6— QR Code barcode.N= Normal orientation.2= model 2 (standard QR code).6= magnification factor (1-10, where larger = bigger QR code).^FDQA,— For QR codes, the field data must start withQA,(for automatic error correction) orQM,followed by the error correction level (H, Q, M, L). The actual data follows the comma.
EAN-13 — ^BE
^XA
^FO50,50
^BY3
^BEN,100,Y,N
^FD5901234123457^FS
^XZ
DataMatrix — ^BX
^XA
^FO50,50
^BXN,6,200
^FDLOT-2026-03-0042^FS
^XZ
The ^BX command generates DataMatrix 2D barcodes, commonly used in healthcare, electronics, and aerospace labeling. The 6 is the module size and 200 is the number of columns.
Generate any barcode format visually — no ZPL coding required
Download LabelInn Free →Drawing Lines, Boxes, and Shapes with ^GB
The ^GB (Graphic Box) command draws rectangles, lines, and borders. It's essential for creating structured label layouts with boxes, dividers, and borders.
^GB width,height,thickness,color,rounding
width— Box width in dots.height— Box height in dots.thickness— Line thickness in dots. If thickness equals width or height, you get a filled rectangle.color—Bfor black (default),Wfor white (useful for reverse printing).rounding— Corner rounding, 0 to 8 (0 = square corners, 8 = fully rounded).
Examples
^XA
^FO50,50
^GB700,1,3^FS
^FO50,50
^GB1,400,3^FS
^FO50,50
^GB700,400,3^FS
^FO100,100
^GB200,150,200,B,0^FS
^FO400,100
^GB200,150,3,B,5^FS
^XZ
This code draws: a horizontal line (700 dots wide, 1 dot tall), a vertical line (1 dot wide, 400 dots tall), a rectangular border (700×400, 3-dot line), a filled black rectangle (200×150, fully filled because thickness=200), and a rounded-corner box (200×150, 3-dot line, rounding=5).
Creating a Label Border
A common use of ^GB is adding a border around the entire label. For a 4×6" label (812×1218 dots at 203 DPI), you'd use:
^XA
^FO0,0
^GB812,1218,4^FS
^XZ
Working with Images — ^GF
The ^GF (Graphic Field) command lets you print bitmap images on labels — logos, icons, and other graphics. The image data is sent as a hex-encoded bitmap. The syntax is:
^GFa,b,c,d,data
a— Compression type.A= ASCII hex.b— Binary byte count (total data bytes).c— Graphic field count (bytes per row).d— Rows in the image.data— The hex-encoded bitmap data.
Writing ^GF commands by hand is impractical for any real image. Instead, use a converter tool that takes a PNG/BMP image and generates the corresponding ZPL. LabelInn handles this automatically — drag an image onto your label, and the app converts it to optimized ^GF commands when sending to the printer. You can also use the free online converter at labelary.com to preview and test image-to-ZPL conversion.
Drag & drop images onto labels — LabelInn handles the ZPL conversion
Download LabelInn Free →Practical Examples: Real-World Labels
Now let's put it all together with three complete, real-world label examples you can modify and use.
Example 1: Shipping Label (4×6")
^XA
^CI28
^FO0,0^GB812,1218,3^FS
^FO30,20
^A0N,50,50
^FDFrom: ACME Corp^FS
^FO30,80
^A0N,30,30
^FD123 Industrial Ave, Suite 400^FS
^FO30,120
^A0N,30,30
^FDNew York, NY 10001^FS
^FO30,180^GB752,1,2^FS
^FO30,200
^A0N,60,60
^FDShip To:^FS
^FO30,280
^A0N,45,45
^FDJohn Smith^FS
^FO30,340
^A0N,35,35
^FD456 Commerce Blvd^FS
^FO30,390
^A0N,35,35
^FDLos Angeles, CA 90001^FS
^FO30,460^GB752,1,2^FS
^FO200,500
^BY3
^BCN,120,Y,N,N
^FD9261290100130736518956^FS
^FO30,670^GB752,1,2^FS
^FO250,700
^A0N,60,60
^FDPRIORITY MAIL^FS
^FO580,900
^BQN,2,8
^FDQA,9261290100130736518956^FS
^XZ
This shipping label includes sender and recipient addresses, a Code 128 tracking barcode with human-readable text, a divider line, a service level indicator, and a QR code for mobile scanning.
Example 2: Product Label (2×1")
^XA
^CI28
^FO20,10
^A0N,30,30
^FDOrganic Green Tea^FS
^FO20,50
^A0N,20,20
^FD250g | Best Before: 12/2027^FS
^FO20,85
^BY2
^BCN,50,Y,N,N
^FD8901234567890^FS
^FO320,10
^BQN,2,3
^FDQA,https://acme.com/p/8901234567890^FS
^XZ
A compact product label with the product name, weight, expiry date, an EAN-13 barcode for retail scanning, and a small QR code linking to product details online.
Example 3: Asset Tag (1.5×0.75")
^XA
^FO10,5
^A0N,22,22
^FDACME CORP^FS
^FO10,30
^A0N,18,18
^FDAsset: LAPTOP-0042^FS
^FO10,55
^BY2
^BCN,35,N,N,N
^FDLAPTOP-0042^FS
^FO230,5
^BQN,2,2
^FDQA,LAPTOP-0042^FS
^XZ
A small asset tag with company name, asset identifier, Code 128 barcode, and a tiny QR code — all fitting on a 1.5×0.75" label suitable for sticking on laptops, monitors, and equipment.
Debugging ZPL with Labelary.com
One of the best tools for learning and debugging ZPL is labelary.com — a free online ZPL viewer. Here's how to use it effectively during your learning process:
- Go to labelary.com/viewer.html
- Set your printer DPI (203, 300, or 600) and label size (e.g., 4×6 inches)
- Paste your ZPL code in the left panel
- The rendered label preview appears instantly on the right
- Modify the code and see changes in real time
Labelary is invaluable for iterating on label designs without wasting physical labels. Write your ZPL, preview it, adjust positions, and only send it to the printer when it looks correct. It also has an API (api.labelary.com) that you can use programmatically to render ZPL as PNG images — useful for showing label previews in your own applications.
Common Debugging Tips
- Element not appearing? Check the
^FOcoordinates — the element might be positioned outside the label area. - Text too small? Increase the height and width values in the
^Acommand. - Barcode not scanning? Increase the
^BYmodule width (try 3 or 4) and the bar height. Small barcodes on low-DPI printers are unreliable. - QR code showing garbage? Make sure the
^FDdata starts withQA,orQM,followed by the error correction level. - Overlapping elements? Each element needs its own
^FOcommand. Elements don't automatically flow — you must set each position manually.
Debug visually — LabelInn shows a real-time preview while you design
Download LabelInn Free →When to Use ZPL vs. a Visual Designer
Now that you understand ZPL, when should you actually write ZPL by hand versus using a visual label design tool? Here's a practical breakdown:
Use ZPL Directly When:
- You're building label printing into a custom application (ERP, WMS, POS system)
- You need to modify or fix existing ZPL templates generated by other software
- You want maximum control over printer-level settings (print speed, darkness, media handling)
- You're automating label generation in a scripting environment (Python, Node.js, C#)
- You're debugging a label output issue and need to understand what the printer is receiving
Use a Visual Designer When:
- You're designing labels for the first time and want a fast, intuitive workflow
- You need to print labels on multiple printer brands (not just Zebra)
- You want to import data from Excel/CSV for variable data and batch printing
- You need to collaborate with non-technical team members who can't read ZPL
- You want features like AI label design, template libraries, and one-click barcode generation
LabelInn's Visual-to-ZPL Advantage
LabelInn gives you the best of both worlds. You design labels visually — using drag-and-drop, point-and-click placement, and real-time preview — and LabelInn automatically generates optimized ZPL commands behind the scenes. When you print to a Zebra printer, those ZPL commands are sent directly to the printer for native rendering, which means sharp text, perfect barcodes, and maximum print speed. You get the speed and ease of visual design with the quality and performance of native ZPL output. No ZPL coding required — but if you ever need to inspect or modify the generated ZPL, LabelInn makes that possible too.
Essential ZPL Command Reference
Here's a quick reference of the most important ZPL commands covered in this tutorial, plus a few additional ones you'll use frequently:
| Command | Purpose | Example |
|---|---|---|
^XA |
Start label format | ^XA |
^XZ |
End label format / print | ^XZ |
^FO |
Field origin (x,y position) | ^FO100,50 |
^FD |
Field data (content) | ^FDHello^FS |
^FS |
Field separator (end field) | ^FS |
^A |
Font selection & size | ^A0N,40,40 |
^BY |
Barcode module width | ^BY3 |
^BC |
Code 128 barcode | ^BCN,100,Y,N,N |
^BQ |
QR Code | ^BQN,2,6 |
^GB |
Graphic box / line | ^GB400,3,3^FS |
^GF |
Graphic field (image) | ^GFA,... |
^CI |
Character set | ^CI28 (UTF-8) |
^PQ |
Print quantity | ^PQ5 (print 5 copies) |
^LH |
Label home (origin offset) | ^LH0,0 |
^LL |
Label length | ^LL1218 |
^PW |
Print width | ^PW812 |
Conclusion: Start Writing ZPL or Let LabelInn Do It for You
ZPL is a powerful, well-documented language that gives you complete control over Zebra printer output. Whether you're writing integration code, debugging label issues, or simply satisfying your curiosity about what happens behind the scenes when a label prints, understanding ZPL makes you more effective with Zebra hardware.
That said, hand-coding ZPL for every label is neither efficient nor necessary. LabelInn lets you design labels visually and automatically generates optimized ZPL for Zebra printers (and equivalent commands for other printer brands). You get the speed of drag-and-drop design, the power of native ZPL rendering, and support for features like Excel import, 30+ barcode formats, and AI-assisted label design — all in a free, multi-platform app.
Design Labels Visually — Print with Native ZPL
LabelInn converts your visual designs to optimized ZPL commands. Free download — no ZPL knowledge required.
Download LabelInn Free →