Build a 4x6 Shipping Label in ZPL: Preview, Scan, and Hand Off
A shipping label is a contract between systems that do not care about your intentions. The WMS needs the right variables, the carrier needs a scannable tracking code, the printer needs coordinates that fit the stock, and the person on the dock needs a label that can be read quickly. A pretty preview is not enough. You need a workflow that ends with proof.
This walkthrough builds a practical 4x6 label at 203 DPI. The exact fields will vary by carrier, but the review pattern is reusable: define the frame, place human-readable blocks, add native barcodes, preview at the right density, scan-check, then export a proof for the handoff.
Start with physical constraints
At 203 DPI, a 4x6 inch label is roughly 812 by 1218 dots. Put those numbers in the ZPL instead of relying on printer defaults. That makes the preview honest and helps reviewers understand the intended stock.
^XA
^CI28
^PW812
^LL1218
^FO40,35^A0N,42,42^FDACME FULFILLMENT^FS
^FO40,90^GB730,2,2^FS
^XZ
Add the address block before the barcode
Address text is the part most likely to grow. Build it with wrapping early, then test it with long names and apartment lines. If you only test with "John Smith", the first production exception will find the overlap for you.
^XA
^CI28
^PW812
^LL1218
^FO40,35^A0N,42,42^FDACME FULFILLMENT^FS
^FO40,90^GB730,2,2^FS
^FO40,130^A0N,28,28^FDSHIP TO:^FS
^FO40,170^FB520,5,7,L
^FD{{recipient_name}}\&{{address_line_1}}\&{{address_line_2}}\&{{city_state_zip}}^FS
^FO590,135^BQN,2,6
^FDLA,{{tracking_url}}^FS
^XZ
Preview this version before adding more fields. The QR code has to keep a quiet area. The address block has to survive long data. If these two regions fight now, moving them is cheaper than fixing a finished label.
Add a native tracking barcode
For most shipping workflows, the tracking barcode should be native ZPL, not a screenshot of a barcode from a PDF. Native commands give the printer better control over module width, height, and human-readable text.
^XA
^CI28
^PW812
^LL1218
^FO40,35^A0N,42,42^FDACME FULFILLMENT^FS
^FO40,90^GB730,2,2^FS
^FO40,130^A0N,28,28^FDSHIP TO:^FS
^FO40,170^FB520,5,7,L^FD{{recipient_name}}\&{{address_line_1}}\&{{address_line_2}}\&{{city_state_zip}}^FS
^FO590,135^BQN,2,6^FDLA,{{tracking_url}}^FS
^FO40,760^A0N,26,26^FDTRACKING:^FS
^FO40,805^BY3,3,150
^BCN,150,Y,N,N
^FD{{tracking_number}}^FS
^FO40,1010^GB730,2,2^FS
^FO40,1040^A0N,26,26^FDService: {{service_level}}^FS
^FO420,1040^A0N,26,26^FDOrder: {{order_id}}^FS
^XZ
Run the checks that catch real failures
- Preview at the same DPI as the production printer.
- Use the longest expected recipient name, address, service level, and order ID.
- Check quiet zones around the Code 128 barcode and QR code.
- Scan a physical print with the scanner used on the warehouse floor.
- Export a PNG or PDF proof for operations, QA, and carrier review.
When to use conversion tools
If the starting point is a carrier PDF, use PDF to ZPL as a bridge, then rebuild the critical barcode as native ZPL when the label becomes permanent. If the starting point is HTML from a checkout page, HTML to ZPL can give you a quick layout draft. If the source is a photo, OCR can help reconstruct the first version. In every case, the final step is the same: preview, inspect, and scan.
