Skip to content

n8n integration

n8n sits exactly where labels get stuck: an order lands in a spreadsheet, a carrier returns a PDF, a WMS drops ZPL on an FTP server, and something has to turn one into the other and get it onto a thermal printer. The LabelZoom community node makes that two steps in a workflow.

The node is the supported path, and the one these docs cover. It handles binary in and out, carries every conversion option, and keeps the wire details out of your workflow — everything below assumes you have it installed.

A n8n workflow showing LabelZoom’s node wired to print a label on a Shopify trigger A n8n workflow showing LabelZoom’s node wired to print a label on a Shopify trigger

Settings → Community nodes → Install, then enter:

n8n-nodes-labelzoom

Self-hosted instances can install it directly:

Terminal window
npm install n8n-nodes-labelzoom

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.

The n8n Community nodes install dialog with n8n-nodes-labelzoom entered as the npm package name The n8n Community nodes install dialog with n8n-nodes-labelzoom entered as the npm package name

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 — see A bad API key does not fail for why that distinction matters.

The LabelZoom API credential in n8n showing the API Key, Max Retries and Base URL fields, with a successful connection test The LabelZoom API credential in n8n showing the API Key, Max Retries and Base URL fields, with a successful connection test


The simplest useful workflow: something produces ZPL, you want a PDF.

  1. Add a LabelZoom node.
  2. Resource: Label · Operation: Convert
  3. Source Format: ZPL · Target Format: PDF
  4. 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.

The LabelZoom node configured to convert ZPL to PDF, with the converted PDF shown as binary output The LabelZoom node configured to convert ZPL to PDF, with the converted PDF shown as binary output

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.

The other direction, and the more common one in shipping workflows.

  1. HTTP Request node — download the carrier’s label PDF, with Response Format set to File so it arrives as binary.
  2. LabelZoom node — Label → Convert, Source Format PDF, Target Format ZPL, Input Type Binary File.

Useful options here:

  • PDF Conversion ModeIMAGE (the default) rasterizes each page and preserves the exact appearance, which is what you want for a carrier label. NATIVE extracts the underlying vector and text.
  • PDF Page Number0-based. Set 0 for the first page; leave it empty to convert every page.

The ZPL comes back as binary and, because ZPL is genuinely textual, 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.

Most label templates are mostly fixed with a few fields that change. Put the values in Options → Variable Data (JSON):

[{ "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, and note that multi-page output is a paid feature.

  1. LabelZoom node — Resource: Printer · Operation: Print
  2. Printer — pick from the list. The dropdown shows each printer’s native format and live status, e.g. Warehouse Zebra — ZPL (ready).

The Printer dropdown in the LabelZoom node listing cloud printers with their native format and live status The Printer dropdown in the LabelZoom node listing cloud printers with their native format and live status

  1. Source Format — leave on Auto-detect unless the document is one of the printer languages, which all look alike on the wire.
  2. 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.

The node returns as soon as the job is accepted:

{ "jobId": "9f8e…", "status": "dispatched", "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.

Print sends an Idempotency Key; repeating a key 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 duplicate shipping label is a real cost. This field is the cheapest insurance against one.

If the label is designed in LabelZoom Studio and published to Print Templates, you don’t need to carry the label code through the workflow at all.

  1. Resource: Printer · Operation: Print Template
  2. 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.

The Template dropdown listing Print Templates, each annotated with its merge field names The Template dropdown listing Print Templates, each annotated with its merge field names

  1. Merge Data (JSON) — the values, keyed by field name:
    {{ JSON.stringify({ orderNumber: $json.number, sku: $json.line_items[0].sku }) }}
  2. Leave Validate Merge Fields on, so a missing field is rejected rather than printed as a blank space on the label.

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.

There’s a Label → Convert Template operation too, which renders a filled template without printing it — useful for a preview or approval step.


The conversion endpoint treats an unresolvable credential as anonymous rather than returning 401. A typo’d key returns a perfectly healthy 200 carrying a watermarked free-tier label. Use the credential’s Test button — it calls a different endpoint that does reject a bad key — and during setup, convert one label and look at it.

Keys created from the dashboard are always test keys (lz_test_): they work everywhere, and they are always 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.

Request throughput is capped, and the cap is noticeably tighter on the Free and Basic tiers — those plans are sized for evaluation and light use rather than sustained automation. If a workflow is doing real volume, moving up a tier is the fix; see Rate limits and plans.

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 honours Retry-After, so an occasional limit is absorbed rather than failing the execution.

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.

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.

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 and TSPL’s BITMAP embed a 1-bpp image, and DPL output opens with a literal STX. Decoding those to a string corrupts every label carrying graphics.