After 18 years working with EDI and supply chain systems, I've lost count of how many times I've had to validate an SSCC, Serial Shipping Container Code. Every time, it was either a one-off script, a colleague with a spreadsheet, or a paid tool hidden behind a login wall.
So I built SSCC Pro Vision, a free, open-source validator that runs entirely in the browser. No backend, no login, no cost. And while I was at it, I wrote up everything I know about SSCCs.
What is an SSCC?
The Serial Shipping Container Code is an 18-digit GS1 identifier used to uniquely identify a logistic unit, a pallet, box, roll cage, anything you ship. It's encoded in a GS1-128 barcode and transmitted in EDI messages like DESADV (Despatch Advice) and IFTMIN (Forwarding Instruction).
(00) E XXXXXXXXXXXXXXXXX C
│ │ │ └─ Check digit
│ │ └─── GCP + Serial reference
│ └─────────────────── GS1 Company Prefix
└───────────────────── Extension digit
The (00) is the Application Identifier, it tells any GS1-compliant system that what follows is an SSCC. It's not part of the 18 digits.
The check digit algorithm
SSCCs use the standard GS1 Modulo-10 algorithm. Given a 17-digit body:
- Starting from the rightmost digit, multiply alternating digits by 3 and 1
- Sum all products
- Check digit =
(10 − (sum mod 10)) mod 10
Worked example
Body: 35601234560000001
| Position (from right) | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Digit | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 6 | 5 | 3 |
| Multiplier | 3 | 1 | 3 | 1 | 3 | 1 | 3 | 1 | 3 | 1 | 3 | 1 | 3 | 1 | 3 | 1 | 3 |
| Product | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 6 | 15 | 4 | 9 | 2 | 3 | 0 | 18 | 5 | 9 |
Sum = 74 → Check digit = (10 − (74 mod 10)) mod 10 = (10 − 4) mod 10 = 6
Full SSCC: (00) 356012345600000016 🇵🇹
JavaScript implementation
Here's a clean, dependency-free implementation using BigInt to safely handle large numbers:
/**
* Calculate the GS1 check digit for a 17-digit SSCC body.
*/
function getCheckDigit(body17) {
let sum = 0;
const digits = body17.split('').reverse();
for (let i = 0; i < digits.length; i++) {
sum += parseInt(digits[i]) * (i % 2 === 0 ? 3 : 1);
}
return (10 - (sum % 10)) % 10;
}
/**
* Validate an 18-digit SSCC.
*/
function validateSSCC(sscc18) {
const digits = sscc18.replace(/\D/g, '');
if (digits.length !== 18) throw new Error('SSCC must be 18 digits');
const body = digits.substring(0, 17);
const provided = parseInt(digits[17]);
const expected = getCheckDigit(body);
return { valid: provided === expected, provided, expected };
}
/**
* Normalise any SSCC input, handles 17, 18 and 20-digit formats.
*/
function normaliseSSCC(raw) {
const d = raw.replace(/\D/g, '');
if (d.length === 17) return d + getCheckDigit(d); // generate CD
if (d.length === 18) return d; // full SSCC
if (d.length === 20 && d.startsWith('00')) return d.substring(2); // strip AI
throw new Error(`Unexpected length: ${d.length}`);
}
// Examples
console.log(validateSSCC('356012345600000016'));
// { valid: true, provided: 6, expected: 6 }
console.log(validateSSCC('356012345600000019'));
// { valid: false, provided: 9, expected: 6 }
console.log(normaliseSSCC('00356012345600000016'));
// '356012345600000016'
Common mistakes
1. Confusing the AI with the SSCC digits
When a GS1-128 barcode is scanned, the raw output is typically 00 followed by the 18 digits, 20 characters total. Always strip the leading 00 before validating.
// Wrong
validateSSCC('00356012345600000016'); // 20 digits, will fail
// Correct
validateSSCC(normaliseSSCC('00356012345600000016')); // strips AI first
2. Fixed-width ERP files
Some systems store SSCCs in fixed-width fields where the SSCC is immediately followed by other data, a line number, quantity, etc. The regex \b(00\d{18})\b won't work here because there's no word boundary after the SSCC.
Use a lookbehind instead:
const re = /(?<!\d)(00\d{18})/g;
This captures exactly 20 characters (00 + 18-digit SSCC) regardless of what follows.
Extracting SSCCs from EDIFACT
In EDIFACT messages, SSCCs appear mainly in the GIN segment with qualifier BJ:
GIN+BJ:356012345600000016'
Here's a simple parser that handles custom UNA delimiters:
function extractSSCCsFromEDIFACT(text) {
const results = [];
// Read custom delimiters from UNA service string
let compSep = ':', elemSep = '+', segTerm = "'";
const una = text.match(/^UNA(.{6})/);
if (una) {
compSep = una[1][0];
elemSep = una[1][1];
segTerm = una[1][5];
}
const segments = text
.replace(/\r?\n/g, '')
.split(segTerm)
.map(s => s.trim())
.filter(Boolean);
for (const seg of segments) {
const elements = seg.split(elemSep);
if (elements[0] !== 'GIN') continue;
for (const el of elements.slice(1)) {
const [qualifier, value] = el.split(compSep);
if (qualifier === 'BJ' && value) {
const result = validateSSCC(value);
results.push({ sscc: value, ...result });
}
}
}
return results;
}
Always read the UNA header before parsing. EDIFACT allows custom separators and defaulting to
: + 'will silently fail on non-standard files.
Other segments to check:
-
RFF+SI:<SSCC>, Reference, Shipment ID -
RFF+AAK:<SSCC>, Reference, Despatch number -
PAC, Package level (less common)
Free tool & API
If you don't want to write code, I built SSCC Pro Vision, it does all of this in the browser:
- 📷 Scan GS1-128 barcodes via camera
- ✅ Validate or generate check digits (single or batch)
- 🔁 Expand SSCC ranges
- 📂 Upload EDIFACT, IDoc SAP, XML, CSV or TXT files, SSCCs extracted automatically
- 📱 Installable as a PWA on Android and iOS
There's also a free REST API at https://sscc.birth1mark.workers.dev:
# Validate
curl "https://sscc.birth1mark.workers.dev/validate?sscc=356012345600000016"
# Generate check digit
curl "https://sscc.birth1mark.workers.dev/generate?body=35601234560000001"
# Extract from EDIFACT file
curl -X POST "https://sscc.birth1mark.workers.dev/extract" \
-H "Content-Type: text/plain" \
--data-binary @desadv.edi
No auth, no rate limit headaches (500 req/hour free), no data stored. Full docs at sscc-api-guide.html.
Wrapping up
SSCCs are simple in theory but surprisingly easy to get wrong in practice, especially when you're dealing with scanned barcodes, EDIFACT files from different trading partners, or ERP exports with non-standard field widths.
The GS1 spec is the authoritative source, but hopefully this covers the practical cases you'll actually encounter.
If you work in EDI or supply chain and have questions, drop them in the comments. Happy to help. 🇵🇹
Source code: github.com/birth1mark/sscc-check
API source: github.com/birth1mark/sscc-api
Top comments (0)