{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreigt5jmoh4upje5gdxxqnwrqryttwai7mw6tughrypf7daibrmwbgq",
    "uri": "at://did:plc:25rdn5elo5izoxrmtis34zuk/app.bsky.feed.post/3mpuvnowfczj2"
  },
  "coverImage": {
    "$type": "blob",
    "ref": {
      "$link": "bafkreialg3qn4k3njo5wpfleqgn45irgxph55er3o56u3qmxgggqko6dei"
    },
    "mimeType": "image/webp",
    "size": 72306
  },
  "path": "/rosariov25/how-to-validate-a-gtin-ean-13-barcode-check-digit-gs1-mod-10-explained-5boh",
  "publishedAt": "2026-07-05T05:06:06.000Z",
  "site": "https://dev.to",
  "tags": [
    "barcode",
    "api",
    "webdev",
    "ecommerce",
    "GTIN / UPC / EAN check-digit calculator",
    "JSON API"
  ],
  "textContent": "If you have ever uploaded a product feed to Amazon, Google Merchant Center or Shopify and been rejected with \"invalid GTIN,\" the culprit is almost always the **check digit** — the last digit of the barcode. It is not random: it is calculated from all the other digits, and if it does not match, the platform rejects the code.\n\nHere is exactly how the check digit works, with a worked example you can follow by hand.\n\n##  What is a GTIN check digit?\n\nGTIN (Global Trade Item Number) is the umbrella term for the barcodes on products: **GTIN-8, UPC-A (12 digits), EAN-13 (13 digits) and GTIN-14**. The final digit of every one of them is a **check digit** computed with the **GS1 Mod-10** algorithm. Its job is to catch typos: change one digit and the check digit almost always stops matching.\n\n##  The GS1 Mod-10 algorithm, step by step\n\nTake all the digits **except** the last (the check digit), then:\n\n  1. Starting from the **rightmost** of those digits, multiply every second digit by **3** and the rest by **1**.\n  2. Add up all the results.\n  3. Find what you must add to reach the next multiple of 10. That number (0-9) is the check digit.\n\n\n\nFormally: `check = (10 − (sum mod 10)) mod 10`.\n\n##  A worked example — EAN-13 `400638133393?`\n\nThe first 12 digits are `4 0 0 6 3 8 1 3 3 3 9 3`. Working **right to left** , alternate the weights ×3 and ×1:\n\n\n    digit:   4  0  0  6  3  8  1  3  3  3  9  3\n    weight:  1  3  1  3  1  3  1  3  1  3  1  3\n    product: 4  0  0 18  3 24  1  9  3  9  9  9\n\n\nSum = 4+0+0+18+3+24+1+9+3+9+9+9 = **89**.\n89 mod 10 = 9, so check = (10 − 9) mod 10 = **1**.\n\nThe full valid barcode is therefore **4006381333931**. If a feed lists `4006381333930`, it is wrong — and that is exactly the kind of error that gets a listing rejected.\n\n##  In code (Python)\n\n\n    def gtin_check_digit(body: str) -> int:\n        total = 0\n        for i, ch in enumerate(reversed(body)):\n            total += int(ch) * (3 if i % 2 == 0 else 1)\n        return (10 - total % 10) % 10\n\n    print(gtin_check_digit(\"400638133393\"))  # -> 1\n\n\nThe same algorithm works for UPC-A (12), EAN-13 (13), GTIN-8 and GTIN-14 — only the length changes.\n\n##  Two things that trip people up\n\n  * **Excel eats leading zeros.** A UPC like `036000291452` becomes `36000291452` the moment Excel treats the cell as a number, which changes the length and breaks validation. Format the column as **Text** before pasting.\n  * **Wrong length.** UPC-A is 12 digits, EAN-13 is 13. Padding a UPC with a leading zero turns it into a valid EAN-13 — that is normal, not an error.\n\n\n\n##  The fast way (no math)\n\nIf you just need to check or generate a check digit right now, paste the code into a free GTIN / UPC / EAN check-digit calculator — it validates GTIN-8 / UPC-A / EAN-13 / GTIN-14 in the browser and tells you the correct digit when it is wrong.\n\nFor **bulk** work — validating a whole product feed, or wiring this into your own app — there is a deterministic JSON API that checks up to 100 codes per call (and also handles IBAN, EU VAT, VIN, ISIN and more). Same input, same output, every time — no AI guessing.",
  "title": "How to Validate a GTIN / EAN-13 Barcode Check Digit (GS1 Mod-10, explained)"
}