How to generate QR codes in bulk from a spreadsheet
One QR code is a two-minute job. Two hundred — table numbers, asset tags, conference badges, a unique link per printed flyer — is where people either lose an afternoon copy-pasting or sign up for a service that meters them. The right shape is a spreadsheet in, a folder of images out, and nothing in between that can expire.
The five-minute version
- In your spreadsheet, make sure there is one row per code, with a content column (the URL or text the code should hold) and a label column (a short name for the file and the caption).
- Export as CSV. Open it in a text editor once to check the content column really contains what you think — no stray spaces, no formulas, no
#REF!. - Paste or upload the CSV into a bulk static QR generator, map the two columns, and check the preview of the first few codes.
- Export a ZIP (one image per row) for digital use, or a print sheet PDF if the codes are going straight onto labels or cards. Scan two or three at random before you print the run.
Get the sheet into shape
The generator does not care about your spreadsheet’s layout, only about two columns. Everything else can stay.
- Content — exactly what the scanner should receive. For a link, the full URL including
https://. For WiFi, aWIFI:T:WPA;S:name;P:password;;string. For a contact, a vCard block. For an asset tag, the serial number itself is fine — inventory apps read plain text. - Label — the human name: “Table 12”, “ASSET-0417”, “Ana Ruiz”. It becomes the file name in the ZIP and the caption under each code on a print sheet, which is how you match a printed code back to a row without scanning it.
If your content is a URL that differs per row only by an ID, build it with a formula (="https://yoursite.com/t/"&A2) and copy the values, then export. Google Sheets: File → Download → CSV. Excel: File → Save As → CSV UTF-8. Numbers: File → Export To → CSV. Keep the header row — a good generator uses it to name the columns in the mapping step.
Static or dynamic: it matters more at volume
The static-vs-dynamic distinction is a preference for one code and a structural decision for three hundred. A dynamic batch is three hundred redirects on someone else’s server. Every one of them lives as long as the subscription does — and every one of them is on a physical object you chose because you did not want to reprint it.
This is also why free bulk tiers stop at 50 or 100: each dynamic code is a hosted thing that costs the service money forever, so they meter it. A static code costs nobody anything after it is drawn. A client-side generator can produce 5,000 as easily as 5, and none of them can be switched off — including by the generator going out of business.
The one thing dynamic batches genuinely offer is per-code scan counts. You can keep that without the dependency: put a unique query parameter in each URL (?t=12, ?tag=0417) and count them in your own analytics. The code stays static; the tracking stays yours.
Preview before you commit
Bulk mistakes are expensive because they are multiplied. Before exporting anything, look at the first few rendered codes and scan one with your phone. The three failures worth catching:
- Wrong column mapped. The preview shows the label as the code’s content, or vice versa. Swap the mapping; do not touch the sheet.
- Header row encoded as a code. You now have a code that says “url”. Tick “first row is headers”.
- Content too long to scan small. A vCard with five phone numbers or a 200-character link makes a dense code that fails at label size. Shorten the content, or print larger — the print-size guide has the numbers.
ZIP or print sheet?
- ZIP of PNGs when each code goes somewhere different: into a badge template, a mail merge, a CMS, an inventory system. One 1024 px image per row, file named after its label, so
Table-12.pngis findable without opening it. - Print sheet PDF when the codes are the printed thing: a grid of codes with captions on A4 or Letter, cut or stuck onto tables, equipment, seats. Choose the column count to match the physical size you need per code — fewer columns, bigger codes. Getting that sheet onto label stock intact is its own job: printing QR code labels covers the print-dialog setting that shrinks the grid, and when a die-cut sheet is the wrong tool.
Either way, keep the CSV. In a year, when three tables are replaced or a batch of tags is lost, you regenerate exactly those rows — and because the codes are static, the new ones are pixel-for-pixel identical to the originals. (If your batch is an asset register, the asset-tag guide covers the ID scheme and label sizes; if the batch is one code per SKU headed for a print run, the product-packaging guide covers the URL scheme and the press; if it is one code per table for order-at-table, the restaurant-tables guide covers whose URL to encode and the seated scan; if it is one unique code per printed voucher, the coupons-and-vouchers guide covers the ID scheme and why the expiry lives in your till, not the code; if it is one code per active listing for an estate agency’s riders and window cards, the real-estate-signs guide covers the two-codes-two-lifespans split and outdoor sizes; if it is one single-use code per admission, the event-tickets guide covers the random-ID scheme and the first-scan-wins door list.)
Before the print run
- Scan three codes at random from the exported set — first, last, one in the middle.
- Print one sheet on plain paper first and hold it against the label stock; then print one on the real stock and scan it from the real distance before printing the rest (why, and what the proof sheet tells you).
- Check high contrast and a clear quiet zone; styling that looks fine at 1024 px can fail on a 2 cm label.
- Store the CSV and the export together, named by date. The batch is reproducible for as long as the sheet exists.