Validate and preview labels in CI with npx labelixa: globs, ZPL/EPL/TSPL/CPCL, --json, stable exit codes; GitHub Actions, GitLab, Azure and Bitbucket examples.
The labelixa npm package ships a command-line tool. It lints label files and renders previews inside the pipeline, before anything reaches a printer; it is a thin shell over the API, not a second engine.
Node.js 18+ is all you need. npx fetches the package on each run; install globally for a permanent setup.
npx labelixa --version
# or install once:
npm install -g labelixaOn macOS you can also install it with Homebrew (the tap pulls in Node.js as a dependency):
brew tap labelixa/tap
brew trust labelixa/tap # Homebrew 7+: third-party taps are trusted once
brew install labelixa# lint every label; exit code 1 on error findings
npx labelixa validate "labels/**/*.zpl"
# warnings also fail the build; JSON report for the job log
npx labelixa validate "labels/**/*.zpl" --fail-on warning --json > report.json
# one PNG per label as a build artifact
npx labelixa render "labels/**/*.zpl" --dpmm 8 --width 4 --height 6 --out-dir previews/
# a single label straight to a file
npx labelixa render shipping.zpl --format pdf --out shipping.pdfGlob patterns (**, *, ?) are expanded by the CLI itself, so a quoted pattern works the same on Windows runners.
| Command | Description |
|---|---|
validate <files|globs|-> | Lints label code; exit code 1 at or above the finding threshold. |
render <files|globs|-> | Produces PNG or PDF; --out for one file, --out-dir for many. |
preview <file|-> | Writes one label as PNG to stdout (shortcut for render). |
info | Version, target API and auth mode — no network, never prints the key. |
| Option | Description |
|---|---|
--lang zpl|epl|tspl|cpcl | Printer language; defaults to the file extension, else ZPL. |
--dpmm 6|8|12|24 | ZPL density (default 8 = 203 dpi). |
--width N --height N | ZPL label size in inches (default 4×6). |
--index N | Which label of a multi-label stream to draw (default 0). |
--format png|pdf | Output format; PDF is ZPL only. |
--out PATH | Path of the single output (default stdout). |
--out-dir DIR | One output per input file; the directory is created. |
--fail-on error|warning|info|none | Threshold at which validate exits 1 (default error). |
--json | One machine-readable JSON document on stdout; human messages on stderr. |
The language is chosen from the file extension; --lang overrides it. Density and size apply to ZPL; the other languages read the size from the code itself.
| Extension | Language |
|---|---|
.zpl, .prn | ZPL |
.epl | EPL |
.tspl | TSPL |
.cpcl | CPCL |
| Code | Meaning |
|---|---|
0 | Success; no finding at or above the threshold. |
1 | validate: findings at or above the threshold. |
2 | Usage error: unknown option, no matching file, invalid value. |
3 | API or network error: 4xx/5xx response, still 429 after retries, no connection. |
One document, one result per file. diagnostics is the API's diagnostics record verbatim (code, severity, line/column, message); failed counts files above the threshold, apiFailed files that failed with an API error.
{
"version": "0.4.0",
"command": "validate",
"failOn": "error",
"results": [
{
"file": "labels/ship.zpl",
"language": "zpl",
"ok": false,
"summary": {"error": 1, "warning": 1, "info": 0},
"diagnostics": [
{"code": "ZPL1001", "severity": "error", "line": 1, "col": 4,
"mesaj": "Unknown command: ^QQ",
"url": "https://labelixa.com/zpl/rules/ZPL1001"}
]
}
],
"failed": 1,
"apiFailed": 0
}The key is read ONLY from the LABELIXA_API_KEY environment variable and is not accepted as an argument (ps and shell history leak arguments). LABELIXA_API_URL changes the target (on-prem).
Without a key the anonymous rate limit applies; a 429 is retried at most twice, visibly, after the server's Retry-After. Every request carries X-Client: cli/<version>, so usage is attributed to the tool, not to a person.
On GitHub the shortest route is the Labelixa ZPL Lint action on the Marketplace: it wraps the CLI, writes findings with rule links to the job summary, adds before/after previews on pull requests and uploads the PNGs as an artifact.
name: labels
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: Labelixa/labelixa-action@v1
with:
files: "labels/**/*.zpl"
fail-on: warning
api-key: ${{ secrets.LABELIXA_API_KEY }} # optional; anonymous quota without itInputs: files, fail-on, language, dpmm/width/height, render, previews, artifact, api-key, api-url (on-prem). The key is optional; without it the anonymous rate limit applies. The full list is in the action's README.
The same command on four platforms. The key lives in each platform's secret variable store, never in the pipeline file.
name: labels
on: [push, pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npx labelixa validate "labels/**/*.zpl" --fail-on warning
env:
LABELIXA_API_KEY: ${{ secrets.LABELIXA_API_KEY }}
- run: npx labelixa render "labels/**/*.zpl" --out-dir previews/
- uses: actions/upload-artifact@v4
with:
name: label-previews
path: previews/validate-labels:
image: node:20
script:
- npx labelixa validate "labels/**/*.zpl" --fail-on warning
- npx labelixa render "labels/**/*.zpl" --out-dir previews/
artifacts:
paths: [previews/]
# LABELIXA_API_KEY: Settings > CI/CD > Variables (masked)steps:
- task: NodeTool@0
inputs:
versionSpec: '20.x'
- script: npx labelixa validate "labels/**/*.zpl" --fail-on warning
env:
LABELIXA_API_KEY: $(LABELIXA_API_KEY)
- script: npx labelixa render "labels/**/*.zpl" --out-dir $(Build.ArtifactStagingDirectory)/previews
- publish: $(Build.ArtifactStagingDirectory)/previews
artifact: label-previewspipelines:
default:
- step:
image: node:20
script:
- npx labelixa validate "labels/**/*.zpl" --fail-on warning
- npx labelixa render "labels/**/*.zpl" --out-dir previews/
artifacts:
- previews/**
# LABELIXA_API_KEY: Repository settings > Repository variables (secured)To lint label files before they are even committed, the package ships a pre-commit hook. Add to .pre-commit-config.yaml:
repos:
- repo: https://github.com/Labelixa/labelixa-sdk
rev: v0.4.0
hooks:
- id: labelixa-validate
# optional: fail on warnings too
# args: [--fail-on, warning]The hook runs labelixa validate on staged .zpl, .prn, .epl, .tspl, .cpcl files (language by extension). No secret is required: without LABELIXA_API_KEY in the environment the anonymous rate limit applies. The hook is serial by design — the API's rate limit is shared, so parallel instances would only earn 429s.
The same package is the Node.js SDK: the Client class, renderPng/validate (four languages), renderPdf, toEpl. Usage examples are on the Code Examples page.