Bulk QR Code Generator
Paste a list or open a CSV file and every row becomes its own QR code, named from its label, with a repeated label getting -2, -3 in row order, so 500 rows get 500 distinct names, and every code that passes goes into one ZIP with a manifest.csv beside them. Before a code goes into the ZIP it is drawn at the size you chose and read back by jsQR, a decoder that shares no code with the encoder, and what it reads must match the payload byte for byte; a code that fails is marked failed and left out. Each code holds your link, text, contact card or location directly, with no redirect or short link in between, so it never expires and there is no scan counter behind it. The first row can name the columns, or you can pick them by hand, and every row's exact payload is listed on the page before anything is saved. Switch to One code for a single QR code with PNG and SVG downloads. Error correction from L to H, image sizes from 256 to 2,048 pixels, a quiet zone of 4 to 10 modules, a label printed under each code and a logo on a white plate in the middle are all settings, and the settings are remembered in this browser; the rows, the contact details and the logo are not, and nothing is uploaded.
4 rows, 0 files, 0 failed error correction M, no logo quiet zone at least 4 modules
Reading back 0 of 4. Cancel stops after the current code.
A logo is optional. It covers modules in the middle of the code, so each code is read back with the logo in place before it can be saved.
Columns
Which column feeds each part of the code. The first guess comes from the header words, then from the column order.
Every row
The exact payload each code holds, the file it goes in, and what the read back found.
| Row | File | Payload | Status |
|---|---|---|---|
| 1 | table-1.png | https://cafe.example/t/1 | checking |
| 2 | table-2.png | https://cafe.example/t/2 | checking |
| 3 | front-desk.png | https://cafe.example/d/1 | checking |
| 4 | front-desk-2.png | https://cafe.example/d/2 | checking |
Worked examples
- decoded by an independent reader, identical
- 500 uniquely named files, a repeat gets -2, -3 in row order
- kept only if it reads back, otherwise marked failed
Common questions
- How do I make QR codes in bulk from a CSV or Excel file?
- Save the sheet as CSV and press Open CSV file, or select the cells in Excel or Google Sheets and paste them straight into the rows box: a spreadsheet paste arrives tab-separated and is read the same way, and so is a semicolon-separated file. Give it one column for the label and one for the link. A first row of column names such as label, name, url or link is recognised as a header; if the guess is wrong, untick First row is a header, and under Columns you can say which column feeds which part of the code. Every row is drawn and read back on its own, and Download ZIP saves the ones that passed. One batch holds up to 500 rows. A longer list is refused with its row count rather than cut short, so split it into two lists and make a ZIP from each.
- Do these QR codes expire or track scans?
- No. Each code holds the link, text, contact card or location itself. A dynamic QR code from a subscription service holds the service's own short link instead, which redirects to yours, counts the scans and can stop working when the plan ends. Nothing sits between a phone and your link here, so there is nothing to expire and nothing that could count a scan. The other side of that is that a printed code cannot be pointed somewhere else later: to change where it goes, make and print a new one.
- How are the files in the ZIP named?
- From the label column. The label is lowercased and every run of spaces or punctuation becomes one hyphen, while letters in any script are kept, so Front desk becomes front-desk.png and Köln stays köln.png. A label that repeats gets -2, -3 and so on in row order, and a name that would collide with one already used is suffixed again, so 500 rows always make 500 distinct names and the same list always gives the same names. A row with no label is named from its row number, such as row-007. The ZIP also holds manifest.csv, with each row's number, label, file name, read back result and the exact payload inside its code.
- Can I put a logo in the middle of the QR codes?
- Yes. Choose a PNG, JPEG, WebP, GIF or SVG image and it is laid on a white plate in the middle of every code, at about 15, 20, 25 or 30% of the code's width, rounded to an odd number of modules so the plate stays centred, and capped on small codes, never over the three finder squares in the corners. The hint under the logo setting shows the plate the code in view actually gets, such as 9 of 33 modules (27%). Choosing a logo switches error correction to H, the level that can spare the most modules, and you can change it back. A logo covers modules, so every code is read back with the logo in place: at L or M a larger logo often fails, at H it usually passes, and a code that fails is marked failed and is not saved. A code that reads back here can still fail on an older phone camera, so scan one printed code before printing hundreds. The logo stays in this tab and is not remembered.
- What does read back mean, and why would a code fail it?
- After a code is drawn, with its label and logo, at the image size you chose, the finished image is handed to jsQR, a decoder that shares no code with the encoder that made it, and the bytes it reads must be exactly the bytes of the payload. Only a code that matches goes into the ZIP, and in One code mode the download buttons stay off until the code has matched. The usual reason for a failure is a logo too large for the error correction level. A payload too long for the image size is refused before drawing, because every module needs at least 2 pixels. The SVG file is written from the same modules, logo box and label position as the image that was read back.
- What can a code hold: links, text, contact cards or locations?
- Four types, in One code and in a list. A link is kept exactly as typed, except that https:// is added in front of a bare domain such as cafe.example/menu so a phone opens it as a link; javascript: and data: links are refused. Text is kept as typed, in any language, line breaks included. A contact becomes a vCard 3.0 card with a name or an organization plus any of phone, email, website, job title, address and note. A location becomes a geo: URI or a Google Maps link, from decimal degrees, and a pair pasted as 12.9716, 77.5946 is split for you. Payment codes are refused by format: UPI links, crypto payment requests, EMV merchant codes, SEPA transfer codes, Swiss QR-bills and payto: links.
- How much can one QR code hold, and what do L, M, Q and H change?
- At most 2,953 bytes of text at L, 2,331 at M, 1,663 at Q and 1,273 at H; runs of digits pack tighter than that. A payload over the limit is refused with its byte count, never shortened. The level sets how much of a damaged code can still be read, about 7% at L, 15% at M, 25% at Q and 30% at H, and a higher level makes a denser code. The code's square is exactly the size you choose (a label adds a strip below it), with every module a whole number of pixels and the pixels left over added to the margins, so the quiet zone is never smaller than the 4, 6, 8 or 10 modules you picked.
- Is my list uploaded anywhere?
- No. Reading the CSV, drawing every code, reading it back and building the ZIP all happen in this browser tab, and no request carries a row, a payload or the logo. The settings are remembered in this browser so the page opens the way you left it: One code or a list, the type, error correction, image size, quiet zone, the label setting, the logo width, the file format and the location format. The rows, the contact details and the logo are never stored. Start over, at the top of the page, forgets the settings too.
Each code holds your text or link itself, with no redirect in between, so it never expires and no scan is counted. Every code is read back by a separate decoder before it can be downloaded, with a quiet zone of at least 4 modules; a logo covers modules and lowers readability, so a code that fails the read back is marked failed, and one that passes here can still fail on some cameras. Payment codes (UPI, bank transfer, crypto and merchant payment formats) are refused.