# Product JSON-LD Normalizer — Offers, Prices & Variants (`damdamdoom/product-json-ld-normalizer`) Actor

Normalize Product, ProductGroup, Offer, and AggregateOffer JSON-LD from one static product page.

- **URL**: https://apify.com/damdamdoom/product-json-ld-normalizer.md
- **Developed by:** [Masatoshi Shimada](https://apify.com/damdamdoom) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 20.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Product JSON-LD Normalizer — Offers, Prices & Variants

This Apify Actor fetches one public static HTML page and stores exactly one deterministic page result containing normalized Schema.org `Product`, `ProductGroup`, `Offer`, and `AggregateOffer` JSON-LD.

### Input

```json
{
  "url": "https://example.com/product/sku-1",
  "timeoutSeconds": 15,
  "maxResponseBytes": 5242880,
  "maxRedirects": 3
}
```

Only `url` is required. Unknown fields and non-public destinations are rejected. Every redirect is resolved and SSRF-checked again. The fetcher pins the connection to the checked IP and bounds both compressed and expanded bodies.

### Output

A successful fetch pushes exactly one item to the default dataset, including pages with no Product or malformed JSON-LD. Missing values remain `null` or empty arrays. Prices are parsed without a binary float and emitted as non-exponent decimal strings. Every normalized node and finding includes a deterministic `sourcePath`.

Finding codes cover malformed JSON-LD, missing products and identifiers, absent or invalid offers, price/currency/availability problems, invalid aggregate ranges, ambiguous scalar fields, and unresolved references.

### Supported scope

- One public HTTP(S) URL and static HTML only
- `application/ld+json` top-level objects, arrays, `@graph`, and embedded `hasVariant`
- Product and ProductGroup nodes with embedded Offer or AggregateOffer
- `@type` as a string or array

The Actor does not render JavaScript, browse or crawl, use proxies, parse Microdata/RDFa, resolve external `@id` values, inherit group data into variants, validate live stock, or store raw HTML/JSON-LD. It needs no Secret, API key, paid API, browser, or external service.

### Local verification

From this directory with the repository virtual environment available:

```powershell
..\..\.venv\Scripts\python.exe -m unittest discover -s tests -v
..\..\.venv\Scripts\python.exe -m ruff check .
```

For a local Actor run, put input in `storage/key_value_stores/default/INPUT.json`, expose only a local fixture through the test resolver or use an explicitly approved public page, and run `apify run`. Local tests use fixture HTTP only and cost `¥0`.

### Release boundary

Human Owner approved Product #2 Public release, Monetization, and `$0.002` per successful `apify-default-dataset-item` on 2026-08-15. Platform activation remains pending candidate build and production verification; this Release Candidate source artifact alone is not a declaration that those settings are active. Paid cloud runs and external spending remain separate approval-gated actions.

# Actor input Schema

## `url` (type: `string`):

One public HTTP or HTTPS product page. Private and local destinations are rejected.

## `timeoutSeconds` (type: `integer`):

Connection and response read timeout for each request.

## `maxResponseBytes` (type: `integer`):

Reject if either compressed or expanded bytes exceed this value.

## `maxRedirects` (type: `integer`):

Maximum redirects to follow. Every destination is checked again before connecting.

## Actor input object example

```json
{
  "url": "https://example.com/",
  "timeoutSeconds": 15,
  "maxResponseBytes": 5242880,
  "maxRedirects": 3
}
```

# Actor output Schema

## `results` (type: `string`):

Normalized products, groups, offers, findings, and evidence.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "url": "https://example.com/"
};

// Run the Actor and wait for it to finish
const run = await client.actor("damdamdoom/product-json-ld-normalizer").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "url": "https://example.com/" }

# Run the Actor and wait for it to finish
run = client.actor("damdamdoom/product-json-ld-normalizer").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "url": "https://example.com/"
}' |
apify call damdamdoom/product-json-ld-normalizer --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,damdamdoom/product-json-ld-normalizer"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/0TZxW7MJ9HeMn0Jrr/builds/ZaWsqUvymxCU80fXV/openapi.json
