Page2JSON — Dynamic Webpage to Structured JSON avatar

Page2JSON — Dynamic Webpage to Structured JSON

Under maintenance

Pricing

from $0.36 / 1,000 results

Go to Apify Store
Page2JSON — Dynamic Webpage to Structured JSON

Page2JSON — Dynamic Webpage to Structured JSON

Under maintenance

Convert public webpages into clean structured JSON, including JavaScript-rendered pages. Built for agents, automations, and data workflows.

Pricing

from $0.36 / 1,000 results

Rating

0.0

(0)

Developer

Mikkel Bech-Hansen

Mikkel Bech-Hansen

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

1

Monthly active users

5 days ago

Last modified

Share

Page2JSON Actor

Convert public webpages into clean structured JSON, including JavaScript-rendered pages.

Features

  • Multi-mode extraction: auto, static, browser, network, screenshot
  • Intelligent content detection: JSON-LD, embedded JSON, network responses, HTML scraping
  • Browser rendering: Full Chromium with auto-scroll, element waiting, and network capture
  • Dynamic content handling: Handles SPAs, lazy-loaded content, and JavaScript-rendered pages
  • Structured JSON output: Maps extracted data to custom schemas

Getting Started

Prerequisites

  • Node.js 20+
  • Apify CLI

Installation

# Install Apify CLI globally
npm install -g apify-cli
# Initialize the actor
apify init page2json-actor --yes
# Install dependencies
npm install
# Build and push
npm run build
# Run locally
apify run
# Run on Apify platform
apify push

Input Schema

ParameterTypeDefaultDescription
urlsarrayrequiredList of URLs to extract content from
schemaobjectoptionalDesired JSON schema for extracted data
modestring'auto'Extraction mode: auto, static, browser, network, screenshot
render.waitForSelectorstringoptionalCSS selector to wait for before extracting
render.waitForNetworkIdlebooleantrueWait for network to be idle before extracting
render.maxWaitMsinteger15000Maximum wait time (milliseconds)
render.scrollbooleanfalseEnable scrolling for lazy-loaded content
render.maxScrollsinteger8Maximum scrolls to perform
render.scrollDelayMsinteger800Delay between scrolls (milliseconds)
render.clickSelectorsarray[]CSS selectors to click before extraction
extraction.preferJsonLdbooleantruePrefer data from JSON-LD
extraction.preferEmbeddedJsonbooleantruePrefer embedded JSON (e.g., NEXT_DATA)
extraction.preferNetworkJsonbooleantruePrefer network JSON responses
extraction.includeRawTextbooleanfalseInclude raw page text in output
extraction.includeHtmlbooleanfalseInclude raw HTML in output
extraction.includeScreenshotbooleanfalseInclude a screenshot in output
limits.maxPagesinteger10Maximum pages to process
limits.maxConcurrencyinteger3Maximum concurrent requests
limits.maxResponseBytesinteger5000000Maximum response size (bytes)

Output

Each URL returns a structured result:

FieldTypeDescription
urlstringThe processed URL
statusstringsuccess, partial_success, failed, blocked, timeout, invalid_input, unsupported_content_type
extractionMethodstringHow the data was extracted (static_html, json_ld, embedded_json, browser_dom, browser_network_json)
renderedbooleanWhether browser rendering was used
confidencenumberExtraction quality score (0.0 - 1.0)
dataobjectExtracted data mapped to the schema
missingFieldsarrayFields that were requested but not found
warningsarrayIssues encountered during extraction
costSignalsobjectUsage metrics for billing estimation
debugobjectTechnical details for troubleshooting

Cost Model

MethodCost
Static HTML$0.001
JSON-LD / Embedded JSON$0.005
Network JSON$0.01
Full Rendering$0.02
Screenshot+$0.01

Examples

Simple extraction (auto mode)

{
"urls": ["https://example.com"],
"schema": {
"title": "string",
"content": "string"
}
}

Product page extraction

{
"urls": ["https://shop.example.com/product/123"],
"schema": {
"title": "string",
"price": "string",
"description": "string",
"images": "array",
"reviews": "array"
},
"mode": "auto"
}

Browser-rendered page (SPA)

{
"urls": ["https://react-app.example.com"],
"schema": {
"products": "array"
},
"mode": "browser",
"render": {
"waitForSelector": ".product-grid",
"scroll": true,
"maxScrolls": 10,
"clickSelectors": ["#load-more-button"]
}
}

Architecture

src/
extractors/
staticHtmlExtractor.ts — HTML scraping (beautifulsoup4)
jsonLdExtractor.ts — JSON-LD extraction (jsonld npm)
embeddedJsonExtractor.ts — __NEXT_DATA__ etc. (regex)
browserDomExtractor.ts — DOM scraping (playwright)
networkJsonExtractor.ts — Intercept network calls (playwright)
tableExtractor.ts — HTML table parsing (cheerio)
commonFieldExtractors.ts — Title, meta, headings, links
browser/
renderPage.ts — Playwright browser control
captureNetworkJson.ts — Network response monitoring
waitForDomStable.ts — DOM stability detection
autoScroll.ts — Lazy content loading
scoring/
confidence.ts — Quality scoring (0.0 - 1.0)
dynamicDetection.ts — Detect if browser is needed
schema/
validateInput.ts — Input validation
mapToSchema.ts — Schema mapping
monetization/
billingEstimator.ts — Cost estimation
usageLogger.ts — Usage logging
utils/
htmlProcessor.ts — Text extraction
retryLogic.ts — Retry with backoff
errorHandling.ts — Error classes
rateLimiter.ts — Concurrency control
types.ts — TypeScript types
main.ts — Actor entry point

Running Locally

# Build
npm run build
# Run locally
apify run
# Run on Apify
apify push

Environment Variables

VariableDefaultDescription
APIFY_TOKENApify API token
APIFY_DEFAULT_KEY_VALUE_STORE_IDactor's defaultKey-value store ID
PLAYWRIGHT_TIMEOUT30000Playwright browser timeout (ms)
MAX_BROWSERS5Max concurrent browsers

API Reference

Input

interface Page2JSONInput {
urls: string[];
schema?: Record<string, string>;
mode?: 'auto' | 'static' | 'browser' | 'network' | 'screenshot';
render?: {
waitForSelector?: string;
waitForNetworkIdle?: boolean;
maxWaitMs?: number;
scroll?: boolean;
maxScrolls?: number;
scrollDelayMs?: number;
clickSelectors?: string[];
};
extraction?: {
preferJsonLd?: boolean;
preferEmbeddedJson?: boolean;
preferNetworkJson?: boolean;
includeRawText?: boolean;
includeHtml?: boolean;
includeScreenshot?: boolean;
};
limits?: {
maxPages?: number;
maxConcurrency?: number;
maxResponseBytes?: number;
};
}

Output

interface ExtractionResult {
url: string;
status: 'success' | 'partial_success' | 'failed' | 'blocked' | 'timeout' | 'invalid_input' | 'unsupported_content_type';
extractionMethod: string;
rendered: boolean;
confidence: number;
data: Record<string, unknown>;
missingFields: string[];
warnings: string[];
costSignals: {
browserUsed: boolean;
requestCount: number;
durationMs: number;
responseBytes: number;
totalCost: number;
};
debug: {
staticTextLength: number;
renderedTextLength: number;
jsonLdFound: boolean;
embeddedJsonFound: boolean;
networkJsonCandidates: number;
};
}

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

License

MIT