CIRCULATEQR

Bulk QR Codes: Create Hundreds at Once or by API

By the CirculateQR team · Updated · 7 min read

Short answer

To create QR codes in bulk, list every code in a spreadsheet with a unique ID, its destination URL and a name, then generate one image per row. For static codes, a free open-source library such as qrcode for Node.js writes a thousand files in a few seconds. For dynamic codes you can edit and track later, use a QR service’s API to create them in batches. Either way, scan-test a sample from every batch before printing, and keep the spreadsheet as your record of which code went where.

On this page
  1. How should you plan a bulk QR code run?
  2. How do you generate static QR codes in bulk yourself?
  3. How do you print hundreds of different QR codes?
  4. How do you check a bulk batch before it goes out?
  5. How do you track each code in a bulk run?
  6. How does CirculateQR’s batch API work?
  7. Frequently asked questions

Key facts

  • Plan one row per code: a unique ID, the destination, a readable name and any metadata such as SKU, store or batch.
  • Static codes can be generated in bulk for free with an open-source library. They never expire, but they cannot be edited or tracked.
  • A short ID keeps codes simple: https://example.com/r/A7K2Q9 makes a 29 × 29 module code at error correction level M.
  • CirculateQR’s batch API creates up to 1,000 dynamic codes per request on the Stealth plan, so 5,000 codes take 5 calls.
  • Each item in a batch is processed independently: a bad row fails on its own and the rest are created.
  • CirculateQR has no CSV upload in the dashboard. Bulk creation is through the API.

How should you plan a bulk QR code run?

The whole job has six steps:

  1. Build the spreadsheet, one row per code.
  2. Choose static or dynamic for the batch.
  3. Generate the codes with a library or an API.
  4. Prepare the print files in the format your printer wants.
  5. Test a sample of every batch, printed.
  6. Track each code against its row.

The spreadsheet is the part people rush, and the part that causes most reprints. Give every row:

Example rows for a store window campaign
iddestinationnamestore
S26-042-WINhttps://example.com/stores/042Spring 26, store 042, window042
S26-043-WINhttps://example.com/stores/043Spring 26, store 043, window043
  • An ID that never changes. Use a naming convention such as campaign, location, placement. If people will ever type the ID, leave out characters that look alike, such as 0 and O, or 1, l and I.
  • A destination per row. Pointing every code at one page with the ID in the URL is easier to maintain than thousands of separate pages. Add UTM tags if you measure in web analytics; see UTM tracking for print.
  • Short URLs. Every extra character can push the code to a denser version with smaller modules.

Then decide static or dynamic. Static codes are free and permanent but fixed. Dynamic codes can be repointed and counted, but depend on the provider’s service.

How do you generate static QR codes in bulk yourself?

For static codes you do not need a service at all. The open-source qrcode package for Node.js turns a CSV file into one SVG per row. Save your sheet as codes.csv with an id,url header, then run:

// make-codes.js  (npm install qrcode, Node.js 18 or later)
// Simple CSV only: no commas inside values. Use a CSV parser for real data.
const fs = require('node:fs');
const QRCode = require('qrcode');

const rows = fs.readFileSync('codes.csv', 'utf8')
  .trim()
  .split(/\r?\n/)
  .slice(1) // skip the header row
  .map(line => line.split(',').map(cell => cell.trim()));

async function main() {
  fs.mkdirSync('out', { recursive: true });
  for (const [id, url] of rows) {
    await QRCode.toFile(`out/${id}.svg`, url, {
      errorCorrectionLevel: 'M', // L, M, Q or H
      margin: 4,                 // quiet zone, in modules
    });
  }
  console.log(`Wrote ${rows.length} files`);
}

main().catch(err => { console.error(err); process.exit(1); });

In our test it wrote 1,000 SVG files in about four seconds. SVG is vector, so it prints sharply at any size. Change the extension to .png and add a width in pixels if your printer wants raster images. Level M suits most print; use H only when something covers part of the code. The error correction guide explains why. For a handful of codes, the free QR code generator is quicker.

Printing a different code on every piece is called variable data printing. There are two ways to feed it:

  • One image per row. You supply a folder of files named by ID, and the layout pulls in the right file for each record.
  • Encoded at print time. You supply the spreadsheet, and the printer’s software, or your layout tool, draws each code from the URL column. Adobe InDesign’s Data Merge, for example, can create QR codes from a data column.

Ask your printer which they prefer before you generate anything: file format, naming, resolution, and whether the order of rows must match the print sequence. Keep the 4-module quiet zone in the layout, and size the codes with the size guide.

How do you check a bulk batch before it goes out?

  • Check the files. Decode every generated image with a decoding library and compare the result with its row. This catches copy-and-paste and encoding mistakes.
  • Scan printed samples from every sheet or roll: the first, the last and a few at random. For runs of a few hundred, scan every one.
  • Check alignment. In a mail merge, the classic failure is the code for row 41 printed beside the address for row 42. Scan a few pieces and compare the result with the name or number printed on them.
  • Check destinations. Run every URL through a link checker so no code lands on a 404 page.
  • Check dynamic codes are live and on a plan that keeps them active for the life of the print.

How do you track each code in a bulk run?

With static codes, give each row a unique URL or UTM tags and read the visits in your web analytics. With dynamic codes, the QR service counts scans for each code, and metadata ties each one back to its store, SKU or batch. How QR scan tracking works explains what those counts can and cannot tell you.

Polling for stats has a cost at scale. Checking the analytics of 5,000 codes once a day is 150,000 API requests a month. Checking weekly is about 22,000. Webhooks avoid the polling: the service sends your server a message for each scan as it happens.

How does CirculateQR’s batch API work?

CirculateQR has no CSV bulk upload in the dashboard. Bulk creation goes through the API. Batch creation needs a read and write key, which comes with the Stealth plan (100,000 requests a month, unlimited dynamic codes). The Artisan plan gets read-only keys (10,000 requests a month), enough to list codes and read analytics but not to create them. Call the API from your server, never from browser code, because the key is a secret.

Send up to 1,000 codes per request to POST https://circulateqr.com/api/v1/qr/batch:

Authorization: Bearer cqr_live_YOUR_KEY
Content-Type: application/json

{
  "codes": [
    { "destination": "https://example.com/stores/042", "name": "S26-042-WIN", "metadata": { "store": "042" } },
    { "destination": "https://example.com/stores/043", "name": "S26-043-WIN", "metadata": { "store": "043" } }
  ]
}

type defaults to DYNAMIC. The response lists what was created, matched to your rows by index:

{
  "created": 2, "failed": 0, "total": 2,
  "results": [
    { "index": 0, "id": "uuid", "shortId": "abc123", "name": "S26-042-WIN",
      "destination": "https://example.com/stores/042",
      "shortUrl": "https://circulateqr.com/go/abc123", "createdAt": "..." },
    { "index": 1, "id": "uuid", "shortId": "def456", ... }
  ]
}
  • Partial failures. Each item is processed on its own. Failed items appear in an errors list such as { "index": 1, "error": "destination is required" }, and the rest are still created. Retry only the failed rows.
  • Limits. Each batch call counts as one request toward the monthly quota. The API docs also list a per-minute rate limit (10,000 requests a minute on Stealth); over it, the API returns 429 with a Retry-After header.
  • Print files. Each code is stored as a plain 512 px PNG, but the batch response returns links, not artwork. Render print files from each shortUrl with the script above, so you control size, format and quiet zone.
  • Changes later. PATCH /api/v1/qr/:id changes a code’s destination, name or status; the printed short link stays the same. DELETE is a soft delete: the code is deactivated, not erased.
  • Scan events. Webhooks post each scan to your server, signed with HMAC-SHA256, and failed deliveries are retried.
Creating 5,000 dynamic QR codes with five batch API callsSpreadsheet: 5,000 rowsid, destination, name, metadata5 batch calls × 1,000 codesPOST /api/v1/qr/batch5,000 short links backmatch each result to its row by indexRender print files yourselfSVG, your size, 4-module marginPrinter, then scan-testscan samples from every sheet
The worked example: 5,000 shelf-label codes from one spreadsheet, in five batch calls.

Plans and quotas are on the pricing page, and every endpoint is in the API docs.

Frequently asked questions

Can I upload a CSV to CirculateQR to create codes in bulk?

No. CirculateQR’s dashboard has no CSV bulk upload. Bulk creation uses the batch API, which takes up to 1,000 codes per request and needs the Stealth plan. For static codes, you can generate as many as you like yourself with an open-source library, or make them one at a time in the free generator.

How many QR codes can I generate for free?

Static codes made with an open-source library are free and unlimited, and they never expire. CirculateQR’s free plan gives you 10 QR credits a month; up to 5 dynamic codes live at once, each live 14 days unless upgraded or unlocked for $5; unlimited static codes.

Does every code in a bulk run need to be unique?

Only if you want to tell the pieces apart. Unique codes show which store, mailing list or item was scanned, and let you change one destination without touching the others. If every piece leads to the same page and you do not need to compare placements, one code printed on everything is simpler.

What file format should I send my printer for QR codes?

Ask first. Vector files such as SVG or PDF stay sharp at any size and are the safest choice. If the printer wants raster images, export PNGs large enough for the final print size at the resolution they specify. Some printers prefer just the spreadsheet of URLs and generate the codes in their own software.

What happens if one code in a CirculateQR batch request fails?

The others are still created. Each item is processed independently, and the response reports how many were created and failed, with an errors list giving the index of each failed item and the reason. Fix those rows and send them again in a new request.

Last updated . Written by the CirculateQR team. Spotted something wrong or out of date? Email support@circulateqr.com.

Create dynamic QR codes by API

Batch-create up to 1,000 trackable codes per request on the Stealth plan, change destinations later with PATCH, and receive a webhook for each scan.