Extract a JavaScript-Rendered Product Page
This real-world example shows how to extract product content from a JavaScript-rendered e-commerce page using the Scraper API.
We will use the ScrapingCourse JavaScript Rendering page and compare the same extraction with JavaScript rendering disabled and enabled.
Use Case
Modern websites often use JavaScript to render or load content after the initial page response.
For this example, we use:
https://www.scrapingcourse.com/javascript-renderingThe page contains multiple products with their names, prices, and product links.
The extracted content includes products such as:
- Chaz Kangeroo Hoodie — $52
- Teton Pullover Hoodie — $70
- Bruno Compete Hoodie — $63
- Frankie Sweatshirt — $60
- Hollister Backyard Sweatshirt — $52
- Stark Fundamental Hoodie — $42
- Hero Hoodie — $54
- Oslo Trek Hoodie — $42
- Abominable Hoodie — $69
- Mach Street Sweatshirt — $62
- Grayson Crewneck Sweatshirt — $64
- Ajax Full-Zip Sweatshirt — $69
Before You Start
You need:
- A Geonode API key
- Python 3.9 or later
- The
requestspackage
Store your API key in an environment variable:
export GEONODE_SCRAPER_API_KEY="YOUR_API_KEY"On Windows PowerShell:
$env:GEONODE_SCRAPER_API_KEY="YOUR_API_KEY"Keep Your API Key Private
Never put your Geonode API key directly in your source code or commit it to your repository. Store it in an environment variable or .env file instead.
Install the Dependency
Install the requests package:
pip install requestsCase 1: Extract Without JavaScript Rendering
First, send the request with JavaScript rendering disabled.
import os
import requests
api_key = os.environ["GEONODE_SCRAPER_API_KEY"]
response = requests.post(
"https://scraper.geonode.io/v1/extract",
headers={
"X-Api-Key": api_key,
"Content-Type": "application/json",
},
json={
"url": "https://www.scrapingcourse.com/javascript-rendering",
"formats": ["markdown"],
"render_js": False,
"processing_mode": "sync",
},
)
response.raise_for_status()
result = response.json()
print(result["data"]["markdown"])Case 1 Result
The actual extraction returned the following Markdown:
---
meta-viewport: width=device-width, initial-scale=1.0
title: JS Rendering Challenge to Learn Web Scraping - ScrapingCourse.com
---
# JS Rendering

## Challenge
Enable JavaScript to see products
[Chaz Kangeroo Hoodie Chaz Kangeroo Hoodie $52](https://scrapingcourse.com/ecommerce/product/chaz-kangeroo-hoodie)
[Teton Pullover Hoodie Teton Pullover Hoodie $70](https://scrapingcourse.com/ecommerce/product/teton-pullover-hoodie)
[Bruno Compete Hoodie Bruno Compete Hoodie $63](https://scrapingcourse.com/ecommerce/product/bruno-compete-hoodie)
[Frankie Sweatshirt Frankie Sweatshirt $60](https://scrapingcourse.com/ecommerce/product/frankie-sweatshirt)
[Hollister Backyard Sweatshirt Hollister Backyard Sweatshirt $52](https://scrapingcourse.com/ecommerce/product/hollister-backyard-sweatshirt)
[Stark Fundamental Hoodie Stark Fundamental Hoodie $42](https://scrapingcourse.com/ecommerce/product/stark-fundamental-hoodie)
[Hero Hoodie Hero Hoodie $54](https://scrapingcourse.com/ecommerce/product/hero-hoodie)
[Oslo Trek Hoodie Oslo Trek Hoodie $42](https://scrapingcourse.com/ecommerce/product/oslo-trek-hoodie)
[Abominable Hoodie Abominable Hoodie $69](https://scrapingcourse.com/ecommerce/product/abominable-hoodie)
[Mach Street Sweatshirt Mach Street Sweatshirt $62](https://scrapingcourse.com/ecommerce/product/mach-street-sweatshirt)
[Grayson Crewneck Sweatshirt Grayson Crewneck Sweatshirt $64](https://scrapingcourse.com/ecommerce/product/grayson-crewneck-sweatshirt)
[Ajax Full-Zip Sweatshirt Ajax Full-Zip Sweatshirt $69](https://scrapingcourse.com/ecommerce/product/ajax-full-zip-sweatshirt)Case 2: Extract With JavaScript Rendering
Now run the same extraction with JavaScript rendering enabled.
The only change is:
"render_js": trueimport os
import requests
api_key = os.environ["GEONODE_SCRAPER_API_KEY"]
response = requests.post(
"https://scraper.geonode.io/v1/extract",
headers={
"X-Api-Key": api_key,
"Content-Type": "application/json",
},
json={
"url": "https://www.scrapingcourse.com/javascript-rendering",
"formats": ["markdown"],
"render_js": True,
"processing_mode": "sync",
},
)
response.raise_for_status()
result = response.json()
print(result["data"]["markdown"])Case 2 Result
The actual extraction returned the following Markdown:
---
meta-viewport: width=device-width, initial-scale=1.0
title: JS Rendering Challenge to Learn Web Scraping - ScrapingCourse.com
---
# JS Rendering

## Challenge
Enable JavaScript to see products
[Chaz Kangeroo Hoodie Chaz Kangeroo Hoodie $52](https://scrapingcourse.com/ecommerce/product/chaz-kangeroo-hoodie)
[Teton Pullover Hoodie Teton Pullover Hoodie $70](https://scrapingcourse.com/ecommerce/product/teton-pullover-hoodie)
[Bruno Compete Hoodie Bruno Compete Hoodie $63](https://scrapingcourse.com/ecommerce/product/bruno-compete-hoodie)
[Frankie Sweatshirt Frankie Sweatshirt $60](https://scrapingcourse.com/ecommerce/product/frankie-sweatshirt)
[Hollister Backyard Sweatshirt Hollister Backyard Sweatshirt $52](https://scrapingcourse.com/ecommerce/product/hollister-backyard-sweatshirt)
[Stark Fundamental Hoodie Stark Fundamental Hoodie $42](https://scrapingcourse.com/ecommerce/product/stark-fundamental-hoodie)
[Hero Hoodie Hero Hoodie $54](https://scrapingcourse.com/ecommerce/product/hero-hoodie)
[Oslo Trek Hoodie Oslo Trek Hoodie $42](https://scrapingcourse.com/ecommerce/product/oslo-trek-hoodie)
[Abominable Hoodie Abominable Hoodie $69](https://scrapingcourse.com/ecommerce/product/abominable-hoodie)
[Mach Street Sweatshirt Mach Street Sweatshirt $62](https://scrapingcourse.com/ecommerce/product/mach-street-sweatshirt)
[Grayson Crewneck Sweatshirt Grayson Crewneck Sweatshirt $64](https://scrapingcourse.com/ecommerce/product/grayson-crewneck-sweatshirt)
[Ajax Full-Zip Sweatshirt Ajax Full-Zip Sweatshirt $69](https://scrapingcourse.com/ecommerce/product/ajax-full-zip-sweatshirt)Compare the Results
You can compare both requests directly:
Observed Result
For this particular target and the captured runs, both cases returned the same Markdown content. The example therefore demonstrates how to enable JavaScript rendering, but the captured result does not establish that render_js is required for this page.
Extracted Products
The returned Markdown contains 12 product entries.
| Product | Price |
|---|---|
| Chaz Kangeroo Hoodie | $52 |
| Teton Pullover Hoodie | $70 |
| Bruno Compete Hoodie | $63 |
| Frankie Sweatshirt | $60 |
| Hollister Backyard Sweatshirt | $52 |
| Stark Fundamental Hoodie | $42 |
| Hero Hoodie | $54 |
| Oslo Trek Hoodie | $42 |
| Abominable Hoodie | $69 |
| Mach Street Sweatshirt | $62 |
| Grayson Crewneck Sweatshirt | $64 |
| Ajax Full-Zip Sweatshirt | $69 |
Understanding the Response
The extracted page content is available under:
data.markdownYou can use the returned Markdown directly or process it further in your application.
For example:
markdown = result["data"]["markdown"]
print(markdown)The Scraper API returns page content rather than automatically converting the page into structured product fields.
If your application needs fields such as:
name
price
url
sku
availabilityyou can parse the returned Markdown or HTML in your own application.
Structured Product Data
The Scraper API returns extracted page content as Markdown or HTML. It does not automatically return e-commerce fields such as product name, price, or SKU as structured fields.
When to Use JavaScript Rendering
Use:
"render_js": truewhen the content you need depends on JavaScript execution.
Common examples include:
- Product information loaded after the page opens
- Client-side rendered product listings
- Content populated dynamically by JavaScript
- Pages where the initial HTML does not contain the content you need
For pages where the required content is already available without browser rendering, you can use:
"render_js": falseThis avoids browser rendering when it is not needed.
What About wait_config?
This example does not include wait_config.
The focused Case 2 probe successfully completed with:
{
"render_js": true,
"processing_mode": "sync",
"wait_config": null
}It reported 12 product links and 12 prices in the returned Markdown.
Using wait_config
If a JavaScript-rendered page requires an explicit browser wait condition, you can use wait_config to control when the browser should consider the page ready for extraction.
Complete Example
Once you understand the difference between the two requests, the JavaScript-rendered version can be reduced to this:
import os
import requests
API_KEY = os.environ["GEONODE_SCRAPER_API_KEY"]
URL = "https://www.scrapingcourse.com/javascript-rendering"
response = requests.post(
"https://scraper.geonode.io/v1/extract",
headers={
"X-Api-Key": API_KEY,
"Content-Type": "application/json",
},
json={
"url": URL,
"formats": ["markdown"],
"render_js": True,
"processing_mode": "sync",
},
)
response.raise_for_status()
result = response.json()
print(result["data"]["markdown"])Request Parameters
| Parameter | Value | Purpose |
|---|---|---|
url | https://www.scrapingcourse.com/javascript-rendering | Target page to extract |
formats | ["markdown"] | Returns the extracted content as Markdown |
render_js | true | Enables JavaScript rendering |
processing_mode | sync | Waits for the extraction to complete |
Next Steps
Now that you can extract a page with JavaScript rendering, continue to Compare a Product Page Across Locations to extract the same product page from different countries with proxy geo-targeting.
You can also explore:
- Extract multiple product URLs with Batch
- Discover product URLs with Map and extract them with Batch
- Crawl a product or content section
- Run longer extractions asynchronously