via.placeholder.com/qr · /barcode

QR codes and barcodes

Encode any text as a QR code. Or get a barcode that scans but can never match a real product: test-safe EAN-13, UPC-A, EAN-8, ITF-14 and GS1-128 numbers from the ranges GS1 reserves for internal use and examples.

QR codes

https://via.placeholder.com/qr/<url-encoded text>[.png|.svg|.webp|.gif|.jpg][?size=&ecc=&margin=&fg=&bg=]
https://via.placeholder.com/qr.png?text=<text>
https://via.placeholder.com/qr?data=<text>&format=svg
PartValuesDefault
textEverything after /qr/, slashes included, minus a trailing image extension. ?text= or ?data= (also chl, content, value, url) win over the path. Up to 1024 bytes of UTF-8.https://placeholder.com/
format.png, .svg, .webp, .gif, .jpg (or ?format=). Other extensions, AVIF included, get a PNG.png
size16 to 2000 px (also s, w, width, chs=150x150). The image is exactly that square; modules are whole pixels and the rest goes into the quiet zone. If the code doesn't fit at 1 px per module, the image grows.200
scale1 to 50 px per module, instead of size: the image size follows from the module count.none
eccError correction L, M, Q, H (also low…high, 7/15/25/30, chld=H|4).M
marginQuiet zone in modules, 0 to 20.4
fg, bg3 or 6 digit hex (with or without #), a CSS colour name, or r-g-b. bg=transparent works for PNG, SVG, WebP and GIF.black on white

Percent-encode URLs. An unencoded URL works in the path (/qr/https://example.com/?id=5): its own query keys are put back onto it. But keys that clash with ours (size, color, margin, …) are read as ours, so encode the URL when it must be exact.

Byte mode is UTF-8 without ECI, never Micro QR, and the error correction is never raised behind your back, so the module count is predictable. The X-QR-Version header says which version and level you got, e.g. 2-M. /qrcode/… is an alias, and Google Charts parameters (chl, chs, chld) are understood.

Barcodes

https://via.placeholder.com/barcode/<type>/<value>[.png|.svg|.webp|.gif|.jpg]
https://via.placeholder.com/barcode/<type>         a test-safe code
https://via.placeholder.com/barcode/<type>?seed=7  another test-safe code
https://via.placeholder.com/barcode/<type>/test.json?count=10 a list of test-safe codes (max 100)
https://via.placeholder.com/barcode/<digits>       type guessed from the length
TypeAliasesValue
ean13ean, ean-13, gtin13, jan12 digits (check digit computed) or 13
upcaupc, upc-a, gtin1211 or 12 digits
ean8gtin87 or 8 digits
itf14itf, gtin1413 or 14 digits
gs1-128gs1128, ean128, ucc128Application Identifiers in brackets: (01)09521234500001(10)ABC
code128c128, code-1281 to 80 ASCII characters
code39c39, code-391 to 80 of 0-9 A-Z - . $ / + % and space

/barcode/<digits> guesses: 8 digits EAN-8, 12 UPC-A, 13 EAN-13, 14 ITF-14, anything else Code 128. An EAN-13 without its check digit has 12 digits and would be read as UPC-A, so name the type. /barcode/qr/<text> makes a QR code. The value can also come from ?value=; spaces and hyphens in numeric values are dropped.

OptionValuesDefault
scalePixels per narrow bar, 1 to 10.2
widthPicks the largest scale that fits and pads the quiet zones to exactly this width.none
heightBar height, 10 to 1000 px.proportional to the symbology
hrthrt=0 hides the human-readable digits (also text=0, includetext, displayvalue).on
marginQuiet zone in bar widths. Never below the symbology's own minimum (EAN-13 11/7, UPC-A 9, EAN-8 7, ITF-14 10, Code 128/39 10).the minimum
bearerITF-14 bearer bars; bearer=0 turns them off.on
checkfix corrects a wrong check digit, keep renders it as given, mod43 adds Code 39's optional check character.reject wrong digits
prefixWhich test-safe range: company, region or demo (see below).per type
seedAny string; picks another test-safe code.0
fg, bgAs for QR codes.black on white

Test-safe codes

Leave out the value (or write test, random, sample, demo) and you get a code from a GS1 number range that no product on a shop shelf can carry. It is computed from a hash of the type, range and seed, so the same URL always gives the same code, with a valid check digit. The X-Barcode-Test header names the range.

TypeDefault rangeOther ranges (?prefix=)
EAN-13company: GS1 Prefix 04 (040–049), Restricted Circulation Numbers within a companyregion: 02 and 20–29; demo: 952, for demonstrations and examples
UPC-Acompany: number system 4 (= GS1 Prefix 04)region: number system 2
EAN-8company: GS1-8 Prefix 200–299demo: 952
ITF-14demo: GTIN-14 on GS1 Prefix 952none
GS1-128demo: (01) GTIN-14 on 952 plus (10)TEST and four digitsnone
Code 128, Code 39TEST- plus six digits (no GS1 meaning)none
{
  "type": "ean13", "symbology": "EAN-13", "seed": "7", "count": 2,
  "range": "GS1 Prefix 04 (040-049): Restricted Circulation Numbers within a company",
  "source": "GS1 General Specifications Release 26.0 (Jan 2026), …",
  "codes": [
    {"value": "0488626180328",
     "png": "https://via.placeholder.com/barcode/ean13/0488626180328.png",
     "svg": "https://via.placeholder.com/barcode/ean13/0488626180328.svg"},
    …
  ]
}

Check digits and errors

Give a numeric code without its check digit and it is computed. Give one with a wrong check digit and you get 400 Bad Request: an error image in the format you asked for, with the expected digit in the image and in the X-Placeholder-Error header. That way a typo shows up where the barcode should have been.

Other errors (an unknown type, a value a symbology can't encode, QR text over 1024 bytes) are also 400 error images, cached for a day. JSON endpoints answer errors in JSON.

Formats and headers

HeaderValue
X-QR-VersionQR version and error correction level, e.g. 2-M
X-Barcode-TypeSymbology, e.g. EAN-13
X-Barcode-ValueThe encoded value, check digit included
X-Barcode-TestThe test-safe range, when the code was generated for you
X-Barcode-WarningSet when check=keep rendered a wrong check digit
X-Placeholder-ErrorWhat went wrong, on 400 responses

QR and barcode files carry the same embedded marker as avatars and photos, so a downloaded copy is still caught by placeholder-check.