ToolSink
Back to blog

How to Generate Custom Barcodes (And How Check Digits Actually Work)

ToolSink Team

How to Generate Custom Barcodes (And How Check Digits Actually Work)

Barcodes look simple — lines and spaces, or a grid of squares — but the format you pick and how you print it determines whether a scanner reads it in a fraction of a second or fails repeatedly at checkout. A quick history note: the concept dates to the late 1940s (Norman Joseph Woodland and Bernard Silver, originally a circular "bullseye" design), with the rectangular UPC format standardized for retail in the 1970s.

1D vs. 2D: not just a visual difference

1D (linear) barcodes encode data in the width and spacing of vertical lines, read by a single scan line (laser or camera line). Capacity and character set vary meaningfully by format — this is the part generic guides tend to blur together:

  • UPC-A / EAN-13 — numeric only, fixed length (12 or 13 digits including a check digit), used for retail products
  • Code 39 — alphanumeric (uppercase letters, digits, a few symbols), lower data density, common in automotive/defense/inventory
  • Code 128 — full ASCII character set, high density, the default choice for logistics and shipping labels where you need more than just digits

2D barcodes (QR codes, Data Matrix) encode data in a two-dimensional pattern, which is why they hold far more data in the same physical space and can be read from any angle. QR codes can store several kilobytes — enough for a URL, contact card, or Wi-Fi credentials, not just a short numeric ID.

Picking a format isn't just aesthetic: if you need to encode a serial number with letters in it, UPC/EAN literally can't do it (numeric only) — you'd need Code 128 or a 2D format instead.

How check digits catch scanning errors

Most numeric barcode formats include a check digit — a final digit mathematically derived from the others, used to catch a misread digit before bad data enters your system. UPC-A's check digit calculation:

def upc_check_digit(digits):
    # digits: the first 11 digits of a UPC-A code, as a string
    odd_sum = sum(int(d) for d in digits[0::2]) * 3   # positions 1,3,5... x3
    even_sum = sum(int(d) for d in digits[1::2])       # positions 2,4,6... x1
    total = odd_sum + even_sum
    check_digit = (10 - (total % 10)) % 10
    return check_digit

# Example: first 11 digits of a UPC-A code
print(upc_check_digit("03600029145"))  # → 2, completing the code as 036000291452

If a scanner misreads even one digit, the recalculated check digit won't match the printed one, and the scan is rejected rather than silently entering wrong data into a POS or inventory system. This is why a barcode with a smudged or misprinted digit sometimes fails to scan at all rather than scanning as the wrong product — the check digit is doing its job.

Printing details that actually determine whether it scans

  • Contrast: dark ink (black is safest) on a light, non-reflective background. Avoid red barcodes specifically — many laser scanners use a red light source and can't distinguish red ink from the background.
  • Quiet zone: the blank margin immediately around the barcode. Scanners use it to detect where the code starts and ends; text, borders, or graphics inside that margin can make an otherwise correct barcode unreadable.
  • Resolution: barcodes generated at low resolution or scaled up from a small image become blurry at print size, which is a common and avoidable cause of scan failures. Export at the print size you actually need rather than scaling after the fact.
  • Test before mass printing: scan a small test batch with the actual hardware (the specific scanner or phone app) that will be used in production before printing thousands of labels.

Common use cases

  • Inventory/asset tracking — unique IDs per item, batch, or location
  • Point of sale — faster, typo-free checkout versus manual entry
  • Event ticketing — unique per-ticket codes for entry tracking and counterfeit resistance
  • Shipping/logistics — Code 128 is the common choice here due to its higher data density

Generating one

If your workflow just needs a one-off barcode rather than integration into a larger system, a browser-based generator that lets you pick the format, enter your data, and export as PNG/SVG is the fastest route — just confirm the specific format matches what your scanner or downstream system expects, since UPC/EAN, Code 39, and Code 128 aren't interchangeable for the same input data.