Encode and decode GS1 EPC identifiers for RAIN (UHF) RFID tags. Convert between GTIN, SSCC, SGLN, and 50+ other formats — from barcode to EPC hex and back.
Implements the GS1 EPC Tag Data Standard (TDS) 2.3 and Tag Data Translation (TDT) 2.2 specifications. Used in production for RFID tag programming, inventory systems, and supply chain applications.
Try it online: https://www.mimasu.nl/tag-data-translation/try-online
- Spec-complete: All 50 EPC schemes including TDS 2.3 '+' and '++' variants with Digital Link URIs
- Deterministic: Every encode/decode is provably correct against the GS1 specification — no approximations, no guessing
- Fast: SGTIN-96 encode in 7.8 us, decode in 7.7 us (benchmarked on Apple M1 Pro)
- Cross-platform: .NET, JavaScript/TypeScript (WASM), Python, Swift, Kotlin, Flutter
- Production-ready: Exception-free
TryTranslateAPI for high-throughput tag programming and reading
- GTIN to EPC encoding (SGTIN-96, SGTIN-198) and decoding
- SSCC, SGLN, GRAI, GIAI, GSRN, GDTI, SGCN, ITIP, GID, CPI, ADI, USDOD encoding
- GS1 Digital Link URI generation and parsing
- '++' schemes with custom hostname encoding for branded Digital Link URIs
- GS1 Company Prefix lookup
- Filter Value tables
- Hex to binary and binary to hex conversion
| Platform | Package | Status |
|---|---|---|
| .NET 8/9/10 | NuGet | Available |
| .NET MAUI (Android) | NuGet | Available (3.0.0+) |
| .NET MAUI (iOS) | NuGet | Available (3.0.0+) |
| .NET MAUI (macCatalyst) | NuGet | Available (3.0.0+) |
| JavaScript/TypeScript | npm | Available (3.0.0+) |
| Python | PyPI | Available (3.0.0+) |
| iOS (Swift) | Swift Package Manager | Available (3.0.0+) |
| Android (Kotlin/Java) | GitHub Packages | Available (3.0.0+) |
| Flutter (Dart) | pub.dev | Available (3.0.0+) |
| Scheme | Formats |
|---|---|
| SGTIN | SGTIN-96, SGTIN-198, SGTIN+, SGTIN++ |
| SSCC | SSCC-96, SSCC+, SSCC++ |
| SGLN | SGLN-96, SGLN-195, SGLN+, SGLN++ |
| GRAI | GRAI-96, GRAI-170, GRAI+, GRAI++ |
| GIAI | GIAI-96, GIAI-202, GIAI+, GIAI++ |
| GSRN | GSRN-96, GSRN+, GSRN++ |
| GSRNP | GSRNP-96, GSRNP+, GSRNP++ |
| GDTI | GDTI-96, GDTI-113, GDTI-174, GDTI+, GDTI++ |
| SGCN | SGCN-96, SGCN+, SGCN++ |
| ITIP | ITIP-110, ITIP-212, ITIP+, ITIP++ |
| GID | GID-96 |
| CPI | CPI-96, CPI-var, CPI+, CPI++ |
| ADI | ADI-var |
| USDOD | USDOD-96 |
| DSGTIN | DSGTIN+, DSGTIN++ |
'++' schemes (TDS 2.3) support lossless encoding of custom hostnames in EPC binary, enabling round-trip translation with branded Digital Link URIs like https://coca-cola.com/01/... instead of https://id.gs1.org/01/....
dotnet add package TagDataTranslationOr via Package Manager:
Install-Package TagDataTranslation
The NuGet package includes targets for .NET 8.0/9.0/10.0, Android, iOS, and macCatalyst. .NET MAUI projects will automatically resolve the correct platform target.
git clone https://github.com/dannyhaak/TagDataTranslation.git
cd TagDataTranslation
dotnet build src/TagDataTranslation/TagDataTranslation.csproj- .NET 8.0 or later (supports .NET 8.0, 9.0, and 10.0)
- For mobile targets: .NET MAUI workload (
dotnet workload install maui)
using TagDataTranslation;
var engine = new TDTEngine();
string epcIdentifier = "gtin=00037000302414;serial=10419703";
string parameterList = "filter=3;gs1companyprefixlength=7;tagLength=96";
string binary = engine.Translate(epcIdentifier, parameterList, "BINARY");
string hex = engine.BinaryToHex(binary);
// hex = "30340242201d8840009efdf7"var engine = new TDTEngine();
string binary = engine.HexToBinary("30340242201d8840009efdf7");
string legacy = engine.Translate(binary, "", "LEGACY");
// legacy = "gtin=00037000302414;serial=10419703"var engine = new TDTEngine();
var result = engine.TranslateDetails("30340242201d8840009efdf7", "", "TAG_ENCODING");
Console.WriteLine($"Pure Identity: {result.Fields["pureIdentityURI"]}");
Console.WriteLine($"Tag URI: {result.Fields["tagURI"]}");
Console.WriteLine($"GTIN: {result.Fields["gtin"]}");
Console.WriteLine($"Serial: {result.Fields["serial"]}");using TagDataTranslation.DigitalLink;
var components = new DigitalLinkComponents
{
Domain = "id.gs1.org",
PrimaryKey = ("01", "00037000302414"), // AI 01 = GTIN
KeyQualifiers = new List<(string, string)>
{
("21", "10419703") // AI 21 = Serial
}
};
string digitalLink = DigitalLinkGenerator.Generate(components);
// https://id.gs1.org/01/00037000302414/21/10419703if (DigitalLinkParser.TryParse("https://id.gs1.org/01/00037000302414/21/10419703", out var components))
{
Console.WriteLine($"GTIN: {components.PrimaryKey.Value}");
// GTIN: 00037000302414
}var engine = new TDTEngine();
var result = engine.GetPrefixLength("0037000302414");
Console.WriteLine($"Prefix: {result.Prefix}, Length: {result.Length}");
// Prefix: 0037000, Length: 7var engine = new TDTEngine();
if (engine.LoadErrors.Count > 0)
{
foreach (var error in engine.LoadErrors)
{
Console.WriteLine(error);
}
}public string Translate(string epcIdentifier, string parameterList, string outputFormat)Translates an EPC identifier from one representation to another.
| Parameter | Description |
|---|---|
epcIdentifier |
The EPC to convert (binary string, hex, URI, or legacy format) |
parameterList |
Semicolon-delimited key=value pairs (see Parameter Keys below) |
outputFormat |
Target format (see Output Formats below) |
Returns: The converted EPC as a string.
Pass as semicolon-delimited key=value pairs, e.g. "filter=3;gs1companyprefixlength=7;tagLength=96".
| Key | Required | Description |
|---|---|---|
filter |
Encode only | Filter value (0-7). Determines packaging level (POS item, case, pallet, etc.) |
gs1companyprefixlength |
Encode only | Length of the GS1 Company Prefix (6-12). Determines the partition table entry |
tagLength |
Encode only | Target tag length in bits (e.g., 96, 198). Selects the scheme variant |
hostname |
'++' encode only | Custom hostname for branded Digital Link URIs (e.g., coca-cola.com) |
When decoding (hex/binary input), no parameters are needed — the engine determines everything from the binary data.
| Format | Description | Example |
|---|---|---|
BINARY |
Binary bit string | 001100000011010000... |
TAG_ENCODING |
Tag URI with filter | urn:epc:tag:sgtin-96:3.0037000.030241.10419703 |
PURE_IDENTITY |
Pure Identity URI (no filter) | urn:epc:id:sgtin:0037000.030241.10419703 |
LEGACY |
Legacy key=value format | gtin=00037000302414;serial=10419703 |
LEGACY_AI |
Element string with AIs | (01)00037000302414(21)10419703 |
GS1_DIGITAL_LINK |
GS1 Digital Link URI | https://id.gs1.org/01/00037000302414/21/10419703 |
public TranslateResult TranslateDetails(string epcIdentifier, string parameterList, string outputFormat)Same as Translate, but returns a TranslateResult object containing all extracted fields.
public bool TryTranslate(string epcIdentifier, string parameterList, string outputFormat, out string? result, out string? errorCode)Translates an EPC identifier without throwing exceptions. Ideal for high-throughput scenarios.
if (engine.TryTranslate(epcIdentifier, parameterList, "BINARY", out var result, out var errorCode))
{
Console.WriteLine($"Success: {result}");
}
else
{
Console.WriteLine($"Failed: {errorCode}");
}public bool TryTranslateDetails(string epcIdentifier, string parameterList, string outputFormat, out TranslateResult? result, out string? errorCode)Same as TryTranslate, but returns a TranslateResult object on success.
public PrefixLengthResult GetPrefixLength(string input)Looks up the GS1 Company Prefix length for a given identifier.
public Dictionary<int, string> GetFilterValueTable(string scheme)Returns the filter value descriptions for a scheme (e.g., "SGTIN" returns {0: "All Others", 1: "POS Item", ...}).
public IReadOnlyList<string> LoadErrors { get; }Contains any errors encountered while loading scheme files. Inspect this after construction to debug missing or malformed schemes.
public string HexToBinary(string hex) // Convert hex to binary string
public string BinaryToHex(string binary) // Convert binary string to hexTDTTranslationException is thrown with one of these codes:
| Code | Description |
|---|---|
TDTFileNotFound |
Scheme definition file not found |
TDTFieldBelowMinimum |
Numeric field below minimum value |
TDTFieldAboveMaximum |
Numeric field above maximum value |
TDTFieldOutsideCharacterSet |
Field contains invalid characters |
TDTUndefinedField |
Required field is missing |
TDTSchemeNotFound |
No matching scheme found |
TDTLevelNotFound |
No matching level found |
TDTOptionNotFound |
No matching option found |
TDTLookupFailed |
External table lookup failed |
TDTNumericOverflow |
Numeric overflow occurred |
Benchmarked on Apple M1 Pro, .NET 8.0 (BenchmarkDotNet):
| Operation | Mean | Allocated |
|---|---|---|
| SGTIN-96 encode (GTIN → binary) | 7.8 us | 9.9 KB |
| SGTIN-96 decode (binary → GTIN) | 7.7 us | 9.2 KB |
| SGTIN++ encode (with hostname) | 24.3 us | 75.3 KB |
| SGTIN++ decode (with hostname) | 5.0 us | 7.8 KB |
| HexToBinary (96-bit) | 99 ns | 480 B |
| BinaryToHex (96-bit) | 54 ns | 192 B |
The engine uses compiled regex caching, pre-sorted scheme data, and lookup tables for hex/binary conversion. The TDTEngine constructor loads all schemes once; subsequent Translate() calls benefit from cached patterns and pre-computed data structures.
Run benchmarks yourself:
dotnet run -c Release --project test/TagDataTranslation.BenchmarksSee the examples/ directory for platform-specific sample projects:
examples/ConsoleApp/-- .NET console applicationexamples/MauiApp/-- .NET MAUI cross-platform app (Android, iOS, macCatalyst)examples/NodeApp/-- Node.js application (via WebAssembly)
dotnet build src/TagDataTranslation/TagDataTranslation.csproj
dotnet test test/TagDataTranslation.Tests/TagDataTranslation.Tests.csprojdotnet pack src/TagDataTranslation/TagDataTranslation.csproj -c Release -o ./artifactsTo publish to NuGet.org:
dotnet nuget push ./artifacts/TagDataTranslation.*.nupkg --api-key YOUR_API_KEY --source https://api.nuget.org/v3/index.json| Version | Changes |
|---|---|
| 3.0.0 | Cross-platform SDKs: npm (WASM), Python (pythonnet), Swift (NativeAOT), Android (NativeAOT), Flutter (dart:ffi), .NET MAUI (Android, iOS, macCatalyst); performance optimizations (regex caching, lookup tables, pre-sorted fields); BSL 1.1 licensing |
| 2.3.0 | TDS 2.3 support with 12 new '++' schemes for custom hostname encoding in Digital Link URIs |
| 2.1.0 | Added TryTranslate/TryTranslateDetails for exception-free high-throughput translation |
| 2.0.1 | Multi-targeting support for .NET 8.0, 9.0, and 10.0 |
| 2.0.0 | TDT 2.2 with JSON schemes, Digital Link support, new schemes (DSGTIN+, GDTI-113, etc.) |
| 1.1.5 | Updated GCP prefix file, ITIP encoding fixes |
| 1.0.0 | Initial release with TDT 1.6/1.11 support |
This library is licensed under the Business Source License 1.1 (BSL 1.1).
- Non-production use (development, testing, evaluation) is free
- Production use requires a commercial license -- contact tdt@mimasu.nl
- Each version converts to Apache 2.0 four years after release
See LICENSING.md for full details.
The included JSON and XSD artifacts are (c) GS1 (https://www.gs1.org/standards/epc-rfid/tdt).
- Tag programming: Encode GTINs and SSCCs to EPC hex for writing to RAIN RFID tags
- Tag reading: Decode EPC hex from RFID readers back to human-readable identifiers
- Inventory systems: Translate between barcode and RFID representations
- Supply chain: Convert between GS1 Digital Link URIs and EPC binary
- Label printing: Generate EPC hex for RFID-enabled label printers (Zebra, SATO, etc.)
- Mobile RFID apps: Encode/decode on iOS and Android via native SDKs