# Product JSON-LD Extractor (`eichan/product-jsonld-extractor`) Actor

Extract one product name, description, brand, and category from a user-provided public product page's schema.org Product JSON-LD.

- **URL**: https://apify.com/eichan/product-jsonld-extractor.md
- **Developed by:** [Eichan Jolly](https://apify.com/eichan) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.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/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Product JSON-LD Extractor

Extract **one product's basic metadata** from one user-supplied public product page containing [schema.org Product](https://schema.org/Product) JSON-LD. No store login, browser, proxy, Apify SDK, or third-party Python library is required.

### What it does

1. Validates a single public `productUrl`.
2. Downloads only that HTML page (up to 2 MB), following at most three same-store redirects.
3. Reads `<script type="application/ld+json">` blocks, including JSON-LD arrays and `@graph` objects.
4. Finds the first usable `Product` node, extracts five stable fields, and appends **one** dataset item via the Apify REST API.

There is **no full HTML product scraping** or price extraction. This Actor does not discover products or visit embedded links.

### Who it is for

Small retailers, catalog administrators, and data teams who need basic schema.org metadata from a product URL they already know.

### Input

```json
{
  "productUrl": "https://example.com/products/sample-product"
}
```

The example address is **illustrative only** and does not promise an actual Product JSON-LD record. Replace it with a public product page you want to examine. The Apify Console prefill contains exactly one URL.

| Field | Type | Required | Meaning |
|---|---|---|---|
| `productUrl` | string | Yes | One HTTP(S) product-page URL; no login or custom ports. |

### Example output

The following example is **illustrative**, not a claim about the example URL's live content:

```json
{
  "url": "https://example.com/products/sample-product",
  "name": "Canvas Tote Bag",
  "description": "Reusable cotton tote bag.",
  "brand": "Sample Goods",
  "category": "Bags"
}
```

Each successful run produces **at most one dataset item**. These five keys are always present. Unavailable values are `null`, not invented. `url` is the original normalized input URL (without the fragment). `brand` can be a text value or the `name` from a brand object. A category array is joined into a comma-separated string.

### Limits and expected behavior

- **Only public HTML:** JavaScript-rendered metadata, microdata, RDFa, and hidden/authenticated records are not parsed.
- **JSON-LD only:** Nested JSON-LD nodes are searched, but only the first usable `Product` is returned. Product variants or multiple products on one page are not independently listed.
- **No data found:** If the page has no usable schema.org `Product` JSON-LD, the Actor logs a clear message and returns **zero dataset items**. A missing optional field is `null`.
- **Resource caps:** 15-second HTTP timeout, 2 MB HTML limit, 100 JSON-LD blocks, and 3,000 inspected JSON nodes. One product URL is fetched per run.
- **URL restrictions:** Rejects local/private/non-global destinations at initial DNS validation, credentials, custom ports, Amazon/eBay domains, and redirects outside the supplied store (the `www` hostname variation is allowed). DNS checks reduce SSRF risk but are not a complete defense against DNS rebinding.
- **Transport:** Python `urllib.request` with standard certificate verification. Sites may rate-limit, block automated requests, or return malformed JSON-LD; there is no bypass or retry flood.
- **Errors:** Inaccessible URLs, malformed responses, and invalid input are reported in plain language in the run log, without tracebacks. Network failures result in a nonzero exit code.
- **Public data:** Use only product URLs you are permitted to access; honor the site's terms and applicable law.

### Run on Apify

Upload this folder as an independent Actor (the `.actor/actor.json` links to `../input_schema.json` and `../Dockerfile`). On a normal Apify run, the code reads the `INPUT` record from the run's default key-value store and writes one JSON array item to the default dataset via authenticated Apify REST endpoints. `APIFY_TOKEN` and the default storage IDs are supplied by Apify. It does **not** require the Apify SDK.

### Run locally

Requires Python 3.12+ and no installed packages:

```bash
cd product-jsonld-extractor
printf '{"productUrl":"https://YOUR_PUBLIC_PRODUCT_URL"}\n' > input.json
python src/main.py --input input.json
```

Local mode prints **one JSONL line to stdout** when a product is found. Explanatory messages go to stderr. Local mode does not contact Apify storage.

### Store classification and pricing suggestion

- **Apify category / industry:** E-commerce
- **Suggested use case:** Product data extraction
- **Suggested output type:** Products
- **Suggested pricing:** $3.00 USD per 1,000 **successfully emitted dataset items** ($0.003 each), on a per-result basis.

These are **publishing recommendations**, not charged or declared automatically by `actor.json`. Configure the current Apify Store classification and monetization/event billing separately in the publisher console. Do not charge for an empty result.

# Actor input Schema

## `productUrl` (type: `string`):

A public product-page URL supplied by you. Replace the illustrative example before running. No Amazon, eBay, or login pages.

## Actor input object example

```json
{
  "productUrl": "https://example.com/products/sample-product"
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing the Actor's result items

# 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 = {
    "productUrl": "https://example.com/"
};

// Run the Actor and wait for it to finish
const run = await client.actor("eichan/product-jsonld-extractor").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 = { "productUrl": "https://example.com/" }

# Run the Actor and wait for it to finish
run = client.actor("eichan/product-jsonld-extractor").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 '{
  "productUrl": "https://example.com/"
}' |
apify call eichan/product-jsonld-extractor --silent --output-dataset

```

## MCP server setup

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

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/BBjUlo8iEjIT8OPFN/builds/fOKwacByZcX4BECzy/openapi.json
