Bulk workflows

How to Create Bulk QR Codes from Excel or CSV

There are three honest ways to get QR codes out of Excel: a formula that puts a static image in a cell, a tool that swallows the .xlsx whole, and exporting CSV into a platform that manages the codes afterwards. VastQR is the third — 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. Which Excel route
  2. The in-cell formula
  3. Direct .xlsx importers
  4. Structuring the sheet
  5. What one row means
  6. Exporting to CSV
  7. Validating the batch
  8. CSV validator
  9. Duplicate destinations
  10. Designing the batch
  11. The activation manifest
  12. How many to test
  13. Which file format to print
  14. .xlsx tools vs this workflow
  15. After the codes exist
  16. FAQ

Which Excel route is the right one?

These are genuinely different products, not three brands of the same thing. Pick by what has to be true after the codes exist.

What you needThe routeWhat it costs you
A few static QR images sitting in cellsAn Excel formula plus a QR image APIStatic forever, and the formula is not available in every Excel
Upload the .xlsx untouchedA tool that imports XLSX directlyBehaviour varies by tool — check what it does with formulas, sheets and blank rows
Hundreds of codes you can edit after printingExcel → CSV → a managed dynamic QR platformOne export step, and a dependency on the redirect service
Changing a destination after the runDynamic codes, whichever route created themHosted redirect dependency
Scan data per printed placementDynamic codesAnalytics that need interpreting, not just reading

VastQR implements the third row. The other two are described below honestly rather than dismissed, because a page that pretends the formula does not exist is a page nobody trusts on the rest.

Option 1: a static QR image straight from a cell

Modern Excel can display an image returned by a URL, so combining that with a QR image API puts a code directly in the sheet. With the value to encode in A2:

=IMAGE("https://quickchart.io/qr?text=" & ENCODEURL(A2))

ENCODEURL makes the cell value safe to put in a query parameter, the API returns a QR image for it, and IMAGE renders that image in the cell.

This is not a universal Excel formula
Microsoft documents IMAGE() in current Microsoft 365 and Excel 2024 builds, and documents that ENCODEURL() is not available in Excel for the web or Excel for Mac. Check your own build before planning a workflow around it — and note that the formula sends each cell’s value to a third-party service, so it is the wrong tool for tokens, credentials or anything confidential.

The deeper limit is not compatibility, it is permanence. The formula produces a static image. Change the cell later and the workbook renders a different one; the code you already exported, placed in artwork and sent to a printer does not change, because nothing about it can.

Whether that matters for what you are printing →

Option 2: a tool that imports .xlsx directly

Some bulk QR tools accept .xlsx and .xls, read multiple sheets, and let you map columns in their interface. That is genuinely convenient when you would rather not export anything.

It is also not automatically the better workflow, because the convenience is at the upload step and the risk is everywhere after it. Worth establishing before you trust one with a production run:

  • what happens to cells that are formulas rather than values;
  • how merged cells are read;
  • which sheet it picks when the workbook has several;
  • whether blank rows are skipped or become empty codes;
  • whether it infers the header row correctly;
  • whether the output is static or dynamic;
  • whether the file is parsed in the browser or uploaded to a server;
  • how the downloaded filenames map back to spreadsheet rows.

VastQR does not claim native XLSX import. One export step buys a format with no hidden behaviour in it, which is the trade this workflow makes deliberately.

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.

What the validator actually does, row by row

Paste this into the preview and you can watch each rule fire. These are not illustrative values — they are the real behaviour of the importer:

title,destination_url
Valid One,https://example.com/one
Valid Two,https://example.com/two
Missing Scheme,example.com/three
Broken Row,not-a-valid-url
Unsafe,javascript:alert(1)
RowWhat the importer doesWhat gets stored
https://example.com/oneAccepted as writtenhttps://example.com/one
example.com/threeNormalized — a bare host is a destination, not a mistakehttps://example.com/three
not-a-valid-urlRejected. Not guessed at, not silently droppednothing — the row is held back
javascript:alert(1)Rejected. Only web destinations are acceptednothing

Three rows in, two codes out, and one row waiting for a human. That is the number the activation manifest shows, and it is deliberately not the number of lines in your file.

The VastQR bulk preview after pasting three CSV rows. Row 1, Valid One, was entered as https://example.com/one and is Ready. Row 2, Valid Two, was entered as the bare host example.com/three and the destination column shows it stored as https://example.com/three, also Ready. Row 3, Broken Row, was entered as not-a-valid-url and is marked Fix URL. The header reads two valid dynamic QR codes ready, one row needs a valid http(s) URL, and the panel below repeats it as two ready and one excluded, alongside $19 a month and up to 500 active dynamic QR codes.
The same three rows from the block above, pasted into the live generator. Row 2 is the one to check: it went in as a bare host and comes out with a scheme, counted as ready. Row 3 is refused rather than guessed at. Nothing is created — the batch only exists after activation.

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.

QR CSV Validator

Check a sheet against the rules the importer actually applies, before you create anything. This runs the same parser and the same destination rules the import runs, in your browser — the file is not uploaded.

Your CSV
or drop a file here · .csv up to 2MB

Your CSV is checked in this browser. The file is read and parsed locally and is never uploaded.

A header row naming destination_url, destination or url is detected automatically. Without one, every line is read as data — a plain column of links is valid input. title is optional.

Choose or paste a CSV to check it against the same rules the importer uses.

This runs the importer’s own parser and destination rules, so a row it accepts here is a row the import accepts. It does not check that a destination is online, correct, or the page you meant — only that it is a usable web address.

Ready to turn a validated sheet into codes? Create the batch with VastQR.

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.

Validate every row; physically test a sample

These two are different jobs and people routinely do one and claim the other. Row validation is automated and should cover everything — every row passes the importer or it does not become a code. Physical scan testing is manual, so it covers a sample, and the sample has to be chosen rather than grabbed.

Test at least one printed code from every materially different:

  • physical size;
  • substrate and finish;
  • placement and viewing distance;
  • output treatment;
  • destination pattern.
One successful scan is not a 500-code proof
If the run is expensive, raise the sample rather than the confidence. A batch is only as deployable as its worst-printed member, and that member is never the one on your desk.

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 →

A direct .xlsx tool against this workflow

A comparison table is only worth reading if it can lose a row. This one does.

RequirementA direct XLSX generatorThis workflow
Upload .xlsx without exportingOften yesNo — export CSV first
CSV importUsuallyYes
Static QR imagesOften the default outputNot the focus — VastQR creates managed dynamic codes
Destination editable after printingDepends on the toolYes
A managed library afterwardsDependsYes
Redirect-level scan dataDependsYes
Validation before anything is createdVariesYes, with the ready count stated
Up to 500 active dynamic codesTool-specificThe current plan

The first row is a genuine loss and it stays in. If not exporting a file is the thing you care most about, a direct XLSX tool is the better fit and you should use one.

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.
Can I create QR codes in Excel with a formula?
In supported versions, yes — IMAGE() can display an image returned by a URL, and combining it with ENCODEURL() and a third-party QR image API puts a code in a cell. Microsoft documents that ENCODEURL is not available in Excel for the web or Excel for Mac, so it is not a universal formula. What it produces is a static image: change the cell later and the workbook renders a new one, while anything already exported and printed is unchanged.
Should I generate static or dynamic QR codes from Excel?
Static when the encoded value is genuinely permanent and you would rather not depend on a hosted redirect. Dynamic when the destination might move after printing, when you want redirect-level scan data, or when the batch is large enough that managing it matters more than generating it.
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 →