Skip to content
UseQR
ESC

Jump to

MOVEOPEN50 places

Developers & agents

Bulk QR generation at scale

For up to 1,000 codes per call, POST to https://useqr.app/api/v1/qr/batch with output url, no key needed, and per-item failures return fixes without failing the batch. For millions, generate locally with a pure-JS library and a worker pool. Either way, keep a manifest mapping each payload to its file, because a QR image is unreadable to humans.

View as MarkdownPaste this page into any AI assistant. It is plain, portable Markdown.

The batch endpoint

One POST, up to 1,000 codes:

curl -s -X POST https://useqr.app/api/v1/qr/batch \
  -H "Content-Type: application/json" \
  -d '{
    "output": "url",
    "style": { "size": 1024, "ec": "Q" },
    "items": [
      { "id": "table-01", "data": "https://example.com/t/01" },
      { "id": "wifi", "type": "wifi", "fields": { "ssid": "CafeGuest", "password": "espresso" } }
    ]
  }'

The limits, and the reasoning behind them:

output Per-call cap Why
url 1,000 nothing is rendered: you get back a deterministic GET URL per item
base64 (rendered PNG) 100 rasterising is real work inside a function budget
with "verify": true 50 every item is rendered and decoded back

output: "url" is the interesting one. Because the GET endpoint is deterministic and cacheable forever, a URL is the image: the batch call does no rendering at all, which is why it scales 10× further. Paste the URLs into documents, emails or a CMS and they render on first view and cache indefinitely (why that works).

Two behaviours worth designing around: items can mix plain data with typed payloads (type + fields, same builders as the WiFi and UPI generators), and a bad item never fails the batch. It comes back with ok: false, an error and a fix, while the other 999 succeed. Check failed in the response envelope ({count, ok, failed, results}) rather than the HTTP status.

Millions: generate locally

Past tens of thousands, the network is the bottleneck, not the maths. Encoding is cheap (the numbers); a pure-JS generator on a worker pool saturates CPU cores without any service in the loop:

// worker.js: one core's share of the CSV
import QRCode from "qrcode";
import { parentPort, workerData } from "node:worker_threads";

for (const { id, url } of workerData.rows) {
  await QRCode.toFile(`out/${id}.png`, url, { width: 1024, errorCorrectionLevel: "Q" });
}
parentPort.postMessage("done");

Shard the input across os.cpus().length workers. Prefer SVG output when the codes are headed to print: the files are smaller and scale-free. For spreadsheet-driven jobs without code, the bulk tool takes a CSV and returns a ZIP, grid PDF or Avery label sheets.

Determinism is your cache

A QR code is a pure function of its inputs. The same data, size, EC level and styling always produce the same matrix, and with a deterministic renderer, the same bytes. So:

  • Key outputs by a hash of the inputs, and never regenerate what you already have. Re-running a million-row job after fixing 40 rows should render 40 codes.
  • Idempotent re-runs fall out for free: generation becomes safe to retry, resume and parallelise without coordination.

Manifest discipline

The expensive failure in bulk jobs is not generation. It is mixing up which code is which, because every QR code looks identical to a human. Rules that prevent it:

  • Name files from your stable identifier (table-01.png), never from row numbers, which change the moment someone sorts the spreadsheet.
  • Write a manifest.csv alongside the output: id, payload, file, generated_at. It is the only way to audit a box of printed stickers six months later.
  • Spot-verify before print: decode a sample (or run verify: true on batches of ≤ 50) and compare against the manifest, the decode-verify loop at batch scale.

FAQ

How many QR codes can I generate in one API call?

UseQR's batch endpoint accepts up to 1,000 items per call with output url, or 100 when the API renders PNGs for you. Calls are keyless and free, so larger jobs are just a loop over chunks.

How do I generate a million QR codes?

Locally: a pure-JavaScript or Python generator on a worker pool, one worker per CPU core, writing SVG or PNG to disk. Encoding is microseconds per code, so disk and rendering dominate. Keep a manifest mapping ids to payloads to files.

How do I keep track of which QR code is which?

Name every file from a stable identifier in your data, and write a manifest CSV of id, payload and filename with the output. Humans cannot tell codes apart by looking, so the manifest is your only audit trail.

Should bulk QR codes be verified before printing?

Yes, decode at least a sample and compare against the manifest. The batch API does this inline with verify true for up to 50 items per call, reporting scannable per item, and a full decode pass locally is cheap.

Try it: free, no signup

  • A free QR code API with no key, UseQR's REST API needs no signup, no API key and no SDK. GET /api/v1/qr?data=hello returns a PNG. The shortest form is /q/hello.png, which drops straight…
  • QR code generation performance, What generating a QR code actually costs: encoding is microseconds, rendering dominates, and PNG rasterisation is the expensive step. Where optimisation pays.
  • Caching and CDN strategy for QR images, QR codes are pure functions of their parameters, so cache them forever: immutable Cache-Control, hash-keyed storage, CDN edge caching, and why cache-busting is wrong.
  • QR codes in CI and automated testing, How to test QR codes in a pipeline: decode assertions, snapshot the matrix rather than the PNG, verify endpoints as gates, and E2E download-and-decode round trips.