Skip to main content

JSON-LD format

Changed in v0.99.19 and v0.99.20

The passport JSON-LD changed in ways that affect code that parses it:

  • @id is 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-level dpp:verificationStatus, dpp:lastVerified and dpp:complianceStatus are removed. Use dpp:dateTimeOfLatestUpdate for the last update. The per-certificate dpp:verificationStatus is still emitted.
  • The espr: prefix is gone. Its terms are renamed under dpp:: dpp:circularity (with dpp:recycledContentPercentage, dpp:reparabilityScore and dpp:dismantlingInstructions), dpp:substancesOfConcern, dpp:economicOperators (with dpp:role and dpp:eoriNumber), dpp:dppGranularity and dpp:productCategory. The values are unchanged, so read the dpp: keys where you read the espr: keys.
  • gs1:serialNumber is now gs1:hasSerialNumber, the GS1 Web Vocabulary property for AI 21.
  • Rated capacity (dpp:ratedCapacity) has unit code AMH (ampere hour), not AMP.
  • sku is 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: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.
  • The bpv1_3: prefix is now declared in @context, and DigitalProductPassport is 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: and bpv1_3: namespaces. dpp: and bpv1_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 an espr: 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 @context as dpp: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:

  1. Go to search.google.com/test/rich-results
  2. Enter the URL of your product page or paste the JSON-LD directly
  3. 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)​

TermTypeDescription
Product, DigitalProductPassport@typeThe two document types.
namePropertyProduct name.
imagePropertyArray of product image URLs.
descriptionPropertyProduct description.
skuPropertyModel identifier: the first of the form fields model_number, model_id, product_model_number and model that holds a value. Omitted when none does.
brandProperty{ "@type": "Brand", "name": … }.
manufacturerPropertyOrganization node with name, address, globalLocationNumber (GLN), url, and contactPoint.
gtinPropertyGTIN of the product, when assigned.
identifierPropertyPropertyValue node used for typed identifiers (e.g. EORI on economic operators).
weightPropertyQuantitativeValue in kilograms (unitCode: "KGM"), under dpp:batteryInformation.

dpp: terms (Traceable)​

TermTypeDescription
dpp:dppIdPropertyTraceable DPP identifier.
dpp:versionPropertyInteger version counter.
dpp:passportVersionPropertyVersion string ("N.0").
dpp:passportURN / dpp:passportURNIssuerPropertyBattery passport URN and the URN issuer (https://traceable.digital).
dpp:dateTimeOfLatestUpdatePropertyDate-time of the latest DPP update (BatteryPass v1.3 attr #4); also nested under dpp:metadata.
dpp:batchId, dpp:productionDate, dpp:placeOfManufacturePropertyProduction identification.
dpp:certificatesPropertyArray of dpp:Certificate nodes (name, dpp:documentType, dpp:verificationStatus, dpp:issuer, dpp:validUntil).
dpp:carbonFootprintPropertyObject with dpp:totalKgCO2e, dpp:kgCO2ePerKwh, dpp:methodology, dpp:performanceClass, dpp:verificationBody.
dpp:batteryPerformancePropertyObject 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:batteryInformationPropertyObject with dpp:chemistry, dpp:batteryCategory, dpp:batteryStatus, dpp:passportURN, weight.
dpp:technicalSpecificationsPropertyArray of schema.org PropertyValue nodes.
dpp:materialCompositionPropertyArray of material entries, nested under dpp:circularity.
dpp:metadataPropertyObject with dpp:issuedAt, dpp:validUntil, dpp:granularity, dpp:dateTimeOfLatestUpdate.
dpp:Certificate, dpp:Substance, dpp:BpvAttributeClassNode types used within the arrays above.

Passport structure terms (dpp:)​

TermTypeDescription
dpp:productCategoryPropertyHuman-readable battery category literal (e.g. "EV Battery", "LMT Battery").
dpp:dppGranularityPropertyDPP granularity: "Item", "Batch", or "Model".
dpp:circularityPropertyObject with dpp:recycledContentPercentage, dpp:reparabilityScore, dpp:dismantlingInstructions, and dpp:materialComposition.
dpp:substancesOfConcernPropertyArray of dpp:Substance nodes (name, dpp:casNumber, dpp:concentrationRange, dpp:locationInProduct).
dpp:economicOperatorsPropertyArray 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:hazardousSubstancesNoneDeclaredPropertyBoolean. 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:criticalRawMaterialsNonePresentDeclaredPropertyBoolean. 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.

TermTypeDescription
dpp:passportAvailabilityPropertyA dpp:PassportAvailability node, present only on an archived passport.
dpp:PassportAvailabilityClassThe type of the node above.
dpp:availabilityStatusPropertyAlways archived.
dpp:archiveReasonPropertyOne or more of withdrawn, end_of_production, company_inactive.
dpp:noticePropertyThe same text a visitor reads on the passport page.
dpp:withdrawalReasonPropertyThe withdrawal reason, present when the product was withdrawn.
dpp:withdrawnAtPropertyThe withdrawal date-time (ISO 8601), present when the product was withdrawn.
dpp:endOfProductionAtPropertyWhen 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.

TermTypeDescription
dpp:regulatoryBasisPropertyA dpp:RegulatoryBasis node holding the regulatory basis recorded for the passport's battery category.
dpp:RegulatoryBasisClassThe type of the node above.
dpp:regulationPropertyThe regulation named in the category configuration.
dpp:statusPropertyThe scope status recorded for the category, for example OUT_OF_SCOPE or DELEGATED_ACT_PENDING.
dpp:scopeArticlePropertyThe article that the scope status rests on.
dpp:categoryArticlePropertyThe article recorded for the category. Omitted when the configuration holds none.
dpp:scopeStatementPropertyFixed wording, present only when dpp:status is OUT_OF_SCOPE or DELEGATED_ACT_PENDING.
dpp:regulatorySource, dpp:RegulatorySourceProperty, ClassThe legal source behind the basis, with dpp:instrument, dpp:celex and dpp:url.
dpp:instrument, dpp:celex, dpp:urlPropertyThe name of the legal instrument, its CELEX number, and a link to it.
dpp:verifiedOnPropertyThe date the regulatory basis entry was last verified.

Industry specification terms (dpp:)​

TermTypeDescription
dpp:industrySpecAlignmentPropertyA 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:IndustrySpecClassThe type of the node above.
dpp:specCode, dpp:name, dpp:publisher, dpp:publisherRef, dpp:urlPropertyThe specification's code and name, its publisher, a reference to the publisher's document, and a link.

These appear on the child links under schema.org hasPart.

TermTypeDescription
dpp:linkAttestationPropertyplatform-verified when the child is a passport on this platform, or operator-asserted-external when the operator supplied an external https passport URL.
dpp:externalDppIdPropertyThe identifier recorded for an external child passport, present when there is one.

gs1: terms​

TermTypeDescription
gs1:hasSerialNumberPropertySerial number of the individual product (GS1 application identifier 21).

bpv1_3: terms​

TermTypeDescription
bpv1_3:publicMandatoryAttributesPropertyArray 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:publicMandatoryAttributeCountPropertyCount of entries in the array above.
Was this page helpful?