# Shopify barcode to gtin

The Shopify variant barcode field is where a GTIN lives, but Shopify neither requires nor validates it, so the mapping has to be conditional: use the barcode when it is a structurally valid GTIN, fall back to brand with mpn when it is not, and declare identifier_exists only for products that have none.

- **Canonical URL:** https://www.feedlab.io/knowledge/mappings/shopify-barcode-to-gtin
- **Last reviewed:** 18 September 2026
- **Source:** feedlab knowledge base
- **Licence:** free to quote and cite with attribution to feedlab


## The Shopify side

| Property | Value |
| --- | --- |
| API field | `variant.barcode` |
| Called | Barcode (ISBN, UPC, GTIN, etc.) |
| Found at | Product → Variants → edit variant → Inventory → Barcode |
| Feeds | `gtin`, `mpn`, `identifier_exists` |


## Before and after

| In Shopify | In the feed | Note |
| --- | --- | --- |
| `05012345678900` | `05012345678900` | Valid 14-digit GTIN, passed through unchanged with its leading zero intact. |
| ` 012345678905 ` | `012345678905` | Whitespace from a spreadsheet import, trimmed. Still a valid UPC-A. |
| `978-1-23456-789-7` | `9781234567897` | Hyphenated ISBN-13, punctuation stripped to leave a valid GTIN. |
| `WAREHOUSE-A-14` | `(omitted)` | Not an identifier. Routed to the brand and mpn fallback rather than submitted. |
| `5012345678900` | `(omitted)` | Thirteen digits but the check digit fails, so it is a typo rather than a GTIN. |
| `(empty)` | `(omitted)` | Nothing to send. identifier_exists is set to no only if the product genuinely has no GTIN. |



## The transformation, step by step

1. **Read the barcode from the variant, not the product** — Each Shopify variant has its own barcode, because each size and colour has its own GTIN in reality. A feed built at product level has nowhere to read a per-variant barcode from and ends up repeating one value or sending none.
2. **Trim whitespace and strip formatting characters** — Barcodes arrive with leading spaces from spreadsheet imports and with hyphens from anyone who typed them from packaging. Remove spaces, hyphens and any other punctuation before validating, because a structurally valid GTIN with a hyphen in it is rejected as invalid rather than cleaned up.
3. **Validate the length** — A GTIN is 8, 12, 13 or 14 digits. Anything else is not a GTIN, whatever it is. This single check catches internal references, shelf locations and supplier codes, which is what the field most often actually contains.
4. **Validate the check digit** — The final digit is derived from the others, so a transposed pair produces a value of the right length that is still invalid. Calculating the check digit is the difference between a feed that looks clean and one that is clean.
5. **Route the failures rather than sending them** — When the barcode is absent or invalid, send brand with mpn instead, and set identifier_exists to no only where the product genuinely has no manufacturer identifier. Submitting a bad value is worse than submitting nothing, because an invalid identifier is an error while an absent one is a warning.



## What goes wrong

### The field is a general-purpose box in practice

Shopify labels it "Barcode (ISBN, UPC, GTIN, etc.)" and validates none of it, so merchants use it for supplier codes, internal references and shelf locations. Mapping it straight to gtin ships whatever is in there, and the channel reports invalid identifiers rather than the data-quality problem you actually have.

### Leading zeros disappear through spreadsheets

A twelve-digit UPC starting with zero becomes an eleven-digit number the moment the file passes through Excel or Sheets. Any catalogue built from supplier spreadsheets has some of these, and they cannot be recovered from the feed: the fix is at the import, or from the supplier list again.

### A valid length is not a valid GTIN

Skipping the check digit means accepting every transposed pair of digits in the catalogue. Those values match nothing, so the item loses the benefit of having an identifier while still claiming one.

### Blanket identifier_exists hides the real gap

Setting identifier_exists to no across the catalogue silences the warnings and removes every product from identifier-based matching. It is the right declaration only for goods that genuinely have no manufacturer barcode.




## How feedlab maps it

feedlab treats identifiers as a conditional chain rather than a single mapping: trim and strip the variant barcode, accept it as gtin when the length and check digit are valid, fall back to brand with mpn when they are not, and set identifier_exists only for products flagged as having no identifier. The rule preview shows how many products land in each branch against the real catalogue before anything is published.






## Frequently asked questions

### Where is the GTIN stored in Shopify?

In the barcode field on each variant, under Inventory in the variant editor. It is per variant rather than per product, because each size and colour has its own barcode.

### Why is my Shopify barcode rejected as an invalid GTIN?

Either it is not the right length, or its check digit does not match. Both happen because Shopify does not validate the field, so internal references and typos sit in it alongside genuine barcodes.

### What should I send when the barcode is empty?

Brand with mpn, which channels accept in place of a GTIN. Set identifier_exists to no only for products that genuinely have no manufacturer identifier, such as handmade goods.

### Can I map the SKU to gtin instead?

No. A SKU is your own reference and will not be a valid GTIN, so it fails validation and matches nothing. If you need a fallback, the SKU can serve as an mpn when you are the manufacturer.




## Primary sources

- [Google: gtin attribute specification](https://support.google.com/merchants/answer/6324461)
- [Shopify: ProductVariant API reference](https://shopify.dev/docs/api/admin-graphql/latest/objects/ProductVariant)



