Bulk workflows

How to Create Bulk QR Codes from Excel or CSV

If the URLs already live in a spreadsheet, there is no reason to create codes one at a time. The production route is Excel → CSV → validate → preview → activate, and the word carrying the weight is validate: three hundred rows is not three hundred production-ready QR codes until something has checked them.

Written by
VastQR Product & Editorial Team
Last updated
On this page
  1. Structuring the sheet
  2. What one row means
  3. Exporting to CSV
  4. Validating the batch
  5. Duplicate destinations
  6. Designing the batch
  7. The activation manifest
  8. Which file format to print
  9. After the codes exist
  10. FAQ

Structure the sheet before you think about QR codes

Keep the import schema small even when the internal workbook has thirty columns. Two columns do the job:

titledestination_url
Product Card 001https://example.com/product/001
Richmond — Table 21https://example.com/menu
North Entrance — Poster Aexample.com/summer
SKU-884 — Box Inserthttps://example.com/sku-884

A bare host like example.com/summer is normalized to https://example.com/summer on import. Anything that is not a usable web destination stays invalid rather than being guessed at, which is the behaviour you want when the alternative is printing it.

Header names the importer recognises
The destination column may be called destination_url, destination or url. The title may be title or name. A file with no header line at all is read as one destination per line.

Decide what one row means

Before generating anything, define the identity model. Does a row mean one store, one table, one SKU, one sign, one flyer variant, one campaign placement? That single decision drives your titles, your analytics and every bulk change you will ever make.

If three hundred rows are all called QR Code, the library becomes useless the first time one printed asset needs a different destination from the other 299.

Titles that survive contact with reality

Good titles answer: where is this code, in the physical world?

  • Richmond — Table 21
  • North Entrance — Poster A
  • SKU-884 — Box Insert
  • Trade Show — Booth Backdrop

The best title is not the tidiest one. It is the one an operator who did not create the batch can find in six months.

Exporting from Excel

  1. Save or export the worksheet as CSV

    Only the active sheet is exported. If the workbook has several tabs, make sure you are on the right one.

  2. Check that formulas exported as values

    If destinations are built by formula, confirm the CSV holds the computed URLs rather than anything stale or an error string.

  3. Eyeball a few rows before importing

    Look specifically for:

    • blank lines in the middle of the data;
    • commas inside unquoted titles;
    • URLs left over from a previous campaign;
    • placeholder text nobody replaced;
    • schemes that are not http or https;
    • duplicate rows that may or may not be intentional.
  4. Paste or upload it

    Both routes run through the same parser, so the same bytes produce the same rows, the same normalized destinations and the same ready count either way.

Validate before you create, not after you print

A good importer does not turn uncertainty into three hundred production codes. The preview separates rows that are ready from rows that need attention, and shows the destination it will actually store — not the raw text you pasted.

The VastQR bulk preview showing a parsed batch: a count of rows that are ready, a row flagged as needing attention with its reason, and the normalized destination that will be stored for each row.
The ready count is the number of codes activation will create. If your sheet has 200 rows and this says 197, three rows will not become codes until they are fixed.

The economics here are lopsided in a way worth stating plainly: validating costs a minute, and a packaging reprint costs days and thousands of dollars.

Already have your spreadsheet?

Upload or paste the CSV and see exactly which rows are ready — before signing up, and before paying.

Duplicate destinations are usually correct

Two rows can legitimately share one URL:

  1. Table 1
  2. Table 2
  3. Table 3
Three placements, one menu URL, three separate codes.

The destination is identical; the physical placements are not. If you want to know which table actually gets used, they need separate QR identities.

Do not deduplicate by URL
Automatically collapsing rows that share a destination destroys placement-level identity, and with it every question you might later want to ask about which placement worked.

Design the batch once, then handle exceptions

Bulk generation should be bulk-native. Set the supported design once for the whole batch and preview it. If a subset needs something different later, select those rows and apply the exception rather than rebuilding the batch by hand.

The operating principle is: brand once, change exceptions deliberately. Both halves matter — the second one is what stops a “consistent” batch from being a batch you cannot vary.

Read the manifest before you activate

Activation is the moment the batch becomes real infrastructure, so it is the moment the commitment should be stated in full. Before signup or payment you should be able to see:

  • how many dynamic codes will be created;
  • how many rows are excluded, and why;
  • the design that will be applied;
  • that destinations stay editable after printing;
  • the price and the active-code allowance.

The buyer should never have to guess what the button is about to create.

Which file format to send to print

FormatUse it whenWatch out for
SVGThe artwork may be resized in a design workflowNothing much — vector edges stay crisp at any size
PNGThe downstream workflow requires raster artPixel count at the FINAL physical size, not the nominal DPI of the document
PDFThe printer or layout workflow expects a documentDo not assume PDF automatically means vector — verify the proof

Whichever you choose, print one real proof at final size and scan it before approving the run. A format decision cannot rescue a code that is physically too small.

How big the printed code needs to be →

Generation is the start of the lifecycle

A manufacturer with 500 product inserts does not have a generation problem. They have five hundred routing assets distributed across markets, some sharing destinations, several localised, all of them physically unreachable once shipped.

The fragile version of that project generates 500 images and finds the bad URLs after the boxes are printed. The safe version validates, fixes the exceptions, previews, activates, tests a sample, and only then prints.

Afterwards, the library is what you actually live in — searching, filtering, editing destinations, pausing, re-downloading, and checking which codes are receiving scans.

Keeping hundreds of printed codes under control →

Frequently asked questions

Can I create multiple QR codes from one Excel file?
Yes. Export the sheet as CSV and use one row per QR code. The import reads a destination column and an optional title.
Can I upload an .xlsx file directly?
No. The current workflow accepts CSV. Excel exports CSV in two clicks, and CSV is also what Google Sheets, Numbers and most internal systems can produce, so it is the interchange format.
Does every row need a unique URL?
No. Different physical placements can and often should share a destination while remaining separate QR codes, because the placement is what you want to measure and manage.
Can I change the URLs after the codes are printed?
Yes, for dynamic codes. The printed pattern stays the same and the destination behind it changes.
What happens to invalid rows?
They are held out of activation and shown with the reason. Valid rows stay ready, so one bad cell does not block the batch.
What if I need more than 500 active codes?
The current plan is built around up to 500 active dynamic codes. If your project genuinely needs more active at once, treat that as a product-fit question before you commit to a print run — not something to solve by splitting the work across accounts.

Working in Google Sheets instead? The Sheets-specific workflow is here →