Skip to main content

ZPL Label Generator

v1.2.0

Renders imported or pasted ZPL II code, including .zplii files with ^GF graphics, ^FV fields, and ISO 16023 MaxiCode symbols, at one pixel per printer dot at 152 to 600 dpi, then exports ZPL, EPL, PNG, or PDF. Placeholders such as {#} substitute CSV or Excel data and carton numbering, printing a write-in blank where no value exists. Saved templates drive bulk runs from spreadsheet rows.

Your inputs stay in your browser

Everything you enter is processed on your device. This tool loads a code library from cdnjs.cloudflare.com, which sees your IP address but never what you type.

Retail
Inventory
Logistics
Loading the tool
Reference

Documentation

A ZPL label generator turns a designed layout, or an existing ZPL file, into the exact raster a Zebra thermal printer would produce. The engine draws every label at one pixel per printer dot, so the preview is what the printer produces at the selected density, not an approximation of it.

  • Two ways of building a label are supported. A stacked-text design builds a label from text lines, lettered Text A downward, each with its own height in printer dots, an optional bold weight, and left, center, or right alignment. Those per-line controls are hidden until Show per-line options is ticked under Settings, which keeps the line list to one row per line; a line holds whatever height, weight, alignment, and row grouping it was given either way. Alternatively, an existing .zpl, .zplii, .zpl2, .prn, or .txt file, or pasted code, renders unchanged where the command subset allows, so labels built on other systems reproduce as they were designed.
  • Carrier and WMS files render with the full ZPL II command set: ^FV behaves as ^FD, ^FH turns _1E style escapes back into bytes, ^GF draws ASCII hex graphics including the run-length codes that repeat digits, fill a row, or repeat the row above, and ^LR flips the default field color. Printer setup commands such as ^MN, ^MF, ^MC, ^CV, and ^DN leave no mark on paper and are listed once as passed through rather than flagged individually.
  • A file that states no ^PW or ^LL is measured rather than guessed: the label sizes to the marks the format makes, snapped to the nearest quarter inch, so a 4 by 6 inch shipping label comes in at 812 by 1218 dots at 203 dpi rather than being cut to a default size. Width and Height follow the code in this mode, keeping the dimensions line, the PDF page, and the print sheet at the raster's physical size, though either can still be overridden by hand. Any field still past the edge is reported with its exact overshoot in dots.
  • Line order in the list sets line order in both the ZPL and the preview. Grouping a line into the row above, rather than stacking it below, splits the usable width into equal columns, with each line keeping its own size, bold weight, and alignment; the first line has nothing to sit beside, so this option does not apply to it. Mixed sizes sharing a row share a baseline, so a small country-of-origin note aligns with the bottom of a large carton number rather than its top.
  • Text wider than its column moves to extra rows and pushes the lines below it down, while the line list still shows one entry per line. The rows are not filled first-fit: the generator keeps the fewest rows the line needs, then places the breaks so an address reads the way it is written, ending a row after a comma or after the street type (Drive, Ave, Parkway) rather than stranding a ZIP code, and keeping a code such as RNO: with the words it names. Each row enters the ^FB field behind a \& line break and the field's maximum-line count equals the row count, so the printed rows match the preview row for row rather than being wrapped again by the printer's own font.
  • A line wider than the space it has, whether a single long word or a centered line plus its write-in blanks, is reported in Checks, including a line held to half the width by Same row. Shrink text to fit, an option under Label and Printer that starts unticked, answers both side and bottom overruns by scaling every line height by the same factor, only as far as needed and never below 40 percent, and Checks names the factor it used.
  • The stacked-text design and a raw ZPL listing are kept independent: code typed or opened is never touched by the other mode, and switching modes or reloading the page leaves both intact. Writing the current design out as raw ZPL keeps its variable placeholders intact, so {#} and named variables continue substituting after hand-editing.
  • Rendering happens automatically as the design changes, after a brief pause, or on demand, and any command that is unsupported or was defaulted is reported afterward rather than silently ignored.
  • Label size follows a preset, such as 4 x 2 in, or a custom width and height; both accept decimals, fractions such as 1/2, and mixed numbers such as 4 1/4, in inches or millimeters. Print density defaults to 203 dpi, print quality is grayscale or bitonal, and orientation rotates 90, 180, or 270 degrees, with 180 emitted as ^POI. Settings, variables, saved templates, and bulk configuration all persist between visits exactly as they were left.
  • Variables are named placeholders wrapped in configurable delimiters (curly braces by default) that substitute into both the stacked-text design and raw ZPL in real time. A CSV or Excel file can populate the whole variable list at once: headers become the names, the first data row becomes the values.
  • A run is numbered with a step value and a label count, as in the default Carton #{#} of {total}, and generating ZPL emits one ^XA block per label. Leaving either empty prints the placeholder as blank space sized by the Write-in blank setting under Settings and Designer Options (8 spaces by default), so the number can be filled in by hand; any variable with an empty value behaves the same way, whether typed or pulled from a CSV cell. Setting the write-in blank to 0 closes those gaps instead.
  • Line spacing multiplies the gap between rows and between wrapped rows inside one line, and is written into the ZPL as the ^FB line-spacing parameter so the printer matches the preview. A value of 1.0 sets lines solid, 1.5 is the default, and 3.0 spreads a short label out.
  • Vertical centering, on by default, moves the whole line stack together as one group and keeps its internal spacing, rather than centering each line on its own, which matters most on a label carrying only a line or two. Turning it off pins the first line to the top margin instead. Warnings report the dot range the text occupies and the exact overshoot when it runs past the bottom edge.
  • The preview reports exact ZPL dot coordinates under the cursor, and in the raw-ZPL view a click inserts a ^FO field at that position, which is a fast way to place or correct a field without computing coordinates by hand. Panning and zooming the preview changes only the view, never the label itself, and can always be reset back to a default fit.
  • A generated-ZPL listing shows the exact code an export would produce, with variables substituted and every numbered label included; a run too large to display in full holds the first label and says so, though the exports still carry the whole sequence. Copying from that listing copies only what is shown, while copying from an export copies the whole run.
  • An export of more than one label reports progress, such as rendered label 45 of 300, so a long run never looks stalled while it renders one label at a time and hands control back to the browser between them, keeping the page responsive throughout. PDF pages are compressed, so a 300 label run lands near 12 MB rather than several hundred.
  • A design can be saved as a named template, reloaded or deleted later, and every saved template exported to one JSON file for version control or handing to a coworker, with import merging that file back in on any machine. A template holds the layout, label size, density, quality, orientation, font, spacing, and delimiters, but not the variable values, step number, or label count, which stay with whichever run is current. Saving over an existing name or deleting a template cannot be undone, and an import reports what it added, what it replaced by name, and anything in the file it could not read; an entry that is not a readable template is refused rather than stored.
  • A preset file, loaded under Bulk Multi-Label Generation, turns the text lines and Step # into pick lists drawn from a sheet of approved values so a label cannot go out with a mistyped address or department. Each column maps to an input, by a header naming a line, by the column's values opening the way a line already does, by carrying on from the column beside it, or failing all three by column order; every mapping stays a dropdown the user can change, and a column mapped to nothing still narrows the others. Locked inputs suggest as the user types, match anywhere in the value rather than only at its start, and refuse anything the sheet does not carry. Picking a value narrows every other input to the rows that agree with it and fills in whatever is left with one possibility, so choosing a distribution centre brings its address, department, and PO prefix with it; a prefix shared by two customers leaves both open until something else settles it. A PO# line and # of labels stay typeable, with only the leading digits of a PO number checked against the sheet, and Step # locks only where a column feeds it. A loaded preset stays available on later visits and is cleared by Reset.
  • Bulk generation runs a design or a set of templates against a CSV or Excel file whose header row names the variables and whose every following row becomes one label. Only the first worksheet is read, the first non-empty row is treated as the header, and quoted fields containing commas parse correctly. A header repeated within the same row is reported, and the leftmost copy is the one that prints.
  • Columns bind to placeholders by exact match on the header text, letter case included, so a column named SKU does not fill {sku}. Leading and trailing spaces are trimmed, so " sku " still binds, but an inner space is not, so a column named unit price needs a placeholder written as {unit price}. Empty headers are ignored, and changing the delimiters changes the placeholder while the header stays the plain word underneath. Loading a file reports the binding before a run rather than after: which columns feed the label, any name differing only by case, any placeholder with no column, and any column the design never uses; checking more than one template repeats that report per template, since two templates can want different columns from the same file.
  • Precedence runs column value, then typed variable, then write-in blank: the file wins wherever both supply a value for the same name, and {#} and {total} always come from the run's step number and label count rather than from a column. A file of sku, desc, and price columns against a design reading {sku}, {desc}, and Made in {origin} reports sku and desc feeding the label, price unused, and origin with no matching column: filling {origin} once under variables applies it to every row, adding an origin column varies it per row, and leaving it produces a write-in blank instead. An empty cell behaves as a missing column, so a partly filled spreadsheet still produces usable labels.
  • Checking more than one saved template for a bulk run renders each data row through every checked layout, which is how a shipping label and a contents label come off one row of data; leaving every template unchecked uses the current design instead. Numbering multiplies the run again: 3 rows through 2 templates with a label count of 2 produces 12 labels, and a run is capped at 2000 labels.
  • Bulk output can be one ZPL file with an ^XA block per label for sending straight to a printer, a ZIP of PNGs named by template and row, or a multi-page PDF at the exact label size. Every export leads with an unpunctuated date stamp such as 20260806, so a folder of runs sorts chronologically.
  • The current label can be exported as ZPL, as EPL in the stacked-text mode, as a PNG, as a PDF, sent directly to a printer, or copied as ZPL text.

The rendering engine supports ^XA, ^XZ, ^PW, ^LL, ^LH, ^FO, ^FT, ^A, ^CF, ^FD, ^FV, ^FH, ^FS, ^FB, ^GB, ^GF in the ASCII hex format, ^BY, ^BC (Code 128 with a computed checksum), ^BD (MaxiCode), ^FR, ^LR, ^FW, ^CI, ^FX, ^PQ, and ^POI. ^BD is encoded for real per ISO/IEC 16023 at the true 1.11 by 1.05 inch symbol size with full Reed-Solomon error correction: modes 2 and 3 read the structured carrier block from the first 15 characters of the field data, class of service (3), country code (3), postal code (9), the layout UPS labels use, dropping to mode 3 automatically when the postal code is not numeric, while modes 4, 5, and 6 encode the whole field. Every symbol generated during development, including this page's own PNG exports, decoded byte for byte under an independent ISO 16023 reader across 1,200 randomized messages; scanning a printed label before a production run is still worth doing. Field data that cannot be encoded falls back to a block captioned MAXICODE PLACEHOLDER with an error naming the reason, and reversing a MaxiCode draws faithfully but is flagged because no reader decodes white-on-black. Z64 and B64 compressed ^GF payloads need a deflate decoder the preview does not carry and are left blank. Any other command is listed rather than silently dropped, and printer-configuration commands are grouped into one line instead of one warning each.

Thermal label work spans one-off cartons, numbered case packs, and thousand-row warehouse runs. The generator covers each of these because the same design drives the ZPL text, the raster preview, and every export format, and because saved templates plus variable substitution separate the layout from the data that fills it.

  • Carton Shipping Labels: Build a 4 x 2 in carton label with From, To, address, PO#, and DEPT# lines, then add Carton {#} of {total} with a step value of 1 and a label count of 24 to number a full pallet in one export.
  • Existing ZPL Maintenance: A .zpl file exported from a WMS previews at 203 dpi without a physical printer on hand. Dot coordinates under the cursor identify a misplaced field, and a corrected ^FO can be inserted at that position directly from the preview.
  • Carrier Label Proofing: A .zplii file a UPS or FedEx system produced for a shipment reads back without burning a label. The ^FV address and reference fields, the ^GF service mark, the Code 128 tracking barcode, and the ISO 16023 MaxiCode are all reproduced for real, reporting the postal code, country, and class of service parsed out of the carrier block; because the file states no ^LL, the label sizes itself to 4 by 6 inches instead of showing only the top third, and a footer line pushed past the media edge by the ^LH offset is flagged with its exact overshoot.
  • Retail Shelf and Product Labels: Design a 2.25 x 1.25 in product label with {sku}, {desc}, and {price} variables, save it as a template, and let a CSV of 500 rows drive a ZIP of PNGs for the labeling line.
  • Multi-Format Compliance Runs: Some trading partners want a shipping label and a content label per carton. Selecting both saved templates for a bulk run renders each data row through every selected layout with the same details.
  • Printer Fleet Differences: The same design previews at 203 dpi for one printer model and at 300 dpi for another; dot dimensions update with the density so field positions can be verified per fleet.
  • Driverless Printing: Copied ZPL text feeds lpr, netcat to port 9100, or a print utility directly, while a PDF export produces a page at the exact physical label size for driver-based printing.
  • Label Archival and Sharing: Every saved layout exports to one JSON file for version control or a coworker, and importing merges that file back in on any machine, since inputs also persist locally between sessions.
  • Proofing Before Production: Bitonal print quality shows the pure black and white output a thermal head produces, catching gray antialiased edges that would dither or vanish on real media.

Always verify a generated label by scanning a printed one before you commit to a run. The preview and the PNG, PDF, and print exports are a software simulation of what a thermal printer puts on media; they are not a print quality grade. Every barcode and MaxiCode symbol is built to its published specification and machine-checked here, but that verifies the encoded data, not the printed result. Printer model, print head wear, darkness setting, ribbon, label stock, and scale all decide whether a symbol reads on the line even when the data underneath it is correct. Re-scan whenever any of those change, whenever a label design changes, and on the first label of a new batch. Where a carrier or trading partner requires a graded label, use a barcode verifier that reports an ISO/IEC 15416 or 15415 grade rather than relying on this tool or on a single successful scan.

Inputs, outputs, and what the ZPL Label Generator computes

What the ZPL Label Generator asks for and what it returns, as a plain list. Defaults, units, and ranges are the ones the form loads with.

Inputs

  • Designer (text lines) / ZPL Code (open existing file) · default: Designer (text lines)
  • Step # (numeric input) · minimum: 0
  • # of labels (numeric input) · minimum: 1
  • Or paste ZPL code (variables in delimiters substitute in real time)
  • Show per-line options (height, align, bold, same row) · default: off
  • Write-in blank (spaces) (numeric input) · default: 8 · range: 0 to 40
  • Size preset · default: 4 x 2 in (shipping)
  • Width (text input) · default: 4
  • Height (text input) · default: 2
  • Inches / Millimeters · default: Inches
  • Print density · default: 203 dpi (8 dpmm)
  • Grayscale (smooth preview) / Bitonal (pure black and white, thermal simulation) · default: Grayscale (smooth preview)
  • Orientation · default: Normal
  • Preview font · default: Helvetica (sans-serif, closest to Zebra CG Triumvirate)
  • Line spacing (numeric input) · default: 1.5 · range: 1 to 4
  • Center all lines vertically as one group · default: on
  • Shrink text to fit the label · default: off
  • Delimiter start (text input) · default: {
  • Delimiter end (text input) · default: }
  • Template name (text input)
  • Saved templates
  • Lock inputs to preset values · default: on
  • Output · default: Single ZPL file (one ^XA block per label)
  • ZPL sent to exports (variables substituted)

Controls

Generate · Reset · Export Templates (JSON) · Generate Bulk · Reset View · Copy Shown ZPL · Copy ZPL