n8n integration
The LabelZoom community node converts and prints labels from an n8n workflow. It is verified by n8n, so it installs straight from the canvas; it handles binary in and out, carries every conversion option, and is the path these docs cover.

Video walkthrough
Section titled “Video walkthrough”Install
Section titled “Install”Open the nodes panel on the canvas — +, or press n — search for LabelZoom, and pick it out of More from the community. There is no package name to type. This is the same on n8n Cloud and self-hosted.

Installing is an instance owner or admin action and enables the node for everyone on the instance. If LabelZoom does not appear in the search, verified community nodes are switched off: on n8n Cloud the owner toggles them in the Admin Panel, and self-hosted instances control them with environment variables. A restart may be needed before the node shows up.
Built and tested against n8n 2.x, which itself requires Node 24 or later. The node has no runtime dependencies — it uses n8n’s own HTTP helpers.
Installing by package name
Section titled “Installing by package name”The fallback when verified community nodes are unavailable to you — an older n8n, an instance where an admin has turned them off, or a version you need to pin. Settings → Community nodes → Install, then enter:
n8n-nodes-labelzoomSelf-hosted instances can also install it from the command line:
npm install n8n-nodes-labelzoom

Credentials
Section titled “Credentials”An API key is optional for converting. Leave the credential unset and the node runs on the
free tier: unlimited conversions, watermarked output, first label only, 1 MB request cap. Every
example below works as-is. Add a LabelZoom API credential when you’re ready to ship — see
Authentication. Printing always needs a key with the
print scope; print implies convert, so one key covers both.
| Field | Notes |
|---|---|
| API Key | Optional for Label operations, required for Printer operations |
| Max Retries | 429 and 5xx are retried with exponential backoff. 0 fails fast. Client errors are never retried. |
| Base URL | Only change this if you were given a dedicated endpoint |
The credential’s Test button calls GET /api/v3/templates, not a conversion — a bad key is
rejected there, while the conversion endpoint would accept it anonymously. See
A bad API key does not fail.

Convert ZPL to PDF
Section titled “Convert ZPL to PDF”The simplest useful workflow: something produces ZPL, you want a PDF.
- Add a LabelZoom node.
- Resource: Label · Operation: Convert
- Source Format: ZPL · Target Format: PDF
- Input Type: Text, and put the label code in Label Content — or leave it on Binary File and point Input Binary Field at a file from the previous node.
The result comes out as a binary field (named data by default), ready for Google Drive,
Dropbox, an email attachment, or an HTTP response.

Set label size and density under Options:
| Option | Value |
|---|---|
| Label Width (Inches) | 4 |
| Label Height (Inches) | 6 |
| DPI | 203 |
Leave width and height unset to have LabelZoom detect the size from the source.
Convert a carrier PDF to ZPL
Section titled “Convert a carrier PDF to ZPL”The other direction, and the more common one in shipping workflows.
- HTTP Request node — download the carrier’s label PDF, with Response Format set to File so it arrives as binary.
- LabelZoom node — Label → Convert, Source Format PDF, Target Format ZPL, Input Type Binary File.
Useful options:
- PDF Conversion Mode —
IMAGE(the default) rasterizes each page and preserves the exact appearance, which is what you want for a carrier label.NATIVEextracts the underlying vector and text. - PDF Page Number — 0-based. Set
0for the first page; leave it empty to convert every page.
The ZPL comes back as binary and as a text field on the node’s JSON output, so you can pipe
it straight into a downstream node without decoding the binary yourself.
Fill variable data
Section titled “Fill variable data”Put the values in Options → Variable Data (JSON), keyed by the template’s merge field names:
[{ "sku": "A-100", "qty": "12" }, { "sku": "A-101", "qty": "5" }]Each array entry produces one label. Two entries render the template twice — two pages in a PDF, two concatenated blocks in ZPL. Map it from the incoming item with an expression:
{{ JSON.stringify($json.rows) }}See Multi-label jobs for how each target format handles more than one label. Multi-page output is a paid feature.
Print to a cloud printer
Section titled “Print to a cloud printer”- LabelZoom node — Resource: Printer · Operation: Print
- Printer — pick from the list. The dropdown shows each printer’s native format and live
status, e.g.
Warehouse Zebra — ZPL (ready).

- Source Format — leave on Auto-detect unless the document is one of the printer languages, which all look alike on the wire.
- Point it at your binary field or label text.
You do not need to convert first. If the document isn’t in the printer’s native format,
LabelZoom converts it in transit — a carrier PDF sent to a Zebra becomes ZPL automatically.
Every transform option from Convert works here too, even when no format change happens, so
rotation: 90 on the way to the printer is a one-field change.
Print copies
Section titled “Print copies”Copies sends the job to the printer this many times, from 1 to 9999. It is on both Print and Print Template, from n8n-nodes-labelzoom 1.2.0.
- Leave it at 1 (the default) to send the job once, exactly as before.
- A quantity already in the label multiplies. A label carrying a ZPL
^PQ3with Copies set to 5 prints 15. - A job holding several labels prints collated (A, B, A, B), as one job. The node’s output
reports the
copiesthe job was accepted with —nullwhen Copies was left at 1.
Copies takes an expression, so the count can come from the incoming item:
{{ $json.quantity }}A number that arrives as text, such as "25" from a spreadsheet or CSV, is accepted. Anything
that isn’t a whole number from 1 to 9999 fails the item before a request is sent.
With Copies above 1, the LabelZoom Print Agent serving
the printer must be up to date; an older one fails the item with a 422
(agent_update_required) and nothing prints. For a large run of a complex label, putting the
quantity in the label itself (such as a ZPL ^PQ) usually prints faster — see
Printing copies.
Accepted is not printed
Section titled “Accepted is not printed”The node returns as soon as the job is accepted:
{ "jobId": "9f8e…", "status": "dispatched", "copies": null, "printerId": "b2c3…" }dispatched means an online agent has the job. queued means every bound agent is offline and
it will print when one reconnects. Neither means the label came out of the printer — only
the agent moves a job to completed.
If the workflow needs to know it actually printed, turn on Wait for Completion: the node
polls the job until it reaches completed or failed, or the timeout expires. Otherwise, add a
later Printer → Get Job step with the jobId.
Prevent duplicate prints
Section titled “Prevent duplicate prints”Print sends an Idempotency Key; repeating a key for the same request returns the original job instead of printing again. The default is:
{{ $execution.id }}-{{ $itemIndex }}which makes a retried step safe. Set it from a stable business value to make a whole workflow re-run safe too:
{{ $json.orderNumber }}A key identifies the whole request, Copies included. Repeating it with a different document,
different merge data, a different printer or template, different options, or a different Copies
fails the item with a 422 (idempotency_key_reused) instead of replaying the original job.
So when a workflow deliberately reprints — or prints the same order again at a new quantity —
give that print a key of its own, for example
{{ $json.orderNumber }}-reprint-{{ $execution.id }}. See
Idempotency.
Print a designed template
Section titled “Print a designed template”If the label is designed in LabelZoom Studio and published to Print Templates, you send only the values — no label code in the workflow.
- Resource: Printer · Operation: Print Template
- Pick the printer, then the template. The template dropdown shows each template’s merge
fields, so you can see what data it wants — e.g.
Shipping Label — orderNumber, sku.

- Merge Data (JSON) — the values, keyed by field name:
{{ JSON.stringify({ orderNumber: $json.number, sku: $json.line_items[0].sku }) }}
- Leave Validate Merge Fields on, so a missing field is rejected rather than printed on
the label as the literal text
null— see Merge fields. - Copies — how many times to send the label to the printer. Leave it at 1 to send it once; see Print copies.
Send one object per item. n8n already runs the operation once per input item, so a batch of orders is a batch of items, and each gets its own job and its own idempotency key.
Example: print a stack of price tags
Section titled “Example: print a stack of price tags”Pick a product, enter how many tags you need, and print them. Anything that hands the node a product and a quantity works — a row from a product sheet with a quantity column, an order line, or an n8n Form asking for a SKU and a count, followed by a lookup of that product:
{ "sku": "A-100", "description": "Widget, blue", "price": "4.99", "quantity": 25 }Then a LabelZoom node — Printer → Print Template, your price-tag template, and:
| Field | Value |
|---|---|
| Merge Data (JSON) | {{ JSON.stringify({ sku: $json.sku, description: $json.description, price: $json.price }) }} |
| Copies | {{ $json.quantity }} |
That sends the tag to the printer 25 times as a single job. Design the template to print one tag: a print quantity built into the template multiplies with Copies. Keep the default idempotency key here rather than keying on the SKU — printing the same tag again later is the point, and a SKU key would replay the first job, or be refused with a different Copies.
There’s also a Label → Convert Template operation, which renders a filled template without printing it — useful for a preview or approval step.
Production notes
Section titled “Production notes”Validate the key by converting, not by status code
Section titled “Validate the key by converting, not by status code”A typo’d key returns a perfectly healthy 200 carrying a watermarked free-tier label, because
the conversion endpoint treats an unresolvable credential as anonymous. Use the credential’s
Test button — it calls an endpoint that does reject a bad key — and during setup, convert
one label and look at it. See
A bad API key does not fail.
Test keys and live keys
Section titled “Test keys and live keys”Keys created from the dashboard are always test keys (lz_test_): watermarked and never
billed. Production keys (lz_live_) are provisioned on Pro and above. A workflow that “works
fine but watermarks in prod” is nearly always this, not a configuration problem. See
Test keys and live keys.
Rate limits
Section titled “Rate limits”The throughput cap is noticeably tighter on the Free and Basic tiers — those plans are sized
for evaluation and light use. The budget is shared by everything using the same API key, so
running more workflows in parallel does not buy more throughput; size any Split In Batches loop
with that in mind. The node retries 429 and 5xx with backoff and honors Retry-After, so an
occasional limit is absorbed rather than failing the execution. See
Rate limits and plans.
Never retry an auth failure
Section titled “Never retry an auth failure”The node does not retry 401 or 403, and neither should anything else calling the API.
Repeated authentication failures are themselves rate limited, and the effect is not scoped to
the workflow that caused them — hammering a bad credential can lock out every other workflow
on the same n8n instance. If you set Retry On Fail on the node, keep the attempt count low.
Secrets
Section titled “Secrets”The API key is a bearer credential: anyone holding it can spend your quota. Keep it in an n8n credential, never in a node parameter or an expression.
Calling the API directly
Section titled “Calling the API directly”The node is the supported way to reach LabelZoom from n8n. If you need raw HTTP anyway — from a Code node, or for something the node doesn’t cover — start from Supported formats and the JavaScript Quickstart.
One trap to carry over: take the response as binary. Five of the thirteen targets are
binary, and epl, tspl and dpl come back as text/plain but can inline raw bytes — EPL’s
GW, TSPL’s BITMAP, and DPL’s leading STX. Decoding those to a string corrupts every label
carrying graphics — see Supported formats for why.
See also
Section titled “See also”- LabelZoom on n8n.io — the verified integration listing
- Supported formats — the full source/target matrix and content types
- Conversion parameters — every option behind the node’s Options collection
- Cloud Print API — the printer, job, and agent endpoints the Printer resource wraps
- Errors — status codes and retry guidance
- JavaScript Quickstart — for a Code node, or anywhere you’d rather call the API directly