Skip to main content

Parse JSON-LD output

The /api/dpp/{slug}/jsonld endpoint returns DPP data in JSON-LD format. This page shows practical patterns for consuming that response — from full semantic processing with a JSON-LD library to simple field extraction.

JavaScript with the jsonld package

Install the dependency:

npm install jsonld
# TypeScript types
npm install --save-dev @types/jsonld

Compacting and framing

import jsonld from 'jsonld';

// Fetch the JSON-LD document
async function fetchDppJsonLd(slug: string): Promise<object> {
const response = await fetch(
`https://app.traceable.digital/api/dpp/${encodeURIComponent(slug)}/jsonld`
);

if (!response.ok) {
throw new Error(`Failed to fetch JSON-LD: HTTP ${response.status}`);
}

return response.json();
}

// Compact to a local context for easier field access
async function compactDppJsonLd(slug: string): Promise<Record<string, unknown>> {
const document = await fetchDppJsonLd(slug);

const localContext = {
'@context': {
name: 'https://schema.org/name',
manufacturer: 'https://schema.org/manufacturer',
orgName: 'https://schema.org/name',
addressCountry: 'https://schema.org/addressCountry',
datePublished: 'https://schema.org/datePublished',
dateModified: 'https://schema.org/dateModified',
batteryCategory: 'https://vocab.traceable.digital/v1#batteryCategory',
carbonFootprint: 'https://vocab.traceable.digital/v1#carbonFootprint',
totalKgCO2ePerKwh: 'https://vocab.traceable.digital/v1#totalKgCO2ePerKwh',
recycledContent: 'https://vocab.traceable.digital/v1#recycledContent',
cobaltPercent: 'https://vocab.traceable.digital/v1#cobaltPercent',
lithiumPercent: 'https://vocab.traceable.digital/v1#lithiumPercent',
performance: 'https://vocab.traceable.digital/v1#performance',
nominalCapacityKwh: 'https://vocab.traceable.digital/v1#nominalCapacityKwh',
certifications: 'https://vocab.traceable.digital/v1#certifications',
}
};

return jsonld.compact(document, localContext) as Promise<Record<string, unknown>>;
}

// Extract carbon footprint node using framing
async function extractCarbonFootprintNode(slug: string): Promise<Record<string, unknown> | null> {
const document = await fetchDppJsonLd(slug);

const frame = {
'@context': { 'traceable': 'https://vocab.traceable.digital/v1#' },
'@type': 'traceable:CarbonFootprint'
};

const framed = await jsonld.frame(document, frame) as {
'@graph'?: Array<Record<string, unknown>>;
};

return framed['@graph']?.[0] ?? null;
}

// Usage
const compacted = await compactDppJsonLd('swiftvolt-48v-100ah-ev-pack');
console.log('Product name:', compacted.name);
console.log('Battery category:', compacted.batteryCategory);
console.log('Published:', compacted.datePublished);

const cf = await extractCarbonFootprintNode('swiftvolt-48v-100ah-ev-pack');
if (cf) {
console.log('Carbon footprint:', cf['traceable:totalKgCO2ePerKwh'], 'kgCO₂e/kWh');
console.log('Verified by:', cf['traceable:verifiedBy']);
}

Python with pyld

Install the dependency:

pip install PyLD requests
import requests
from pyld import jsonld
from typing import Any


def fetch_dpp_jsonld(slug: str) -> dict:
"""Fetch the JSON-LD representation of a DPP."""
url = f"https://app.traceable.digital/api/dpp/{slug}/jsonld"
response = requests.get(url, timeout=10)
response.raise_for_status()
return response.json()


def compact_dpp_jsonld(slug: str) -> dict:
"""Fetch and compact a DPP JSON-LD document to a local context."""
document = fetch_dpp_jsonld(slug)

local_context = {
"@context": {
"name": "https://schema.org/name",
"manufacturer": "https://schema.org/manufacturer",
"orgName": "https://schema.org/name",
"addressCountry": "https://schema.org/addressCountry",
"batteryCategory": "https://vocab.traceable.digital/v1#batteryCategory",
"carbonFootprint": "https://vocab.traceable.digital/v1#carbonFootprint",
"totalKgCO2ePerKwh": "https://vocab.traceable.digital/v1#totalKgCO2ePerKwh",
}
}

return jsonld.compact(document, local_context)


def extract_manufacturer(slug: str) -> dict | None:
"""Extract the manufacturer Organisation node using JSON-LD framing."""
document = fetch_dpp_jsonld(slug)

frame = {
"@context": {"schema": "https://schema.org/"},
"@type": "schema:Organization"
}

framed = jsonld.frame(document, frame)
graph = framed.get("@graph", [])
return graph[0] if graph else None


# Usage
compacted = compact_dpp_jsonld("swiftvolt-48v-100ah-ev-pack")
print(f"Product: {compacted.get('name')}")
print(f"Category: {compacted.get('batteryCategory')}")

manufacturer = extract_manufacturer("swiftvolt-48v-100ah-ev-pack")
if manufacturer:
print(f"Manufacturer: {manufacturer.get('schema:name')}")
print(f"Country: {manufacturer.get('schema:addressCountry')}")

Plain JSON extraction (no JSON-LD library)

For systems that need specific fields and do not require full semantic processing, navigate the JSON-LD response directly:

async function extractDppFields(slug: string): Promise<{
productName: string;
batteryCategory: string;
manufacturerName: string | undefined;
manufacturerCountry: string | undefined;
carbonFootprintTotal: string | number | undefined;
cobaltPercent: string | number | undefined;
publishedAt: string | undefined;
}> {
const response = await fetch(
`https://app.traceable.digital/api/dpp/${encodeURIComponent(slug)}/jsonld`
);

if (!response.ok) {
throw new Error(`Failed to fetch JSON-LD: HTTP ${response.status}`);
}

const doc = await response.json();

// Navigate known paths — works without a JSON-LD library
const manufacturerNode = doc['schema:manufacturer'] ?? {};
const carbonFootprintNode = doc['traceable:carbonFootprint'] ?? {};
const recycledContentNode = doc['traceable:recycledContent'] ?? {};

return {
productName: doc['schema:name'],
batteryCategory: doc['traceable:batteryCategory'],
manufacturerName: manufacturerNode['schema:name'],
manufacturerCountry: manufacturerNode['schema:addressCountry'],
// Typed literals have an @value property
carbonFootprintTotal: carbonFootprintNode['traceable:totalKgCO2ePerKwh']?.['@value']
?? carbonFootprintNode['traceable:totalKgCO2ePerKwh'],
cobaltPercent: recycledContentNode['traceable:cobaltPercent']?.['@value']
?? recycledContentNode['traceable:cobaltPercent'],
publishedAt: doc['schema:datePublished']?.['@value'] ?? doc['schema:datePublished'],
};
}

// Usage
const fields = await extractDppFields('swiftvolt-48v-100ah-ev-pack');
console.log(fields);
// {
// productName: 'SwiftVolt 48V 100Ah EV Pack',
// batteryCategory: 'EV_BATTERY',
// manufacturerName: 'SwiftVolt Energy Systems GmbH',
// manufacturerCountry: 'DE',
// carbonFootprintTotal: '61.4',
// cobaltPercent: '16.0',
// publishedAt: '2025-02-01T10:14:22Z'
// }
Typed literals

Numeric values in the JSON-LD response are represented as typed literals: { "@type": "xsd:decimal", "@value": "61.4" }. When doing plain JSON extraction, check for both the literal form and the raw value (as shown above) to handle both cases defensively.

Embedding in HTML head for SEO

To embed the DPP JSON-LD in your product page's <head> for search engine structured data:

import { NextResponse } from 'next/server';

// Next.js App Router example — page.tsx
export default async function DppPage({ params }: { params: { slug: string } }) {
const jsonLdResponse = await fetch(
`https://app.traceable.digital/api/dpp/${params.slug}/jsonld`,
{ next: { revalidate: 300 } } // revalidate every 5 minutes
);

let jsonLdData: object | null = null;
if (jsonLdResponse.ok) {
jsonLdData = await jsonLdResponse.json();
}

return (
<>
{jsonLdData && (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(jsonLdData),
}}
/>
)}
<main>
{/* page content */}
</main>
</>
);
}

For non-React applications, the equivalent HTML markup:

<head>
<meta charset="UTF-8">
<title>SwiftVolt 48V 100Ah EV Pack — Battery Passport</title>

<script type="application/ld+json">
{
"@context": {
"schema": "https://schema.org/",
"traceable": "https://vocab.traceable.digital/v1#"
},
"@type": ["schema:Product", "traceable:BatteryPassport"],
"@id": "https://app.traceable.digital/dpp/swiftvolt-48v-100ah-ev-pack",
"schema:name": "SwiftVolt 48V 100Ah EV Pack",
"schema:identifier": "swiftvolt-48v-100ah-ev-pack",
"schema:manufacturer": {
"@type": "schema:Organization",
"schema:name": "SwiftVolt Energy Systems GmbH",
"schema:addressCountry": "DE"
},
"schema:datePublished": {
"@type": "http://www.w3.org/2001/XMLSchema#dateTime",
"@value": "2025-02-01T10:14:22Z"
}
}
</script>
</head>

The JSON.stringify output is safe to embed in a <script type="application/ld+json"> tag — JSON-LD does not require HTML escaping for most characters. However, if user-provided content could appear in the JSON (for example, product names), ensure you escape the </script> sequence by replacing </ with <\/ before embedding.

// Safe embedding of potentially user-influenced JSON-LD
function safeJsonLdString(data: object): string {
return JSON.stringify(data).replace(/<\//g, '<\\/');
}