JSON-LD format
The passport JSON-LD changed in ways that affect code that parses it:
@idis now the passport's GS1 Digital Link URI on the host that served the document.- The decentralised identifier is no longer emitted.
dpp:did,dpp:issuerDid, the document-leveldpp:verificationStatus,dpp:lastVerifiedanddpp:complianceStatusare removed. Usedpp:dateTimeOfLatestUpdatefor the last update. The per-certificatedpp:verificationStatusis still emitted. - The
espr:prefix is gone. Its terms are renamed underdpp::dpp:circularity(withdpp:recycledContentPercentage,dpp:reparabilityScoreanddpp:dismantlingInstructions),dpp:substancesOfConcern,dpp:economicOperators(withdpp:roleanddpp:eoriNumber),dpp:dppGranularityanddpp:productCategory. The values are unchanged, so read thedpp:keys where you read theespr:keys. gs1:serialNumberis nowgs1:hasSerialNumber, the GS1 Web Vocabulary property for AI 21.- Rated capacity (
dpp:ratedCapacity) has unit codeAMH(ampere hour), notAMP. skuis the model identifier from the product's form data, and is omitted when there is none. It could previously hold the product name.- The W3C credentials context is removed. The document is not a Verifiable Credential.
dpp:temperatureRangeappears when an idle temperature bound is a number (withminValue,maxValueandunitCodeCEL), or, if there is none, as the operator's storage temperature range text invaluewith nounitCode.- The
bpv1_3:prefix is now declared in@context, andDigitalProductPassportis defined in it.
Why JSON-LD?β
The /api/dpp/{slug}/jsonld endpoint returns DPP data as JSON-LD (JSON for Linked Data). The same document is served from a GS1 Digital Link URI (/01/{gtin}) when the request's Accept header prefers JSON; see DPP endpoints. This format provides several advantages over plain JSON:
- Semantic interoperability: Every term has a globally unique identifier: an IRI in schema.org, in the GS1 vocabulary, or in Traceable's own
dpp:andbpv1_3:namespaces.dpp:andbpv1_3:are Traceable-owned names that do not open as web pages today. Two systems using the same vocabulary will interpret fields identically without out-of-band coordination. - Graph database compatibility: JSON-LD maps directly to RDF triples and can be loaded into triple stores (Apache Jena, Amazon Neptune, GraphDB) for complex querying.
- schema.org tooling: Fields mapped to schema.org terms work with Google's Structured Data Testing Tool, Rich Results Test, and SEO enrichment tools.
- EU interoperability requirements: The EU's Ecodesign regulation and Digital Product Passport framework are moving towards semantic data exchange. JSON-LD positions integrations for future regulatory requirements.
The @contextβ
Traceable DPP JSON-LD responses use an ordered @context array: the standard schema.org context followed by an inline map of prefixes and a type definition.
{
"@context": [
"https://schema.org",
{
"dpp": "https://schema.traceable.digital/dpp/v1/",
"gs1": "https://gs1.org/voc/",
"bpv1_3": "https://schema.traceable.digital/batterypass/v1.3/",
"DigitalProductPassport": "dpp:DigitalProductPassport"
}
]
}
-
schema.org: loaded as the base context. Standard product and organisation terms (
name,image,description,sku,brand,manufacturer,gtin, β¦) are emitted as bare, unprefixed keys and resolve against schema.org. -
dpp:(https://schema.traceable.digital/dpp/v1/): Traceable's namespace for battery / DPP-specific terms with no schema.org equivalent. This includes circularity, economic operators, substances of concern, product category and granularity, which were under anespr:prefix before v0.99.19. -
gs1:(https://gs1.org/voc/): GS1 vocabulary for GTIN / identifier terms. -
bpv1_3:(https://schema.traceable.digital/batterypass/v1.3/): Traceable's mapping of the BatteryPass v1.3 public-mandatory attributes. It is declared in the@context, so a JSON-LD processor keeps these keys. Before v0.99.19 the prefix was not declared, and a strict processor dropped them. -
DigitalProductPassport: defined in the@contextasdpp:DigitalProductPassport.
@type valuesβ
DPP JSON-LD documents carry two @type values: Product, resolved against the schema.org base context, and DigitalProductPassport, defined in the @context as dpp:DigitalProductPassport:
{
"@type": ["Product", "DigitalProductPassport"]
}
Product enables compatibility with general product tooling; DigitalProductPassport identifies the document as a Digital Product Passport.
The @idβ
The @id field is the passport's GS1 Digital Link URI on the host that served the document:
- With a valid GTIN:
https://<host>/01/{gtin}, followed by/10/{batch}and/21/{serial}(in that order) when the request carried them. A customer resolver domain uses its own origin. - Without a valid GTIN:
https://<host>/dpp/{slug}.
The @id never has a query string. The document carries no decentralised identifier.
Full example: EV battery DPP in JSON-LDβ
The following is representative of the structure emitted by the platform JSON-LD mapper. Individual keys are only present when the underlying value exists; empty values are stripped.
{
"@context": [
"https://schema.org",
{
"dpp": "https://schema.traceable.digital/dpp/v1/",
"gs1": "https://gs1.org/voc/",
"bpv1_3": "https://schema.traceable.digital/batterypass/v1.3/",
"DigitalProductPassport": "dpp:DigitalProductPassport"
}
],
"@type": ["Product", "DigitalProductPassport"],
"@id": "https://dpp.traceable.digital/01/09506000134352/21/SN-2026-00421",
"name": "SwiftVolt 48V 100Ah EV Pack",
"image": ["https://app.traceable.digital/.../product.jpg"],
"description": "48V 100Ah EV traction battery pack",
"sku": "SV-48100-EV",
"brand": { "@type": "Brand", "name": "SwiftVolt" },
"manufacturer": {
"@type": "Organization",
"name": "SwiftVolt Energy Systems GmbH",
"address": "BatteriestraΓe 14, 80333 Munich, DE",
"globalLocationNumber": "4012345000009",
"url": "https://swiftvolt.de",
"contactPoint": {
"@type": "ContactPoint",
"email": "compliance@swiftvolt.de"
}
},
"gtin": "09506000134352",
"gs1:hasSerialNumber": "SN-2026-00421",
"dpp:batchId": "B-2026-014",
"dpp:productionDate": "2026-01-20",
"dpp:placeOfManufacture": "Munich, DE",
"dpp:dppId": "dpp_9f2cβ¦",
"dpp:version": 3,
"dpp:passportURNIssuer": "https://traceable.digital",
"dpp:passportVersion": "3.0",
"dpp:certificates": [
{
"@type": "dpp:Certificate",
"name": "IEC 62619:2022",
"dpp:documentType": "Test report",
"dpp:verificationStatus": "Verified",
"dpp:issuer": "TΓV Rheinland",
"dpp:validUntil": "2029-01-15"
}
],
"dpp:circularity": {
"dpp:recycledContentPercentage": 16,
"dpp:reparabilityScore": 7,
"dpp:dismantlingInstructions": "https://swiftvolt.de/dismantling",
"dpp:materialComposition": [
{ "material": "Lithium", "percentage": 6 }
]
},
"dpp:carbonFootprint": {
"dpp:totalKgCO2e": 4948,
"dpp:kgCO2ePerKwh": 61.4,
"dpp:methodology": "ISO 14067:2018",
"dpp:performanceClass": "B",
"dpp:verificationBody": "TΓV Rheinland"
},
"dpp:batteryPerformance": {
"dpp:nominalVoltage": { "@type": "QuantitativeValue", "value": 48, "unitCode": "VLT" },
"dpp:ratedCapacity": { "@type": "QuantitativeValue", "value": 100, "unitCode": "AMH" },
"dpp:cycleLife": 2000,
"dpp:roundTripEfficiency": { "@type": "QuantitativeValue", "value": 96.2, "unitCode": "P1" },
"dpp:energyCapacity": { "@type": "QuantitativeValue", "value": 4.8, "unitCode": "KWH" },
"dpp:temperatureRange": { "@type": "QuantitativeValue", "minValue": -20, "maxValue": 60, "unitCode": "CEL" }
},
"dpp:batteryInformation": {
"dpp:chemistry": "NMC",
"dpp:batteryCategory": "EV - Traction",
"dpp:batteryStatus": "Original",
"dpp:passportURN": "urn:traceable:bat:9f2cβ¦",
"weight": { "@type": "QuantitativeValue", "value": 320, "unitCode": "KGM" }
},
"dpp:technicalSpecifications": [
{ "@type": "PropertyValue", "name": "form factor", "value": "prismatic" }
],
"dpp:substancesOfConcern": [
{
"@type": "dpp:Substance",
"name": "Cobalt(II) oxide",
"dpp:casNumber": "1307-96-6",
"dpp:concentrationRange": "1β5%",
"dpp:locationInProduct": "Cathode"
}
],
"dpp:economicOperators": [
{
"@type": "Organization",
"name": "SwiftVolt Energy Systems GmbH",
"dpp:role": "Manufacturer",
"dpp:eoriNumber": "DE1234567890123",
"identifier": { "@type": "PropertyValue", "propertyID": "EORI", "value": "DE1234567890123" },
"contactPoint": { "@type": "ContactPoint", "email": "compliance@swiftvolt.example", "telephone": "+49 30 0000000" },
"url": "https://www.swiftvolt.example"
}
],
"dpp:metadata": {
"dpp:issuedAt": "2026-02-01T10:14:22.000Z",
"dpp:granularity": "item_level",
"dpp:dateTimeOfLatestUpdate": "2026-03-18T08:45:11.000Z"
},
"dpp:dppGranularity": "Item",
"dpp:dateTimeOfLatestUpdate": "2026-03-18T08:45:11.000Z",
"dpp:productCategory": "EV Battery",
"bpv1_3:publicMandatoryAttributes": [
{
"@type": "dpp:BpvAttribute",
"bpv1_3:attrNum": 5,
"bpv1_3:name": "Battery category",
"bpv1_3:category": "General product & manufacturer information",
"bpv1_3:source": "formData",
"value": "EV - Traction"
}
],
"bpv1_3:publicMandatoryAttributeCount": 1
}
unitCode values are UN/CEFACT common codes (VLT volt, AMH ampere hour, KWH kilowatt-hour, KGM kilogram, CEL degree Celsius, P1 percent).
Parsing JSON-LD in JavaScriptβ
Install the jsonld npm package:
npm install jsonld
Compact the document to simplify property names using your own context:
import jsonld from 'jsonld';
async function compactDppJsonLd(slug) {
const response = await fetch(
`https://dpp.traceable.digital/api/dpp/${slug}/jsonld`
);
const document = await response.json();
// Compact to a simpler local context
const compacted = await jsonld.compact(document, {
'@context': {
name: 'https://schema.org/name',
manufacturer: 'https://schema.org/manufacturer',
dpp: 'https://schema.traceable.digital/dpp/v1/',
carbonFootprint: 'https://schema.traceable.digital/dpp/v1/carbonFootprint',
productCategory: 'https://schema.traceable.digital/dpp/v1/productCategory',
}
});
return compacted;
}
Read a nested node directly. The carbon footprint lives under the dpp:carbonFootprint key, so you can navigate to it without framing:
async function extractCarbonFootprint(slug) {
const response = await fetch(
`https://dpp.traceable.digital/api/dpp/${slug}/jsonld`
);
const doc = await response.json();
const cf = doc['dpp:carbonFootprint'];
if (!cf) return null;
return {
total: cf['dpp:totalKgCO2e'],
perKwh: cf['dpp:kgCO2ePerKwh'],
verificationBody: cf['dpp:verificationBody'],
};
}
Parsing JSON-LD in Pythonβ
Install pyld:
pip install PyLD requests
import requests
from pyld import jsonld
def fetch_and_compact_dpp(slug: str) -> dict:
response = requests.get(
f"https://dpp.traceable.digital/api/dpp/{slug}/jsonld",
timeout=10
)
response.raise_for_status()
document = response.json()
context = {
"@context": {
"name": "https://schema.org/name",
"productCategory": "https://schema.traceable.digital/dpp/v1/productCategory",
"carbonFootprint": "https://schema.traceable.digital/dpp/v1/carbonFootprint",
}
}
compacted = jsonld.compact(document, context)
return compacted
def extract_manufacturer_name(slug: str) -> str | None:
response = requests.get(
f"https://dpp.traceable.digital/api/dpp/{slug}/jsonld",
timeout=10
)
response.raise_for_status()
document = response.json()
# The manufacturer is a bare schema.org term (no prefix)
manufacturer = document.get("manufacturer")
if isinstance(manufacturer, dict):
return manufacturer.get("name")
return None
Plain JSON extraction (without a JSON-LD library)β
For systems that do not need full JSON-LD processing, you can treat the response as plain JSON and navigate to known fields directly:
async function extractKeyFields(slug) {
const response = await fetch(
`https://dpp.traceable.digital/api/dpp/${slug}/jsonld`
);
const doc = await response.json();
// Navigate to known paths directly (no library needed).
// schema.org terms are bare keys; Traceable terms are prefixed.
return {
productName: doc['name'],
productCategory: doc['dpp:productCategory'],
manufacturerName: doc['manufacturer']?.['name'],
carbonFootprintTotal: doc['dpp:carbonFootprint']?.['dpp:totalKgCO2e'],
lastUpdated: doc['dpp:dateTimeOfLatestUpdate'],
};
}
This approach is simple but brittle: it breaks if the context is updated to use prefixes differently. Use a JSON-LD library for production integrations.
Embedding in HTML head for search enginesβ
Paste the JSON-LD response directly into a <script> tag in your HTML <head>:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>SwiftVolt 48V 100Ah EV Pack, Battery Passport</title>
<!-- Traceable DPP JSON-LD, structured data for search engines -->
<script type="application/ld+json">
{
"@context": [
"https://schema.org",
{
"dpp": "https://schema.traceable.digital/dpp/v1/",
"gs1": "https://gs1.org/voc/",
"bpv1_3": "https://schema.traceable.digital/batterypass/v1.3/",
"DigitalProductPassport": "dpp:DigitalProductPassport"
}
],
"@type": ["Product", "DigitalProductPassport"],
"name": "SwiftVolt 48V 100Ah EV Pack",
"manufacturer": {
"@type": "Organization",
"name": "SwiftVolt Energy Systems GmbH"
}
}
</script>
</head>
<body>
<!-- page content -->
</body>
</html>
The Traceable public DPP viewer at https://dpp.traceable.digital/dpp/{slug} automatically embeds the JSON-LD in its HTML <head>, so all published DPPs are already discoverable by search engines without any additional work.
Validating with Google's toolsβ
To validate your JSON-LD markup:
- Go to search.google.com/test/rich-results
- Enter the URL of your product page or paste the JSON-LD directly
- The tool will highlight any warnings or errors in the structured data
Note: Google primarily validates the bare schema.org terms (name, brand, manufacturer, image, β¦). The prefixed terms (dpp:, gs1:, bpv1_3:) will not be recognised by Google's tool but will not cause errors.
Vocabulary referenceβ
This page lists the terms the platform emits. It uses schema.org and GS1 terms where they apply, plus Traceable's own dpp: names for the rest.
The terms are grouped by prefix. schema.org terms are unprefixed. In the @context, dpp: stands for https://schema.traceable.digital/dpp/v1/, gs1: for https://gs1.org/voc/, and bpv1_3: for https://schema.traceable.digital/batterypass/v1.3/. The dpp: and bpv1_3: addresses are names, not web pages: they do not open in a browser today.
schema.org terms (unprefixed)β
| Term | Type | Description |
|---|---|---|
Product, DigitalProductPassport | @type | The two document types. |
name | Property | Product name. |
image | Property | Array of product image URLs. |
description | Property | Product description. |
sku | Property | Model identifier: the first of the form fields model_number, model_id, product_model_number and model that holds a value. Omitted when none does. |
brand | Property | { "@type": "Brand", "name": β¦ }. |
manufacturer | Property | Organization node with name, address, globalLocationNumber (GLN), url, and contactPoint. |
gtin | Property | GTIN of the product, when assigned. |
identifier | Property | PropertyValue node used for typed identifiers (e.g. EORI on economic operators). |
weight | Property | QuantitativeValue in kilograms (unitCode: "KGM"), under dpp:batteryInformation. |
dpp: terms (Traceable)β
| Term | Type | Description |
|---|---|---|
dpp:dppId | Property | Traceable DPP identifier. |
dpp:version | Property | Integer version counter. |
dpp:passportVersion | Property | Version string ("N.0"). |
dpp:passportURN / dpp:passportURNIssuer | Property | Battery passport URN and the URN issuer (https://traceable.digital). |
dpp:dateTimeOfLatestUpdate | Property | Date-time of the latest DPP update (BatteryPass v1.3 attr #4); also nested under dpp:metadata. |
dpp:batchId, dpp:productionDate, dpp:placeOfManufacture | Property | Production identification. |
dpp:certificates | Property | Array of dpp:Certificate nodes (name, dpp:documentType, dpp:verificationStatus, dpp:issuer, dpp:validUntil). |
dpp:carbonFootprint | Property | Object with dpp:totalKgCO2e, dpp:kgCO2ePerKwh, dpp:methodology, dpp:performanceClass, dpp:verificationBody. |
dpp:batteryPerformance | Property | Object with dpp:nominalVoltage, dpp:ratedCapacity, dpp:capacityFade, dpp:powerFade, dpp:cycleLife, dpp:roundTripEfficiency, dpp:energyCapacity, dpp:originalPowerCapability (unit code WTT, watt), dpp:energyDensity, dpp:internalResistanceCell, dpp:temperatureRange (values are schema.org QuantitativeValue nodes with unitCode). dpp:ratedCapacity has unit code AMH (ampere hour). dpp:temperatureRange appears when an idle temperature bound is a number (with minValue, maxValue and unitCode CEL), or, if there is none, as the operator's storage temperature range text in value with no unitCode. |
dpp:batteryInformation | Property | Object with dpp:chemistry, dpp:batteryCategory, dpp:batteryStatus, dpp:passportURN, weight. |
dpp:technicalSpecifications | Property | Array of schema.org PropertyValue nodes. |
dpp:materialComposition | Property | Array of material entries, nested under dpp:circularity. |
dpp:metadata | Property | Object with dpp:issuedAt, dpp:validUntil, dpp:granularity, dpp:dateTimeOfLatestUpdate. |
dpp:Certificate, dpp:Substance, dpp:BpvAttribute | Class | Node types used within the arrays above. |
Passport structure terms (dpp:)β
| Term | Type | Description |
|---|---|---|
dpp:productCategory | Property | Human-readable battery category literal (e.g. "EV Battery", "LMT Battery"). |
dpp:dppGranularity | Property | DPP granularity: "Item", "Batch", or "Model". |
dpp:circularity | Property | Object with dpp:recycledContentPercentage, dpp:reparabilityScore, dpp:dismantlingInstructions, and dpp:materialComposition. |
dpp:substancesOfConcern | Property | Array of dpp:Substance nodes (name, dpp:casNumber, dpp:concentrationRange, dpp:locationInProduct). |
dpp:economicOperators | Property | Array of Organization nodes with name, dpp:role and, where available, dpp:eoriNumber (with a matching identifier), address, contactPoint (email and telephone) and url. An item with no name is not listed. url is emitted only for a website that starts with http:// or https://. |
dpp:hazardousSubstancesNoneDeclared | Property | Boolean. true when the manufacturer declared that no hazardous substance (other than mercury, cadmium or lead) is present, false when the declaration is not made. Omitted unless the product holds a true or false value for the declaration. |
dpp:criticalRawMaterialsNonePresentDeclared | Property | Boolean. true when the manufacturer declared that no critical raw material is present, false when the declaration is not made. Omitted unless the product holds a true or false value for the declaration. It replaces the retired dpp:criticalRawMaterialsNoneDeclared; see the API changelog. |
Archived passport terms (dpp:)β
An archived passport carries a dpp:passportAvailability node. See Archived passports.
| Term | Type | Description |
|---|---|---|
dpp:passportAvailability | Property | A dpp:PassportAvailability node, present only on an archived passport. |
dpp:PassportAvailability | Class | The type of the node above. |
dpp:availabilityStatus | Property | Always archived. |
dpp:archiveReason | Property | One or more of withdrawn, end_of_production, company_inactive. |
dpp:notice | Property | The same text a visitor reads on the passport page. |
dpp:withdrawalReason | Property | The withdrawal reason, present when the product was withdrawn. |
dpp:withdrawnAt | Property | The withdrawal date-time (ISO 8601), present when the product was withdrawn. |
dpp:endOfProductionAt | Property | When the model went out of production (ISO 8601), present when it applies. |
Regulatory basis terms (dpp:)β
These describe the regulation and scope that the category configuration records for the passport's battery category.
| Term | Type | Description |
|---|---|---|
dpp:regulatoryBasis | Property | A dpp:RegulatoryBasis node holding the regulatory basis recorded for the passport's battery category. |
dpp:RegulatoryBasis | Class | The type of the node above. |
dpp:regulation | Property | The regulation named in the category configuration. |
dpp:status | Property | The scope status recorded for the category, for example OUT_OF_SCOPE or DELEGATED_ACT_PENDING. |
dpp:scopeArticle | Property | The article that the scope status rests on. |
dpp:categoryArticle | Property | The article recorded for the category. Omitted when the configuration holds none. |
dpp:scopeStatement | Property | Fixed wording, present only when dpp:status is OUT_OF_SCOPE or DELEGATED_ACT_PENDING. |
dpp:regulatorySource, dpp:RegulatorySource | Property, Class | The legal source behind the basis, with dpp:instrument, dpp:celex and dpp:url. |
dpp:instrument, dpp:celex, dpp:url | Property | The name of the legal instrument, its CELEX number, and a link to it. |
dpp:verifiedOn | Property | The date the regulatory basis entry was last verified. |
Industry specification terms (dpp:)β
| Term | Type | Description |
|---|---|---|
dpp:industrySpecAlignment | Property | A dpp:IndustrySpec node naming an industry specification that the category configuration refers to. It is kept separate from dpp:regulatoryBasis because an industry specification is not a regulation. |
dpp:IndustrySpec | Class | The type of the node above. |
dpp:specCode, dpp:name, dpp:publisher, dpp:publisherRef, dpp:url | Property | The specification's code and name, its publisher, a reference to the publisher's document, and a link. |
Component link terms (dpp:)β
These appear on the child links under schema.org hasPart.
| Term | Type | Description |
|---|---|---|
dpp:linkAttestation | Property | platform-verified when the child is a passport on this platform, or operator-asserted-external when the operator supplied an external https passport URL. |
dpp:externalDppId | Property | The identifier recorded for an external child passport, present when there is one. |
gs1: termsβ
| Term | Type | Description |
|---|---|---|
gs1:hasSerialNumber | Property | Serial number of the individual product (GS1 application identifier 21). |
bpv1_3: termsβ
| Term | Type | Description |
|---|---|---|
bpv1_3:publicMandatoryAttributes | Property | Array of dpp:BpvAttribute nodes carrying the BatteryPass v1.3 public-mandatory longlist, each with bpv1_3:attrNum, bpv1_3:name, bpv1_3:category, bpv1_3:source, and value. |
bpv1_3:publicMandatoryAttributeCount | Property | Count of entries in the array above. |