` | omitted | Query `geoCode` | Requests proxy routing through the ISO 3166-1 alpha-2 country. |
| `--wait-for-selector ` | omitted | Query `waitForSelector` | Waits for a CSS selector. The CLI rejects it unless `--browser-rendering` is explicit. |
| `--home-page` | `false` | Query `homePage=true` | Visits the site root before loading the target page. |
| `--block-resources` | `false` | Query `blockResources=true` | Blocks non-essential browser resources when supported by the selected proxy. |
| `--max-retries ` | `3` | Query `maxRetries` | Sets the maximum retry attempts after a failed request. Zero is accepted. |
| `--token-cap ` | omitted | Query `tokenCap` | Limits the running plan-token total used to decide whether another retry may run. The initial request always runs. |
| `--timeout ` | `30` | Query `timeout` | Sets the page-load timeout. The command allows an additional 30 seconds to receive the response. |
| `--token ` | configured credential | Request headers | Overrides authentication for this command. |
Use browser rendering when JavaScript is needed, but retry the same Super Mode
value without it when browser loading fails, is blocked, or returns worse
content. Toggle Super Mode independently when routing may be the problem. A
selector wait still requires browser rendering. Unblocker usage is based on
runtime and bandwidth: one plan token
per 30 seconds and one plan token per 0.25 MB, rounded up per component. Resource
blocking can reduce bandwidth for text-focused pages. Use `--max-retries` and
`--token-cap` to balance retry reliability with usage. See the
[Token Plan](/docs/getting-started/api-token) for the complete calculation.
### `scrape`
`scrape` calls:
```text
POST https://api.app.mrscraper.com/api/v1/scrapers-ai
```
The default agent is `general`. General and listing require an extraction
prompt:
```bash
mrscraper scrape "https://example.com/product" \
--mode Super \
--prompt "Extract name, price, availability, and image URLs"
```
The request body contains `url`, `message`, and `agent`, plus optional fields
for the selected agent. `--mode Cheap` and `--mode Super` select the backend
execution tier independently of `--agent`; omit `--mode` to preserve the
backend default.
#### Listing agent
```bash
mrscraper scrape "https://example.com/products" \
--agent listing \
--prompt "Extract every product's name, price, and URL" \
--max-pages 5
```
Listing is synchronous and may take several minutes. Progress is printed to
stderr. If `--max-pages` is omitted, the service default applies.
#### Map agent
```bash
mrscraper scrape "https://example.com" \
--agent map \
--max-depth 2 \
--max-pages 50 \
--limit 1000 \
--include-patterns '/products/'
```
Map accepts crawl limits and URL patterns. Prompts, schema guidance, and proxy
country selection are available with the general and listing agents.
#### Local output file
```bash
mrscraper scrape "https://example.com/product" \
--prompt "Extract the product" \
--output ./.mrscraper/product.json
```
`--output` creates parent directories and writes the extracted
`data.data.data` value as pretty JSON. The complete response remains on stdout.
The file is created after a completed extraction returns data.
#### Best-effort schema prompt
```bash
mrscraper scrape "https://example.com/product" \
--prompt "Extract the product" \
--schema-prompt ./product.schema.json
```
`--schema-prompt` reads a local JSON Schema object and adds it to the extraction
instructions as best-effort shape guidance. Use a separate validator when
strict schema compliance is required.
#### Reproduce a scrape with `rerun`
Every successful `scrape` creates a saved AI scraper configuration by default.
The complete stdout response contains its UUID at `data.data.scraperId`. Save
that response when the extraction may need to run again:
```bash
mrscraper scrape "https://example.com/product" \
--prompt "Extract the product name, price, and availability" \
--output ./.mrscraper/product.json \
> ./.mrscraper/product-run.json
SCRAPER_UUID=$(jq -r '.data.data.scraperId' ./.mrscraper/product-run.json)
mrscraper rerun "https://example.com/product-2" \
--type ai \
--scraper-id "$SCRAPER_UUID"
```
The output file contains only `data.data.data`; the stdout envelope retains the
scraper UUID. `rerun` reproduces the saved prompt and agent configuration, but
page changes and model behavior can still change the extracted values.
`rerun` also supports dashboard-built manual workflows and asynchronous bulk
jobs across multiple target URLs. See the full [`rerun`](#rerun) section below
for the available modes and result-tracking workflow.
#### `scrape` parameters
| CLI parameter | Default | API mapping | Accepted agents and behavior |
| ---------------------------- | --------------------- | -------------------------- | -------------------------------------------------------------- |
| `` | required | Body `url` | Target URL for all agents. |
| `-p, --prompt ` | required | Body `message` | Extraction instructions for general/listing. |
| `-a, --agent ` | `general` | Body `agent` | `general`, `listing`, or `map`. |
| `--mode ` | omitted | Body `mode` | Selects the backend execution tier without changing the agent. |
| `--proxy-country ` | omitted | Body `proxyCountry` | General/listing only; rejected for map. |
| `--max-pages ` | omitted | Body `maxPages` | Listing/map only. The service default applies when omitted. |
| `--max-depth ` | omitted | Body `maxDepth` | Map only. |
| `--limit ` | omitted | Body `limit` | Map only. |
| `--include-patterns ` | omitted | Body `includePatterns` | Map only. |
| `--exclude-patterns ` | omitted | Body `excludePatterns` | Map only. |
| `--schema-prompt ` | omitted | Appended to body `message` | Best-effort shape guidance for general/listing. |
| `-o, --output ` | omitted | Output file | Writes `data.data.data` as pretty JSON. |
| `--token ` | configured credential | Request headers | Overrides authentication for this command. |
### `serp`
`serp` calls:
```text
POST https://sync.scraper.mrscraper.com/api/google/serp/v2/sync
```
Use `--format` to choose parsed JSON or the result-page HTML:
```bash
mrscraper serp "iphone 17" --region id --language id --page 2
mrscraper serp "iphone 17" --format html --render-js
```
A complete Google search URL can also be passed directly:
```bash
mrscraper serp "https://www.google.com/search?q=iphone+17&gl=us&hl=en&start=20"
```
The CLI extracts `q`, `gl`, `hl`, and `start`, converts `start` to a page
number, then sends the normal API body.
#### `serp` parameters
| CLI parameter | Default | API mapping | Behavior |
| ---------------------------- | --------------------- | ------------------------ | ------------------------------------------------------------------------- |
| `` | required | Body `query` | Sends a plain query, or locally derives request fields from a Google URL. |
| `--region ` | omitted | Body `region` | Result country. Explicit CLI input overrides `gl` from a URL. |
| `--language ` | omitted | Body `language` | Result language. Explicit CLI input overrides `hl` from a URL. |
| `--page ` | omitted | Body `page` | 1-based result page. Explicit CLI input overrides URL `start`. |
| `--format ` | `json` | Body `format` | Returns parsed JSON or result-page HTML. |
| `--render-js` | `false` | Body `renderJs=true` | Waits for JavaScript-rendered SERP features. |
| `--raw` | `false` | Sends body `format=html` | Deprecated CLI alias for `--format html`. |
| `--client-timeout ` | `120` | CLI request | Sets the HTTP request deadline. |
| `--token ` | configured credential | Request headers | Overrides authentication for this command. |
### `status`
`status` combines account information into a concise summary. It calls:
```text
GET https://api.app.mrscraper.com/api/v1/subscription-accounts
```
The CLI removes credential and billing identifiers, renames selected fields,
and calculates `token_remaining` and `usage_percent`. Interactive terminals get
a dashboard; redirected output is JSON. Force either mode with `--pretty` or
`--json`.
```bash
mrscraper status
mrscraper status --json
```
The JSON summary includes its source endpoints:
```json
{
"kind": "mrscraper-cli-status-summary",
"source_endpoints": ["/subscription-accounts"],
"status_code": 200,
"data": {
"account": {}
}
}
```
With `--domain`, the CLI makes a second request to `/analytic/statuses`, converts
a URL to its hostname, converts relative dates to the API timestamp format, and
merges the result:
```bash
mrscraper status --domain "https://example.com/products" --from 7d --to now
```
#### `status` parameters
| CLI parameter | Default | API mapping | Behavior |
| --------------------------- | --------------------- | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
| `--domain ` | omitted | Analytics query `domain` | Enables the second analytics request; URLs are locally reduced to hostname. |
| `--from ` | `24h` | Analytics query `startDate` | Accepts ISO time or local durations such as `30m`, `24h`, and `7d`, then formats UTC for the API. Used only with `--domain`. |
| `--to ` | `now` | Analytics query `endDate` | Accepts ISO time or `now`, then formats UTC. Used only with `--domain`. |
| `--action ` | empty string | Analytics query `action` | Optional analytics filter. Used only with `--domain`. |
| `--api-token-name ` | empty string | Analytics query `apiTokenName` | Optional analytics filter. Used only with `--domain`. |
| `--json` | automatic when piped | CLI output | Prints the summary as JSON. |
| `--pretty` | automatic in TTY | CLI output | Prints the terminal dashboard. Cannot be combined with `--json`. |
| `--no-color` | off | CLI output | Disables ANSI color in the dashboard. |
| `--token ` | configured credential | Request headers | Overrides authentication for both requests. |
### `rerun`
Choose the saved scraper and the number of target URLs independently:
* `--type ai` runs an AI scraper created by `mrscraper scrape`.
* `--type manual` runs a step-based workflow created in the MrScraper
dashboard. The CLI reruns existing manual workflows; it does not create them.
* Without `--bulk`, the scraper runs on one URL. With `--bulk`, the same saved
configuration is submitted once with a comma- or newline-separated URL list.
Manual reruns can be single or bulk. Bulk reruns can use either an AI or a
manual scraper; bulk describes the number of targets, not the scraper type.
Bulk mode submits one asynchronous backend job; it does not loop over the
single-URL endpoint locally. Save `data.data.bulkResultId` from the submission
response and retrieve the stored result until it finishes:
```bash
mrscraper result --id BULK_RESULT_UUID
```
`rerun` selects an endpoint based on `--type` and `--bulk`:
| Mode | Endpoint |
| ------------- | ----------------------------------------- |
| Single AI | `POST /api/v1/scrapers-ai-rerun` |
| Bulk AI | `POST /api/v1/scrapers-ai-rerun/bulk` |
| Single manual | `POST /api/v1/scrapers-manual-rerun` |
| Bulk manual | `POST /api/v1/scrapers-manual-rerun/bulk` |
```bash
mrscraper rerun "https://example.com/product" \
--type ai --scraper-id SCRAPER_UUID
mrscraper rerun "https://a.example,https://b.example" \
--bulk --type manual --id SCRAPER_UUID
```
#### `rerun` parameters
| CLI parameter | Default | API mapping | Behavior |
| ---------------------------- | --------------------- | ---------------------- | ----------------------------------------------------------------------------------------------- |
| `` | required | Body `url` or `urls` | One URL for single mode. Bulk mode locally splits comma- or newline-separated URLs into `urls`. |
| `--type ` | required | CLI routing | Selects the AI or manual endpoint. |
| `--bulk` | `false` | CLI routing | Selects the bulk endpoint. |
| `--scraper-id ` | required for single | Body `scraperId` | Single endpoint only. Rejected with `--bulk`. |
| `--id ` | required for bulk | Body `scraperId` | Bulk endpoint only. Rejected for single mode. |
| `--max-depth ` | omitted | Body `maxDepth` | Single AI rerun only. Omit it to preserve the saved scraper/backend default. |
| `--max-pages ` | omitted | Body `maxPages` | Single AI rerun only. Omit it to preserve the saved scraper/backend default. |
| `--limit ` | omitted | Body `limit` | Single AI rerun only. Omit it to preserve the saved scraper/backend default. |
| `--include-patterns ` | omitted | Body `includePatterns` | Single AI rerun only. Omit it to preserve the saved scraper/backend default. |
| `--exclude-patterns ` | omitted | Body `excludePatterns` | Single AI rerun only. Omit it to preserve the saved scraper/backend default. |
| `--proxy-country ` | omitted | Body `proxyCountry` | Single AI rerun only. |
| `--max-retry ` | omitted | Body `maxRetry` | Single AI rerun retry limit; zero is accepted. |
| `--timeout ` | omitted | Body `timeout` | Single AI rerun timeout, used by listing reruns. |
| `--token ` | configured credential | Request headers | Overrides authentication for this command. |
The AI controls apply only to single AI reruns. The CLI sends them only when
provided, so omitted values continue using the saved scraper or backend
defaults.
### `results`
`results` calls `GET /api/v1/results` and maps its filtering options directly to
query parameters:
```bash
mrscraper results --page-size 20 --page 2
mrscraper results --search example.com
mrscraper results \
--scraper-id SCRAPER_UUID \
--status Finished \
--type Rerun-AI \
--url "https://example.com/product"
mrscraper results \
--date-range-column updatedAt \
--start-at "2026-08-01T00:00:00Z" \
--end-at "2026-08-18T00:00:00Z"
```
#### `results` parameters
| CLI parameter | Default | API query field | Behavior |
| ------------------------------ | --------------------- | -------------------- | ---------------------------------------------------------------------- |
| `--sort-field ` | `updatedAt` | `sortField` | Field used to sort results. |
| `--sort-order ` | `desc` | `sortOrder` | CLI accepts case-insensitively and sends uppercase `ASC` or `DESC`. |
| `--page-size ` | `10` | `pageSize` | Positive result page size. |
| `--page ` | `1` | `page` | Positive 1-based page number. |
| `--search ` | omitted | `search` | Search filter. |
| `--scraper-id ` | omitted | `filters[scraperId]` | Exact saved scraper UUID filter. |
| `--status ` | omitted | `filters[status]` | Exact `Draft`, `Finished`, `Running`, `Failed`, or `Cancelled` filter. |
| `--type ` | omitted | `filters[type]` | Exact result type filter, such as `AI` or `Rerun-AI`. |
| `--url ` | omitted | `filters[url]` | Exact stored target URL filter. |
| `--date-range-column ` | omitted | `dateRangeColumn` | Column used with `startAt` and `endAt`. |
| `--start-at ` | omitted | `startAt` | Inclusive range start. |
| `--end-at ` | omitted | `endAt` | Inclusive range end. |
| `--token ` | configured credential | Request headers | Overrides authentication. |
### `result`
`result` calls `GET /api/v1/results/{id}`:
```bash
mrscraper result RESULT_UUID
mrscraper result --id RESULT_UUID
mrscraper result --id RESULT_UUID --no-include-html
```
The positional ID and `--id` are local input alternatives. Stored HTML is
included by default; `--no-include-html` sends `includeHtml=false` for a
smaller response while polling status or when extracted data is sufficient.
`--token` overrides authentication for this command.
# MCP Server
import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';
import { Step, Steps } from "fumadocs-ui/components/steps";
import { CodeBlock } from "fumadocs-ui/components/codeblock";
import {
Activity,
Bot,
Database,
FileSearch,
GlobeLock,
RefreshCcw,
Search,
Server,
} from "lucide-react";
MrScraper MCP connects Model Context Protocol clients to the MrScraper
web-data service. It exposes seven tools:
} href="#fetch">
Fetch page HTML using Web Unblocker with browser rendering and proxy routing.
} href="#scrape">
Extract structured fields, listing records, or site maps with AI agents.
} href="#serp">
Query Google SERP for structured search engine results and page discovery.
} href="#status">
Check subscription status, quota usage, rate limits, and token metrics.
} href="#rerun">
Execute new runs for saved AI or manual scraper configurations.
} href="#results">
Browse, filter, paginate, and search stored MrScraper result collections.
} href="#result">
Retrieve full output data and metadata for a single stored result by ID.
Use the hosted Streamable HTTP endpoint for a managed connection, or run the
published MCP package locally through Streamable HTTP or stdio.
## Capabilities
}>
Fetch a known URL with browser rendering, proxy-country routing, selector
waiting, resource controls, and retry limits.
}>
Extract page fields, repeated listing records, or a site URL map with
agent-specific inputs.
}>
Search Google from a query or a complete Google search URL and select JSON
or HTML output.
}>
Read subscription, quota, token usage, rate limits, and optional domain
request outcomes.
}>
Rerun saved AI or manual scraper configurations for one URL or a bulk URL
list.
}>
Browse, filter, paginate, and retrieve stored MrScraper results.
}>
Connect to the hosted MCP endpoint through Streamable HTTP with OAuth 2.1
browser sign-in.
}>
Receive a consistent response envelope in MCP structured content.
## Requirements
* A [MrScraper account](https://app.mrscraper.com)
* An MCP client with Streamable HTTP support
* An [API key](/docs/getting-started/api-token) only when the client cannot use
OAuth 2.1 or when running the server locally
## Quick start with the hosted server
Add the hosted endpoint
Configure a Streamable HTTP server named `mrscraper` with no credential:
```json
{
"mcpServers": {
"mrscraper": {
"type": "http",
"url": "https://mcp.mrscraper.com/mcp"
}
}
}
```
Use this exact URL, including the `/mcp` path.
Sign in
Connect or reload the MCP server. Your client follows the OAuth 2.1
challenge, opens MrScraper in your browser, and asks you to approve access.
Reload and verify
Reload the client or start a new session, then inspect its MCP tool list.
The connection should expose `fetch`, `scrape`, `serp`, `status`,
`rerun`, `results`, and `result`.
## Copyable AI setup prompt
Connect MrScraper MCP to this agent. Detect the current MCP client and use its native Streamable HTTP setup to add a server named mrscraper at exactly
[https://mcp.mrscraper.com/mcp](https://mcp.mrscraper.com/mcp)
with no static credential. Complete the OAuth 2.1 browser sign-in; if it does not start automatically, use the client's MCP login or authenticate command. Only if the client does not support OAuth, fall back to a MrScraper API key from
[https://app.mrscraper.com/api-tokens](https://app.mrscraper.com/api-tokens)
stored through the client's environment-variable or secret-storage mechanism and sent as Authorization: Bearer . Reload the MCP client when required, then list the tools and confirm that fetch, scrape, serp, status, rerun, results, and result are available.
## Client configuration
Add the hosted URL without a static `Authorization` header, then complete
browser sign-in when the client prompts you.
### Codex
```bash
codex mcp add mrscraper \
--url https://mcp.mrscraper.com/mcp
```
Codex uses OAuth by default for Streamable HTTP servers. If browser sign-in does
not start automatically, run `codex mcp login mrscraper`.
### Claude Code
```bash
claude mcp add \
--transport http \
--scope user \
mrscraper https://mcp.mrscraper.com/mcp
```
Open `/mcp` inside Claude Code and authenticate, or run
`claude mcp login mrscraper` from your shell.
### Claude and Claude Desktop
Open the custom connector form
In a general Claude chat, select the **+** button below the input box, then
choose **Connectors → Add connector → Add custom connector**.
Add MrScraper
Enter `MrScraper` as the name and
`https://mcp.mrscraper.com/mcp` as the MCP server URL, then select
**Continue**.
Sign in
Complete the MrScraper OAuth browser flow when Claude prompts you.
### Cursor
Open **Cursor Settings → Tools & MCP → Add Custom MCP**, then add:
```json
{
"mcpServers": {
"mrscraper": {
"type": "http",
"url": "https://mcp.mrscraper.com/mcp"
}
}
}
```
Refresh the MCP server list, then authenticate when prompted.
### VS Code
Add the server to your user settings:
```json
{
"mcp": {
"servers": {
"mrscraper": {
"type": "http",
"url": "https://mcp.mrscraper.com/mcp"
}
}
}
}
```
For a workspace configuration, place the server object under `servers` in
`.vscode/mcp.json`. Start the server and VS Code opens a browser for OAuth.
### Windsurf
Add the following entry to the Windsurf MCP configuration:
```json
{
"mcpServers": {
"mrscraper": {
"serverUrl": "https://mcp.mrscraper.com/mcp"
}
}
}
```
Refresh the MCP server list, then complete OAuth when prompted.
### Other MCP clients
Use these connection values:
| Setting | Value |
| -------------- | ------------------------------------------- |
| Name | `mrscraper` |
| Transport | Streamable HTTP |
| URL | `https://mcp.mrscraper.com/mcp` |
| Authentication | OAuth 2.1; do not configure a static header |
## API key fallback
If a client cannot complete OAuth, create an [API key](https://app.mrscraper.com/api-tokens),
store it through the client's secret mechanism, and send it as a bearer token:
```json
{
"mcpServers": {
"mrscraper": {
"type": "http",
"url": "https://mcp.mrscraper.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_MRSCRAPER_API_KEY"
}
}
}
}
```
For Codex, pass the environment-variable name instead of embedding the key:
```bash
export MRSCRAPER_API_KEY="YOUR_MRSCRAPER_API_KEY"
codex mcp add mrscraper \
--url https://mcp.mrscraper.com/mcp \
--bearer-token-env-var MRSCRAPER_API_KEY
```
## Authentication
| Connection | Credential source |
| --------------------------- | ------------------------------------------------- |
| Hosted Streamable HTTP | OAuth 2.1 browser sign-in, or an API key fallback |
| Self-hosted Streamable HTTP | `Authorization: Bearer ` |
| Local stdio | `MRSCRAPER_API_KEY`, then `MRSCRAPER_API_TOKEN` |
The hosted server publishes OAuth 2.1 protected-resource metadata and challenges
unauthenticated clients to start browser sign-in. Access tokens are issued for
the exact `https://mcp.mrscraper.com/mcp` resource and use `scrape:read`,
`scrape:write`, and `account:read` scopes. A tool called without its required
scope returns `403 insufficient_scope`.
API keys remain supported for clients without OAuth and carry full account
authority. Authentication stays at the transport layer; tools never accept
credentials as arguments.
## Run the MCP server locally
Node.js 20 or newer is required.
### Published package over stdio
```json
{
"mcpServers": {
"mrscraper": {
"command": "npx",
"args": ["-y", "@mrscraper/mcp@latest"],
"env": {
"MRSCRAPER_API_KEY": "YOUR_MRSCRAPER_API_KEY"
}
}
}
}
```
### Source checkout over Streamable HTTP
Clone and build
```bash
git clone https://github.com/mrscraper-com/mrscraper-mcp.git
cd mrscraper-mcp
npm ci
npm run build
```
Start HTTP transport
```bash
TRANSPORT=http npm start
```
The default endpoint is `http://127.0.0.1:8000/mcp`.
Connect the client
```json
{
"mcpServers": {
"mrscraper": {
"type": "http",
"url": "http://127.0.0.1:8000/mcp",
"headers": {
"Authorization": "Bearer YOUR_MRSCRAPER_API_KEY"
}
}
}
}
```
### Docker
```bash
docker build -f docker/Dockerfile -t mrscraper-mcp .
docker run --rm -p 8000:8000 mrscraper-mcp
```
The image binds to \`0.0.0.0). Apply network controls appropriate for the
deployment and keep bearer verification enabled.
## Environment variables
| Variable | Default | Purpose |
| -------------------------------- | --------------------------------- | ---------------------------------------------------------------- |
| `TRANSPORT` | `stdio` | Selects `stdio` or `http`. |
| `HOST` | `127.0.0.1` | HTTP bind address; the Docker image uses `0.0.0.0`. |
| `PORT` | `8000` | HTTP listen port. |
| `MRSCRAPER_API_KEY` | — | Primary stdio credential. |
| `MRSCRAPER_API_TOKEN` | — | Legacy stdio credential alias. |
| `MRSCRAPER_HTTP_AUTH` | `1` | Enables HTTP bearer verification. |
| `MRSCRAPER_ALLOWED_ORIGINS` | — | Comma-separated browser origins allowed to call the HTTP server. |
| `MRSCRAPER_API_BASE_URL` | MrScraper platform API | Platform endpoint override for development and testing. |
| `MRSCRAPER_FETCH_BASE_URL` | MrScraper Web Unblocker | Fetch endpoint override. |
| `MRSCRAPER_SYNC_BASE_URL` | MrScraper synchronous scraper API | SERP endpoint override. |
| `MRSCRAPER_LOG_HTTP_PAYLOAD` | off | Enables trusted-environment request-body diagnostics. |
| `MRSCRAPER_LOG_HTTP_PAYLOAD_MAX` | `8192` | Maximum diagnostic payload length. |
## Security behavior
* HTTP authentication is enabled by default.
* Credential-bearing response headers are filtered from tool output.
* Parsed JSON credential metadata and credentials in generated curl commands
are redacted.
* Extracted scraper values remain available in the response's `data` field.
* Browser-origin requests are accepted from trusted local origins and exact
values configured through `MRSCRAPER_ALLOWED_ORIGINS`.
* Tool calls receive the caller's authenticated OAuth token or API key through
the MCP transport rather than through tool arguments.
## Choosing the right tool
| Starting point | Desired outcome | Tool |
| ------------------- | ---------------------------------- | ------------------------------------ |
| A known URL | Page response from Web Unblocker | `fetch` |
| A known URL | Defined fields or repeated records | `scrape` with `general` or `listing` |
| A site root | A bounded URL map | `scrape` with `map` |
| A topic or keyword | Google result discovery | `serp` |
| A saved scraper ID | A new scraper run | `rerun` |
| An account | Usage and quota details | `status` |
| A result collection | Pagination, filtering, and search | `results` |
| A result ID | One complete stored result | `result` |
A discovery workflow commonly uses `serp` first, followed by `fetch` for
the page response or `scrape` for defined output fields. A saved-scraper
workflow commonly uses `scrape`, then `rerun`, followed by `result`.
## Common response envelope
API-backed tools return the same envelope through MCP `structuredContent` and
a formatted JSON text block:
```json
{
"status_code": 200,
"data": {},
"headers": {
"content-type": "application/json"
}
}
```
| Field | Type | Description |
| ------------- | ----------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `status_code` | number or `null` | HTTP status returned by the MrScraper service, or `null` when the request ends before an HTTP response arrives. |
| `data` | JSON value, string, or `null` | Parsed JSON or response text supplied by the service. |
| `headers` | object | Response headers with credential-bearing headers filtered out. |
| `error` | string, when present | Request failure summary. |
API failures preserve the envelope in `structuredContent` and set the MCP
result's `isError` flag. Input-contract errors are returned as MCP tool
errors. This lets clients inspect status, response data, and safe headers while
also following the standard MCP error signal.
## Tool reference
### `fetch`
Use `fetch` for a known URL when you need the page response from MrScraper
[Web Unblocker](/docs/features/unblocker). Each invocation corresponds to one
request:
```text
GET https://api.mrscraper.com/
```
#### Basic request
```json
{
"url": "https://example.com/products"
}
```
`browser_rendering` and `super_mode` are independent controls. All four
combinations can return different results for the same URL:
| Browser rendering | Super Mode | Input | Loading path |
| ----------------- | ---------- | ----------------------------------------------------------------- | -------------------------------------------------------- |
| Off | Off | `{ "url": "URL" }` | Standard routing with the non-browser loader. |
| On | Off | `{ "url": "URL", "browser_rendering": true }` | Standard routing with browser loading and JavaScript. |
| Off | On | `{ "url": "URL", "super_mode": true }` | Real-device routing with the non-browser loader. |
| On | On | `{ "url": "URL", "browser_rendering": true, "super_mode": true }` | Real-device routing with browser loading and JavaScript. |
Start with both controls off, inspect the response, and change one axis at a
time. Browser rendering is not guaranteed to produce a better response: some
sites fail with it enabled but load without it. Try remaining untested
combinations without repeating an identical failed request.
#### JavaScript-rendered page
```json
{
"url": "https://example.com/products",
"browser_rendering": true,
"wait_for_selector": ".product-card",
"timeout": 45
}
```
#### Real-device Super Mode
Use both controls for real-device browser loading:
```json
{
"url": "https://example.com/products",
"browser_rendering": true,
"super_mode": true
}
```
#### Geo-sensitive page
```json
{
"url": "https://example.com/offers",
"browser_rendering": true,
"geo_code": "ID",
"home_page": true,
"block_resources": true,
"max_retries": 3,
"token_cap": 20
}
```
#### Parameters
| Parameter | Required | Default | API query field | Description |
| ------------------- | -------- | ------- | ------------------ | ----------------------------------------------------------------------------------------------------- |
| `url` | Yes | — | `url` | Target page URL. |
| `browser_rendering` | No | `false` | `browserRendering` | Loads the page in a browser and executes JavaScript. |
| `super_mode` | No | `false` | `super` | Selects real-device routing independently of browser rendering. |
| `geo_code` | No | omitted | `geoCode` | Selects proxy-country routing. |
| `wait_for_selector` | No | omitted | `waitForSelector` | Waits for a CSS selector together with `browser_rendering: true`. |
| `home_page` | No | `false` | `homePage` | Visits the site root before loading the target URL. |
| `block_resources` | No | `false` | `blockResources` | Applies resource blocking during page loading. |
| `max_retries` | No | `3` | `maxRetries` | Sets the retry limit; zero is accepted. |
| `token_cap` | No | omitted | `tokenCap` | Sets the retry token budget. |
| `timeout` | No | `30` | `timeout` | Sets the page-load deadline in seconds. The MCP server allows an additional 30 seconds for transport. |
The response body is available in the envelope's `data` field, commonly as
HTML. Use browser rendering when JavaScript is needed, but retry the same
`super_mode` value without it when browser loading fails, is blocked, or returns
worse content. Toggle `super_mode` independently when routing may be the
problem. A selector wait still requires browser rendering.
### `scrape`
Use `scrape` when you need defined fields, repeated records, or a site URL
map. It calls:
```text
POST https://api.app.mrscraper.com/api/v1/scrapers-ai
```
#### Agent modes
| Agent | Designed for | Inputs |
| --------- | ------------------------------------- | ------------------------------------------------------------------------- |
| `general` | Defined fields from one page | `prompt`, `schema_prompt`, `proxy_country` |
| `listing` | Repeated records across listing pages | `prompt`, `schema_prompt`, `proxy_country`, `max_pages` |
| `map` | Bounded URL discovery across a site | `max_depth`, `max_pages`, `limit`, `include_patterns`, `exclude_patterns` |
Choose inputs from the selected agent's row. The default agent is `general`.
The separate `mode` input selects the `Cheap` or `Super` backend execution
tier. Omit it to preserve the backend default.
#### General extraction
```json
{
"url": "https://example.com/product",
"agent": "general",
"mode": "Super",
"prompt": "Extract the product name, price, availability, description, and image URLs",
"proxy_country": "US"
}
```
The request body includes `url`, `message`, and `agent`, plus
`proxyCountry` when supplied.
#### Listing extraction
```json
{
"url": "https://example.com/products",
"agent": "listing",
"prompt": "Extract every product name, price, availability, and detail URL",
"max_pages": 5
}
```
Listing requests are synchronous. Use `max_pages` to define the desired page
scope. When it is omitted, the service applies its configured default.
#### Site map
```json
{
"url": "https://example.com",
"agent": "map",
"max_depth": 2,
"max_pages": 50,
"limit": 1000,
"include_patterns": "/products/",
"exclude_patterns": "/cart/|/checkout/"
}
```
Map requests send `url`, `agent`, and the crawl controls supplied in the
tool call. Omitted crawl controls use service defaults.
#### Best-effort schema guidance
```json
{
"url": "https://example.com/product",
"prompt": "Extract the product",
"schema_prompt": {
"type": "object",
"properties": {
"name": { "type": "string" },
"price": { "type": "number" },
"in_stock": { "type": "boolean" }
},
"required": ["name", "price"]
}
}
```
The MCP server appends `schema_prompt` to the natural-language instruction as
shape guidance. Validate the returned value in the consuming application when
strict conformance is required.
#### Parameters
| Parameter | Required | Default | Request mapping | Description |
| ------------------ | --------------- | --------------- | ---------------------- | ---------------------------------------------------------------- |
| `url` | Yes | — | Body `url` | Target URL for every agent. |
| `prompt` | General/listing | — | Body `message` | Natural-language extraction instruction. |
| `schema_prompt` | No | omitted | Appended to `message` | Best-effort JSON Schema shape guidance for general/listing. |
| `agent` | No | `general` | Body `agent` | Selects `general`, `listing`, or `map`. |
| `mode` | No | service default | Body `mode` | Selects `Cheap` or `Super` execution independently of the agent. |
| `proxy_country` | No | omitted | Body `proxyCountry` | Proxy country for general/listing. |
| `max_pages` | No | service default | Body `maxPages` | Page bound for listing/map. |
| `max_depth` | No | service default | Body `maxDepth` | Link-depth bound for map. |
| `limit` | No | service default | Body `limit` | URL-result bound for map. |
| `include_patterns` | No | service default | Body `includePatterns` | URL inclusion expression for map. |
| `exclude_patterns` | No | service default | Body `excludePatterns` | URL exclusion expression for map. |
#### Reproduce a scrape with `rerun`
Every successful `scrape` creates a saved AI scraper configuration by default.
The response run object contains `scraperId`. Pass that UUID to `rerun` as
`scraper_id` to apply the same saved prompt and agent configuration to the
original URL or another URL:
```json
{
"target": "https://example.com/product-2",
"type": "ai",
"scraper_id": "scraper-uuid"
}
```
This makes the scraper configuration reproducible, but page changes and model
behavior can still change the extracted values.
`rerun` also supports dashboard-built manual workflows and asynchronous bulk
jobs across multiple target URLs. See the full [`rerun`](#rerun) section below
for the available modes and result-tracking workflow.
### `serp`
Use `serp` when discovery starts from a Google query or Google search URL. It
calls:
```text
POST https://sync.scraper.mrscraper.com/api/google/serp/v2/sync
```
#### Search query
```json
{
"query_or_url": "iphone 17",
"region": "id",
"language": "id",
"page": 2,
"format": "json",
"render_js": false
}
```
#### Google search URL
```json
{
"query_or_url": "https://www.google.com/search?q=iphone+17&gl=us&hl=en&start=20"
}
```
For a Google URL, the server derives:
| URL parameter | Tool request field |
| ------------- | ------------------------------------------- |
| `q` | `query` |
| `gl` | `region` |
| `hl` | `language` |
| `start` | One-based `page` using groups of 10 results |
Explicit `region`, `language`, and `page` inputs take priority over the
corresponding URL values.
#### Parameters
| Parameter | Required | Default | Request mapping | Description |
| ---------------- | -------- | -------------------- | ---------------------- | ---------------------------------------------------------------- |
| `query_or_url` | Yes | — | Body `query` | Search query or complete Google search URL. |
| `region` | No | URL value or omitted | Body `region` | Result country code. |
| `language` | No | URL value or omitted | Body `language` | Result language code. |
| `page` | No | URL value or omitted | Body `page` | One-based result page. |
| `format` | No | `json` | Body `format` | Selects parsed JSON or result-page HTML. |
| `render_js` | No | `false` | Body `renderJs` | Waits for JavaScript-rendered SERP features such as AI Overview. |
| `raw` | No | `false` | Body `format=html` | Compatibility alias for HTML output. |
| `client_timeout` | No | `120` | Local request deadline | Sets the upstream HTTP timeout in seconds. |
### `status`
Use `status` for account information and optional domain request outcomes.
Every call reads:
```text
GET https://api.app.mrscraper.com/api/v1/subscription-accounts
```
Supplying `domain` adds:
```text
GET https://api.app.mrscraper.com/api/v1/analytic/statuses
```
#### Account status
```json
{}
```
#### Domain analytics
```json
{
"domain": "https://www.example.com/products",
"from": "7d",
"to": "now",
"action": "fetch",
"api_token_name": "production"
}
```
The domain input accepts a hostname or a URL. URLs are normalized to their
hostname before the analytics request.
#### Date syntax
| Syntax | Example | Meaning |
| ------------ | ---------------------- | ------------------------------------ |
| Minutes | `30m` | 30 minutes before the reference time |
| Hours | `24h` | 24 hours before the reference time |
| Days | `7d` | 7 days before the reference time |
| Weeks | `2w` | 2 weeks before the reference time |
| Current time | `now` | Current reference time |
| ISO 8601 | `2026-08-18T12:00:00Z` | Exact timestamp |
#### Parameters
| Parameter | Required | Default | Description |
| ---------------- | -------- | ------------ | ----------------------------------------------------- |
| `domain` | No | omitted | Adds request-outcome analytics for a hostname or URL. |
| `from` | No | `24h` | Analytics range start. |
| `to` | No | `now` | Analytics range end. |
| `action` | No | empty filter | Filters analytics by exact action. |
| `api_token_name` | No | empty filter | Filters analytics by API-token name. |
#### Status summary
```json
{
"kind": "mrscraper-cli-status-summary",
"source_endpoints": [
"/subscription-accounts",
"/analytic/statuses"
],
"status_code": 200,
"data": {
"account": {
"subscription_status": "active",
"enterprise": false,
"token_usage": 250,
"token_limit": 1000,
"token_remaining": 750,
"usage_percent": 25,
"rate_limit": 10,
"rate_ttl": 60,
"auto_renew": true,
"ends_at": null,
"user": {
"name": "Ada",
"email": "ada@example.com",
"verified": true
}
},
"analytics": {
"domain": "www.example.com",
"from": "2026-08-11 12:00:00 UTC",
"to": "2026-08-18 12:00:00 UTC"
}
}
}
```
The summary selects account fields, calculates `token_remaining` and
`usage_percent`, and records every source endpoint used for the response.
When domain analytics encounter an API failure, the account summary remains in
`data.account` and the analytics response is available in `data.analytics`.
### `rerun`
Use `rerun` with the UUID of an existing scraper. Choose its type and target
count independently:
* Set `type` to `ai` for an AI scraper created by the `scrape` tool.
* Set `type` to `manual` for a step-based workflow created in the MrScraper
dashboard. MCP reruns existing manual workflows; it does not create them.
* Leave `bulk` as `false` for one URL. Set it to `true` to submit the same saved
configuration once with a comma- or newline-separated URL list.
Manual reruns can be single or bulk. Bulk reruns can use either an AI or a
manual scraper; bulk describes the number of targets, not the scraper type.
Bulk mode submits one asynchronous backend job instead of repeating the
single-URL tool call locally. Save `data.data.bulkResultId` from the response
and pass it to `result` as `result_id` until the stored result is finished.
The combination of `type` and `bulk` selects one endpoint:
| Mode | Endpoint | ID parameter | Target | Crawl controls |
| ------------- | ---------------------------------- | ------------ | ---------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| Single AI | `POST /scrapers-ai-rerun` | `scraper_id` | One URL | `max_depth`, `max_pages`, `limit`, `include_patterns`, `exclude_patterns`, `proxy_country`, `max_retry`, `timeout` |
| Bulk AI | `POST /scrapers-ai-rerun/bulk` | `id` | Comma/newline-separated URLs | Saved scraper configuration |
| Single manual | `POST /scrapers-manual-rerun` | `scraper_id` | One URL | Saved scraper configuration |
| Bulk manual | `POST /scrapers-manual-rerun/bulk` | `id` | Comma/newline-separated URLs | Saved scraper configuration |
The endpoint paths above use the platform API base:
```text
https://api.app.mrscraper.com/api/v1
```
#### Single AI rerun
```json
{
"target": "https://example.com/products",
"type": "ai",
"scraper_id": "scraper-uuid",
"max_depth": 2,
"max_pages": 50,
"limit": 1000,
"include_patterns": "/products/",
"exclude_patterns": "/cart/|/checkout/",
"proxy_country": "ID",
"max_retry": 4,
"timeout": 120
}
```
#### Single manual rerun
```json
{
"target": "https://example.com/product/123",
"type": "manual",
"scraper_id": "scraper-uuid"
}
```
#### Bulk AI rerun
```json
{
"target": "https://example.com/a,https://example.com/b\nhttps://example.com/c",
"type": "ai",
"bulk": true,
"id": "scraper-uuid"
}
```
The bulk target parser separates URLs on commas and newlines.
#### Parameters
| Parameter | Required | Default | Description |
| ------------------ | ----------- | ------- | ------------------------------------------------------------------------------- |
| `target` | Yes | — | One URL, or a comma/newline-separated URL string for bulk mode. |
| `type` | Yes | — | Selects `ai` or `manual`. |
| `bulk` | No | `false` | Selects a bulk endpoint. |
| `scraper_id` | Single mode | — | Saved scraper UUID for one target URL. |
| `id` | Bulk mode | — | Saved scraper UUID for the bulk target list. |
| `max_depth` | Single AI | omitted | Crawl depth; omission preserves the saved scraper/backend default. |
| `max_pages` | Single AI | omitted | Page bound; omission preserves the saved scraper/backend default. |
| `limit` | Single AI | omitted | Result bound; omission preserves the saved scraper/backend default. |
| `include_patterns` | Single AI | omitted | URL inclusion expression; omission preserves the saved scraper/backend default. |
| `exclude_patterns` | Single AI | omitted | URL exclusion expression; omission preserves the saved scraper/backend default. |
| `proxy_country` | Single AI | omitted | Proxy country code. |
| `max_retry` | Single AI | omitted | Retry limit; zero is accepted. |
| `timeout` | Single AI | omitted | Timeout in seconds, used by listing reruns. |
The MCP server sends single-AI controls only when supplied. Manual and bulk
reruns reject them.
Manual reruns carry a compliance acknowledgment in the MCP server
instructions. MCP clients should present that acknowledgment before executing
a manual rerun.
### `results`
Use `results` to browse stored runs through:
```text
GET https://api.app.mrscraper.com/api/v1/results
```
#### Paginated request
```json
{
"sort_field": "updatedAt",
"sort_order": "desc",
"page_size": 25,
"page": 1
}
```
#### Filtered request
```json
{
"sort_field": "updatedAt",
"sort_order": "asc",
"page_size": 50,
"page": 1,
"search": "example.com",
"scraper_id": "scraper-uuid",
"status": "Finished",
"type": "Rerun-AI",
"url": "https://example.com/product",
"date_range_column": "updatedAt",
"start_at": "2026-08-01T00:00:00Z",
"end_at": "2026-08-18T23:59:59Z"
}
```
#### Parameters
| Parameter | Required | Default | API query field | Description |
| ------------------- | -------- | ----------- | -------------------- | ---------------------------------------------------------------------- |
| `sort_field` | No | `updatedAt` | `sortField` | Field used by the results API for sorting. |
| `sort_order` | No | `desc` | `sortOrder` | Case-insensitive `asc` or `desc`; sent to the API in uppercase. |
| `page_size` | No | `10` | `pageSize` | Number of rows per page. |
| `page` | No | `1` | `page` | One-based page index. |
| `search` | No | omitted | `search` | Free-text result filter. |
| `scraper_id` | No | omitted | `filters[scraperId]` | Exact saved scraper UUID filter. |
| `status` | No | omitted | `filters[status]` | Exact `Draft`, `Finished`, `Running`, `Failed`, or `Cancelled` filter. |
| `type` | No | omitted | `filters[type]` | Exact result type filter, such as `AI` or `Rerun-AI`. |
| `url` | No | omitted | `filters[url]` | Exact stored target URL filter. |
| `date_range_column` | No | omitted | `dateRangeColumn` | Column used for the date range. |
| `start_at` | No | omitted | `startAt` | Inclusive range start. |
| `end_at` | No | omitted | `endAt` | Inclusive range end. |
The results API receives the `sort_field` value supplied by the caller.
`sort_order` is normalized and sent as `ASC` or `DESC`.
### `result`
Use `result` when the result UUID is already known:
```text
GET https://api.app.mrscraper.com/api/v1/results/{result_id}
```
```json
{
"result_id": "result-uuid",
"include_html": false
}
```
| Parameter | Required | Default | Description |
| -------------- | -------- | ------- | ----------------------------------------------------------------------------------- |
| `result_id` | Yes | — | Stored MrScraper result UUID. |
| `include_html` | No | `true` | Includes stored HTML. Set `false` for a smaller polling or extracted-data response. |
## Troubleshooting
The MCP server may not have loaded correctly.
1. Reload the MCP client or start a new session.
2. Inspect `tools/list`.
3. Confirm that the server advertises these tools: `fetch`, `scrape`, `serp`, `status`, `rerun`, `results`, and `result`.
The MCP connection is not signed in or is using an invalid API key.
1. For hosted OAuth connections, reconnect so the client starts browser sign-in again.
2. For HTTP API-key connections, confirm that the request includes `Authorization: Bearer `.
3. For stdio connections, confirm that `MRSCRAPER_API_KEY` or `MRSCRAPER_API_TOKEN` is available in the launched server environment.
The client's browser origin is not included in the server's allowed origins.
1. Add the client's exact browser origin to `MRSCRAPER_ALLOWED_ORIGINS`.
2. Restart the MCP server if required.
3. Run the request again.
Command-line and service-to-service MCP clients typically connect without an `Origin` header.
The tool call may not match the parameters supported by the selected operation.
1. Check the tool's parameter table.
2. For `scrape`, use only the inputs listed for the selected agent.
3. For `rerun`, use the ID and crawl controls listed for the selected single or bulk mode.
4. Run the request again with the corrected parameters.
The upstream service may need more time to complete the request.
1. Increase `fetch.timeout` to allow more time for a Web Unblocker request.
2. If the timeout occurs during a Google request, increase `serp.client_timeout`.
3. Run the request again after updating the appropriate timeout.
Use the following command to verify that a local HTTP MCP server is responding correctly:
```bash
npm run test:mcp -- \
--target http://127.0.0.1:8000/mcp \
--token "$MRSCRAPER_API_KEY"
```
For package development, run the following checks:
```bash
npm run format:check
npm run lint
npm test
npm run build
npm pack --dry-run
```
# Overview
import { Bot, BotMessageSquare, TextSearch, Workflow, ShoppingCart, Briefcase, Star, SlidersHorizontal, Mail, Database, Webhook, ClipboardClock, Network, Layers, Map, Home, Plane, DollarSign, Store, Code2, Rocket, FlaskConical, Key, Terminal, Server, ShieldCheck, Waypoints, Users, Cookie, ChartLine, SatelliteDish, HeartPulse, Zap, PackageOpen, Package2, Link2, PanelTop, Globe } from 'lucide-react';
Discover how our powerful scraping platform can transform the way you extract data. Whether you're scraping e-commerce product data, collecting job listings, gathering customer reviews for sentiment analysis, or extracting any website content, our AI-powered and manual scrapers are designed to automate and simplify the process, giving you a powerful edge in any project.
## Start Here
New to MrScraper? These pages get you from sign-up to your first scraped dataset.
} href="/docs/getting-started/quickstart">
Run your first scraper in a few minutes with a step-by-step walkthrough.
} href="/docs/getting-started/playground">
Test API requests, explore features, and generate code without writing code.
} href="/docs/getting-started/api-token">
Learn how tokens work and create an API token for authentication.
} href="/docs/getting-started/billing">
Understand subscription plans, token usage, and billing cycles.
## AI Agents
Pick the agent that matches the page you're scraping, or chain several together.
} href="/docs/features/ai-scraper">
Automatically extract data with natural language instructions — no coding required.
} href="/docs/features/ai-scraper/general">
Extract structured data from a single web page using a natural language prompt.
} href="/docs/features/ai-scraper/listing">
Scrape listing pages with automated pagination, infinite scroll, and load-more handling.
} href="/docs/features/ai-scraper/map">
Discover and extract every URL from a website to understand its structure.
} href="/docs/features/ai-scraper/pdp">
Scrape product detail pages faster and cheaper using cached sources.
} href="/docs/features/ai-scraper/multi-agent-flow">
Combine Map, Listing, and General agents into end-to-end extraction workflows.
## Features
Explore MrScraper's key features and tools designed to make data extraction effortless.
} href="/docs/features/manual-scraper">
Build and customize your own scraper workflow step by step for full control.
} href="/docs/features/manual-scraper/self-healing">
Let AI generate, repair, and extend Manual Scraper workflows when a site changes.
} href="/docs/features/bulk-scraping">
Scrape multiple URLs in one go by uploading a list or Excel file.
} href="/docs/features/unblocker">
Bypass anti-scraping measures and reach geo-restricted content.
} href="/docs/features/proxy">
Route individual scrapers through proxies to mask your IP and improve reliability.
} href="/docs/features/cookie">
Use your own cookies to access content behind logins and restrictions.
} href="/docs/features/schedule">
Automate scraper runs on a schedule to keep your data fresh and up to date.
} href="/docs/features/marketplace">
Use ready-to-run scrapers for popular websites and common scraping use cases.
} href="/docs/features/activating-api">
Activate a scraper as an API endpoint and run it programmatically.
} href="/docs/features/s3-storage">
Save scraped data straight into your own S3 bucket.
} href="/docs/features/analytics">
Monitor performance metrics, token usage, and the health of your scraping operations.
} href="/docs/features/team">
Create a team to share scrapers and collaborate on projects.
## Use Cases
Discover how MrScraper can support different real-world scenarios.
} href="/docs/guides/ecommerce">
Scrape product details, pricing, and availability from major e-commerce sites.
} href="/docs/guides/job-listing">
Collect job postings and company data for recruitment or market analysis.
} href="/docs/guides/sentiment-analysis">
Extract and analyze customer feedback to gain insights into sentiment and satisfaction.
} href="/docs/guides/real-estate">
Gather property listings, prices, and market trends from real estate websites.
} href="/docs/guides/travel-hospitality">
Scrape flight prices, airlines, and schedules for price monitoring and booking analysis.
} href="/docs/guides/optimizing-cost">
Minimize token usage and maximize scraping efficiency without losing accuracy.
} href="/docs/guides/programmatically">
Create an AI scraper once, then run it from your own code via the API.
## Integrations
Integrate MrScraper with your favorite tools to automate your data flow.
} href="/docs/integrations/email">
Receive email notifications whenever a scraper finishes or encounters an error.
} href="/docs/integrations/sql">
Automatically store scraped data in your database for querying and analysis.
} href="/docs/integrations/webhook">
Send scraper results directly to external services through webhooks.
} href="/docs/integrations/zapier">
Connect your scrapers to thousands of apps with no-code Zapier automations.
} href="/docs/integrations/n8n">
Build automated workflows around your scrapers with the MrScraper n8n node.
} href="/docs/integrations/apify">
Run MrScraper as Apify Actors and pipe results into the Apify platform.
} href="/docs/integrations/clawhub">
Install the MrScraper skill to give your OpenClaw agent unblockable web scraping.
## Developer Tools
Work with MrScraper from your terminal, your codebase, or your AI agent.
} href="/docs/getting-started/cli">
Scrape, crawl, and extract data from the web directly from your terminal.
} href="/docs/getting-started/mcp-server">
Let AI agents fetch and extract web data through the Model Context Protocol.
} href="/docs/integrations/python">
Call the MrScraper API asynchronously with the `mrscraper-sdk` package.
} href="/docs/integrations/node">
Scrape, crawl, and extract structured data using the MrScraper Node SDK.
} href="/docs/integrations/langchain">
Use MrScraper as LangChain tools inside your own agents.
} href="/docs/api/overview">
Explore every endpoint, authentication, pagination, and error handling.
## Residential Proxy
Route your own tools and browsers through our proxy network.
} href="/docs/residential-proxy/getting-started/overview">
Understand proxy types, global coverage, and how to get started.
} href="/docs/residential-proxy/configuration/authentication">
Configure username patterns, sessions, and country targeting.
} href="/docs/residential-proxy/examples/overview">
Ready-to-use snippets for Python, Node.js, Go, PHP, Playwright, and more.
# Quickstart
import { Play } from 'lucide-react';
This guide shows you how to make your first scraping request with MrScraper.
## Make Your First API Request
Create a MrScraper account and obtain your API key from the [Playground](https://app.mrscraper.com/playground) before following this guide.
In this quickstart, you'll scrape a Walmart product page using the General AI Agent to get the following data:
* Product name
* Price
* Rating
* Number of reviews
* Product link
cURL
```shell
curl --location --request POST 'https://api.mrscraper.com?token=&html=true&super=true' \
-H 'x-api-token: ' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://www.walmart.com/ip/IdeaPad-Slim-3x-15-Laptop-Snapdragon-X-X1-26-100-16GB-RAM-512GB-SSD-Luna-Grey/19075520026",
"prompt": "Extract the following information in JSON format:\n\nproduct_name\nprice\nrating\nnumber_of_reviews\nproduct_link",
"agent": "general"
}'
```
} href="https://app.mrscraper.com/playground">
Run this request instantly without writing any code.
The response contains the extracted data from the page.
JSON
```json
{
"success": true,
"data": {
"product_name": "Lenovo IdeaPad Slim 3x 15.3\" Laptop AI Snapdragon X 16GB 512GB SSD Luna Grey",
"price": 449,
"rating": 4.5,
"number_of_reviews": 103,
"product_link": "https://www.walmart.com/ip/IdeaPad-Slim-3x-15-Laptop-Snapdragon-X-X1-26-100-16GB-RAM-512GB-SSD-Luna-Grey/19075520026"
},
"thread_id": "cebfaa37-f6de-45e7-8dd4-ec955824d81b",
"token_usage": 16,
"markdown": "",
"screenshot": "",
"status": "Converting data to JSON",
"error": "",
"runtime": 14852
}
```
## Use a Predefined Marketplace API
MrScraper also provides ready-to-use scraping APIs through the [Marketplace](/docs/features/marketplace).
These APIs are designed for specific industries and websites. You do not need to create prompts or extraction logic yourself.
Available categories include:
* E-commerce
* News
* Real Estate
* Travel
* And more
} href="https://app.mrscraper.com/marketplace?page=1&pageSize=12">
Browse and test ready-to-use scrapers.
For example, you can use the [Amazon Product Details API](https://app.mrscraper.com/marketplace/d08bcc7c-fa99-4886-9db2-3c274a9a1c2d) to extract product information from an Amazon product page.
```shell
curl --location --request POST 'https://sync.scraper.mrscraper.com/api/amazon/pdp/sync' \
-H 'Authorization: bearer ' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://www.amazon.com/STANLEY-Flowstate-3-Position-Compatible-Insulated/dp/B0CP9YB3Q4/ref=zg_bs_c_kitchen_d_sccl_2/145-6361404-7555432?pd_rd_w=3BPkW&content-id=amzn1.sym.fef9af56-6177-46e9-8710-a5293a68dd39&pf_rd_p=fef9af56-6177-46e9-8710-a5293a68dd39&pf_rd_r=E598BMWHB9QEZ75X7ABP&pd_rd_wg=Z9psI&pd_rd_r=7e3be220-af38-4e7b-b45c-9a68470a3e1f&pd_rd_i=B0CP9YB3Q4&th=1"
}'
```
The response contains the extracted data from the page.
JSON
```json
{
"success": true,
"message": "Successfully scraped",
"data": [
{
"pageNumber": 1,
"payload": {
"templates": [],
"mods": {
"filter": {
"tItemType": "nt_filter",
"filterItems": [
{
"name": "category",
"unfoldRow": "2",
"title": "Category",
"urlKey": "category",
"hidden": false,
"locked": false,
"type": "category",
"uniqueName": "category",
"value": "",
"displayValue": "",
"options": [
{
"url": "/beli-sabun-pembersih-wajah/?q=159947433",
"title": "Facial Cleanser",
"value": "beli-sabun-pembersih-wajah"
}
]
},
{
"name": "brand",
"unfoldRow": "-1",
"title": "Brand",
"urlKey": "ppath",
"hidden": false,
"locked": false,
"type": "brand",
"uniqueName": "20000",
"options": [
{
"title": "Men's Biore",
"value": "men-s-biore"
}
]
},
{
"name": "service",
"unfoldRow": "4",
"title": "Service & Promotion",
"urlKey": "service",
"hidden": false,
"locked": false,
"type": "multiple",
"uniqueName": "service",
"options": [
{
"title": "Fulfilled By Lazada",
"value": "FBL",
"activeIcon": "",
"normalIcon": ""
},
{
"title": "Cash On Delivery",
"value": "COD",
"activeIcon": "",
"normalIcon": ""
},
{
"title": "Coins",
"value": "coins",
"activeIcon": "",
"normalIcon": ""
},
{
"title": "6.6 Sale",
"value": "gcp_D6",
"activeIcon": "https://img.lazcdn.com/us/lazgcp/e0557f6e-169b-45ec-91c4-e9e30eb17160_ALL-60-60.png",
"normalIcon": "https://img.lazcdn.com/us/lazgcp/e0557f6e-169b-45ec-91c4-e9e30eb17160_ALL-60-60.png"
}
]
},
{
"name": "location",
"unfoldRow": "3",
"title": "Shipped From",
"urlKey": "location",
"hidden": false,
"locked": false,
"type": "location",
"uniqueName": "location",
"value": [],
"options": [
{
"title": "East Java",
"value": "A-ID-4"
},
{
"title": "Jabodetabek",
"value": "A-ID-1"
},
{
"title": "North Sumatera",
"value": "A-ID-6"
},
{
"title": "Kota Depok",
"value": "R80010434"
},
{
"title": "Kab. Sidoarjo",
"value": "R80010303"
},
{
"title": "Kab. Deli Serdang",
"value": "R80010265"
}
]
},
{
"showMin": "Min",
"showMax": "Max",
"name": "price",
"unfoldRow": "2",
"title": "Price",
"urlKey": "price",
"hidden": false,
"locked": false,
"type": "price",
"uniqueName": "price"
},
{
"name": "rating",
"unfoldRow": "2",
"title": "Rating",
"urlKey": "rating",
"hidden": false,
"locked": false,
"type": "rating",
"uniqueName": "rating",
"value": "0"
},
{
"name": "attribute",
"unfoldRow": "-1",
"title": "Skin Care Benefits",
"urlKey": "ppath",
"hidden": false,
"locked": false,
"type": "multiple",
"uniqueName": "40385",
"options": [
{
"title": "Oil Control",
"value": "40385:135942"
},
{
"title": "Pore Control",
"value": "40385:135951"
},
{
"title": "Brightening",
"value": "40385:228695"
}
]
},
{
"name": "attribute",
"unfoldRow": "-1",
"title": "Skin Types",
"urlKey": "ppath",
"hidden": false,
"locked": false,
"type": "multiple",
"uniqueName": "30740",
"options": [
{
"title": "Normal",
"value": "30740:60807"
},
{
"title": "Oily",
"value": "30740:60839"
}
]
},
{
"name": "attribute",
"unfoldRow": "-1",
"title": "Skin Concerns",
"urlKey": "ppath",
"hidden": false,
"locked": false,
"type": "multiple",
"uniqueName": "40391",
"options": [
{
"title": "Oiliness",
"value": "40391:71277"
},
{
"title": "Dullness",
"value": "40391:135957"
}
]
},
{
"name": "attribute",
"unfoldRow": "-1",
"title": "Product Feature",
"urlKey": "ppath",
"hidden": false,
"locked": false,
"type": "multiple",
"uniqueName": "120024468",
"options": [
{
"title": "Paraben-free",
"value": "120024468:136834"
}
]
},
{
"name": "attribute",
"unfoldRow": "-1",
"title": "Product Form",
"urlKey": "ppath",
"hidden": false,
"locked": false,
"type": "multiple",
"uniqueName": "30780",
"options": [
{
"title": "Foam",
"value": "30780:68564"
}
]
},
{
"name": "attribute",
"unfoldRow": "-1",
"title": "Ingredient Preference",
"urlKey": "ppath",
"hidden": false,
"locked": false,
"type": "multiple",
"uniqueName": "120150202",
"options": [
{
"title": "Niacinamide",
"value": "120150202:123811818"
}
]
},
{
"name": "attribute",
"unfoldRow": "-1",
"title": "Special Claims",
"urlKey": "ppath",
"hidden": false,
"locked": false,
"type": "multiple",
"uniqueName": "120023693",
"options": [
{
"title": "BPOM Registered",
"value": "120023693:127537215"
}
]
}
],
"filteredQuatity": "1",
"filteredDoneText": "Product",
"title": "Search Filter",
"pos": 0
},
"listItems": [
{
"name": "Men's Biore Double Scrub Facial Foam Cool Oil Clear 100gr",
"nid": "159947433",
"itemId": "159947433",
"icons": [
{
"domClass": "120014",
"text": "Voucher save 4%",
"type": "text",
"group": "2",
"showType": "0",
"bizType": "voucherApplied"
},
{
"domClass": "225188",
"type": "img",
"group": "3",
"showType": "0",
"bizType": "campaign"
},
{
"domClass": "68675",
"type": "img",
"group": "3",
"showType": "0",
"bizType": "lazMall"
}
],
"image": "https://id-live-01.slatic.net/p/282e6a2fbf26571c3c5eab569e609852.jpg",
"isSmartImage": false,
"originalPriceShow": "",
"priceShow": "Rp32.200",
"discount": "4% Off",
"ratingScore": "4.864764860348532",
"review": "8378",
"location": "Kota Depok",
"thumbs": [],
"sellerName": "KAO Store",
"sellerId": "1000001053",
"brandName": "Men's Biore",
"brandId": "116687",
"cheapest_sku": "BI568HBACHV3ANID-136017",
"skuId": "181742191",
"sku": "BI568HBACHV3ANID",
"categories": [
3509,
3902,
18067,
18216
],
"price": "32200",
"restrictedAge": 0,
"inStock": true,
"originalPrice": "33600",
"clickTrace": "query:159947433;nid:159947433;src:LazadaMainSrp;rn:223837b9b80f3a6303f7c1f263ef8577;region:id;sku:BI568HBACHV3ANID;price:32200;client:desktop;supplier_id:1000001053;session_id:;biz_source:h5_internal;slot:0;utlog_bucket_id:470687;asc_category_id:18216;item_id:159947433;sku_id:181742191;shop_id:16328;templateInfo:-1_A3_C#107879_E#",
"itemSoldCntShow": "41.5K sold",
"longImageDisplayable": false,
"skus": [
{
"id": "BI568HBACHV3ANID-136017"
}
],
"promotionId": "",
"isSponsored": false,
"tItemType": "nt_product",
"skuType": "2",
"adFlag": "0",
"directSimilarUrl": "https://native.m.lazada.com/dynamicxresult?item_img=https%3A%2F%2Fid-live-01.slatic.net%2Fp%2F282e6a2fbf26571c3c5eab569e609852.jpg&src=srp_findsimilar&item_id=159947433&sku_id=181742191¶ms=%7B%22sub_src%22%3A%22long_press%22%2C%22src%22%3A%22srp_findsimilar%22%7D&m=tpp_findSimilar&q=159947433&similarType=findSimilarV1&price=32200.00&spuTriggerItem=0",
"gridTitleLine": "2",
"isFission": "0",
"isBadgeAutoScroll": false,
"showCart": false,
"showBackIcon": false,
"showUnitPrice": false,
"itemUrl": "//www.lazada.co.id/products/pdp-i159947433.html",
"querystring": "fs_ab=2&priceCompare=skuId%3A181742191%3Bsource%3Alazada-search-voucher%3Bsn%3A223837b9b80f3a6303f7c1f263ef8577%3BoriginPrice%3A3220000%3BdisplayPrice%3A3220000%3BisGray%3Afalse%3BsinglePromotionId%3A910000049169004%3BsingleToolCode%3ApromPrice%3BvoucherPricePlugin%3A0%3Btimestamp%3A1780565848388&c=&ratingscore=4.864764860348532&freeshipping=0&source=search&channelLpJumpArgs=&fuse_fs=&search=1&sale=41518&price=3.22E%204&review=8378&location=Kota%20Depok&stock=1&lang=en&request_id=223837b9b80f3a6303f7c1f263ef8577&clickTrackInfo=query%253A159947433%253Bnid%253A159947433%253Bsrc%253ALazadaMainSrp%253Brn%253A223837b9b80f3a6303f7c1f263ef8577%253Bregion%253Aid%253Bsku%253ABI568HBACHV3ANID%253Bprice%253A32200%253Bclient%253Adesktop%253Bsupplier_id%253A1000001053%253Bsession_id%253A%253Bbiz_source%253Ah5_internal%253Bslot%253A0%253Butlog_bucket_id%253A470687%253Basc_category_id%253A18216%253Bitem_id%253A159947433%253Bsku_id%253A181742191%253Bshop_id%253A16328%253BtemplateInfo%253A-1_A3_C%2523107879_E%2523"
}
],
"breadcrumb": [
{
"url": "https://www.lazada.co.id",
"title": "Home"
},
{
"title": "Search Results"
}
],
"sortBar": {
"tItemType": "nt_sortbar",
"filter": "Filter",
"style": "wf",
"sortItems": [
{
"name": "Popularity",
"tip": "Best Match",
"isActive": "true",
"value": "popularity",
"key": "sort",
"tabName": ""
},
{
"name": "Price-ASC",
"tip": "Price low to high",
"value": "priceasc",
"key": "sort",
"tabName": ""
},
{
"name": "Price-DESC",
"tip": "Price high to low",
"value": "pricedesc",
"key": "sort",
"tabName": ""
}
],
"hiddenLayoutBtn": false,
"showFilterBtn": true,
"hasFilter": false
},
"resultTips": {
"tItemType": "nt_resulttips",
"tips": "1 items found for \"{$0}\"",
"keywords": [
{
"text": "159947433"
}
]
},
"linksInfo": []
},
"mainInfo": {
"errorMsg": "",
"bizCode": 0,
"serverParams": "translatedEnQuery%3D159947433%26in_sufficient_relevant_items%3D1%26",
"totalResults": "1",
"pageSize": "40",
"page": "1",
"hiddenLayoutBtn": false,
"layoutInfo": {
"listHeader": [
"didYouMean",
"campaignBanner",
"categoryBar",
"brandBar",
"superStore",
"banner",
"resultTips",
"navCategory",
"hotDeal",
"emptyResult",
"recQuery",
"emptyResultBannerTips",
"limitedResult",
"recommendTitle"
],
"stickyHeader": [
"reminderBanner"
],
"sceneHeader": [],
"halfStickyHeader": [
"sortBar",
"preposeFilter"
],
"bottomHalfStickyHeader": []
},
"pageType": "searchList",
"gridTitleLine": "2",
"trackParams": {},
"userId": "",
"cate_id": "",
"hyperspaceInfo": "",
"currency": "Rp",
"currencyOnRight": "false",
"currencySpace": "false",
"isShowFeedbackForm": "false",
"showThumbs": "false",
"allProductURL": "/all-products/",
"addToCartURL": "//cart.lazada.co.id/cart/api/add",
"cluster": "fiber2_os30",
"column": 2,
"bucketId": "mobile_v4",
"auctionType": 1,
"noMorePages": true,
"srpName": "LazadaMainSrp",
"params": "{\"src\":\"h5_internal\"}",
"searchScenario": "keyword",
"hiddenShopChangeBtn": true,
"selectedFilters": {},
"expParams": {
"disableTileSimple": "1",
"isBadgeAutoScroll": "0",
"filterLazyLoad": "0",
"funnelFilterBtnPosition": "sortBarContainerRight",
"enableShortStyle": "0",
"enableFeedbackAssistant": "1",
"disableScreenSimple": "1",
"enableCompactLineHeight": "1",
"disableFspImagePreload": "0"
},
"filterLazyLoad": false,
"RN": "223837b9b80f3a6303f7c1f263ef8577",
"style": "wf",
"title": "159947433",
"lang": "en",
"venture": "ID",
"themes": [
{
"font-size": "11",
"labelMarginLeft": "0",
"color": "#FF0066",
"key": "120014"
},
{
"img": "https://img.lazcdn.com/us/lzd-onepiece/e09da34c2fe4a880c5c286c8850d9fbd1755779562798.png",
"width": "117",
"labelMarginLeft": "0",
"key": "68675",
"height": "36"
},
{
"img": "https://img.lazcdn.com/us/lazgcp/a49c11fa-1ebb-468b-bcd6-ad3ba69ef827_ALL-112-52.png",
"width": "112",
"labelMarginLeft": "0",
"key": "225188",
"height": "52"
}
],
"q": "159947433",
"rt": {
"all": 179
},
"serverResponseTime": 1780565848,
"reqParams": "{\"src\":\"h5_internal\",\"refer\":\"https://www.lazada.co.id/\",\"scenario\":\"keyword-dynamic\",\"ab_test\":\"BASE:0\"}",
"pageTitle": "159947433 - Harga & Promo Terbaik | Lazada Indonesia"
},
"seoInfo": {
"pageTitle": "159947433 - Harga & Promo Terbaik | Lazada Indonesia",
"description": "Cari 159947433? Lazada Indonesia adalah tempat berkumpulnya toko lokal dan internasional tepercaya! Nikmati belanja lebih aman dan nyaman dengan produk asli, pengiriman cepat, harga terbaik. Belanja sekarang dengan kebijakan pengembalian mudah dan pembayaran aman!",
"robotsContent": "index,follow",
"canonicalHref": "/catalog/?q=159947433",
"androidDeepLink": "android-app://com.lazada.android/lazada/id/page?url_key=%2Fcatalog%2F%3Fq%3D159947433&utm_campaign=%2Fcatalog%2F%3Fq%3D159947433&utm_medium=organic&utm_source=google_app_indexing&utm_from=search",
"nextHref": "/catalog/?page=2&q=159947433",
"internalLink": [],
"h1": "",
"itemListSchema": {
"@context": "https://schema.org",
"@type": "ItemList",
"name": "Best Selling 159947433 Products",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"item": {
"@type": "Product",
"name": "Men's Biore Double Scrub Facial Foam Cool Oil Clear 100gr",
"image": "https://id-live-01.slatic.net/p/282e6a2fbf26571c3c5eab569e609852.jpg",
"url": "//www.lazada.co.id/products/pdp-i159947433.html",
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.9",
"ratingCount": 8378
}
}
}
]
},
"breadcrumbSchema": {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"item": {
"@id": "https://www.lazada.co.id",
"name": "Home"
},
"@type": "ListItem",
"position": 1
}
]
},
"breadcrumbData": [
{
"categoryName": "Home",
"categoryLink": "https://www.lazada.co.id"
},
{
"categoryName": "Search Results"
}
],
"productSchema": {
"@type": "Product",
"@context": "https://schema.org",
"name": "Men's Biore Double Scrub Facial Foam Cool Oil Clear 100gr",
"image": "https://id-live-01.slatic.net/p/282e6a2fbf26571c3c5eab569e609852.jpg",
"sku": "BI568HBACHV3ANID",
"mpn": "181742191",
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.9",
"ratingCount": 8378
},
"brand": {
"@type": "Organization",
"name": "Men's Biore"
}
}
}
}
}
],
"tokenUsage": 10
}
```
# Bulk Scraping With Custom Scraper
import { Step, Steps } from 'fumadocs-ui/components/steps';
The Bulk API lets you run one custom scraper workflow against a list of URLs in a single submission, instead of sending a separate request for every page.
Bulk runs are asynchronous. You submit the workflow and its URLs, receive a submission ID immediately, then poll that ID for progress and results.
## What Is a Custom Scraper?
A **custom scraper** is a Playground request that carries its own manual workflow. Instead of pointing at a saved scraper, you send the workflow steps inline with the request, so the same extraction logic can be applied to any URL you pass in.
## Submit a Bulk Run
Copy the body request from your custom manual scraper.
Paste it into the `"workflow": {}` of the request below.
Fill in your API key, the proxy country, and the list of URLs you want to scrape.
Send the request and save the `submission_id` from the response.
### Request
```bash title="Submit a bulk run"
curl --location 'https://bulk.mrscraper.com/api/gateway/v1/bulk-submissions/run' \
--header 'Content-Type: application/json' \
--header 'x-api-key: {MRSCRAPER_API_KEY}' \
--header 'Cookie: sl-session=P89TLJQZiGoIfOVndtHSPg==' \
--data '{
"engine": "http",
"workflow": {
"url": "https://books.toscrape.com/",
"homePage": true,
"proxyCountry" : "us",
"workflow": [
{
"type": "script",
"data": {
"name": "first_book",
"timeout": 30,
"code": "(function() {\n const firstArticle = document.querySelector('\''article.product_pod'\'');\n if (!firstArticle) {\n return { title: null, price: null };\n }\n \n const titleLink = firstArticle.querySelector('\''h3 a'\'');\n const title = titleLink ? (titleLink.getAttribute('\''title'\'') || titleLink.textContent).trim() : null;\n \n const priceEl = firstArticle.querySelector('\''p.price_color'\'');\n const price = priceEl ? priceEl.textContent.trim() : null;\n \n return { title: title || null, price: price || null };\n})();"
}
}
]
},
"request_method": "POST",
"proxy_country": "us",
"urls": [
"https://books.toscrape.com/",
"https://books.toscrape.com/catalogue/page-2.html",
"https://books.toscrape.com/catalogue/page-3.html"
]
}'
```
| Parameter | Location | Description |
| ----------------------- | -------- | -------------------------------------------------------------------------------------- |
| `x-api-key` | header | Your MrScraper API key. |
| `Cookie` | header | Session cookie for the bulk gateway. Send the default value shown above. |
| `engine` | body | Execution engine used for the run. Use `http`. |
| `workflow` | body | The scraper configuration applied to every URL in the run. |
| `workflow.url` | body | The first page to scrape. |
| `workflow.homePage` | body | Set to `true` to visit the website's home page first, then navigate to the target URL. |
| `workflow.proxyCountry` | body | Country the workflow accesses the pages from. |
| `workflow.workflow` | body | The workflow steps copied from your Playground scraper. |
| `request_method` | body | HTTP method used to request each URL. |
| `proxy_country` | body | Proxy country for the bulk submission. |
| `urls` | body | Array of URLs to run the workflow against. |
### Response
The submission is accepted and queued immediately. The run itself continues in the background.
```json title="Submission accepted"
{
"data": {
"submission_id": "01M0HD8JB6YXN2RZM2AC48391M",
"engine": "http",
"priority": 1,
"status": "queued",
"total_urls": 3,
"succeeded": 0,
"failed": 0,
"dead": 0,
"pending": 3,
"percent_complete": 0,
"created_at": "2026-08-21T05:38:52.902189Z",
"started_at": "2026-08-21T05:38:52.939086Z",
"finished_at": null
},
"message": "submission running"
}
```
The `submission_id` is the only way to retrieve the results of a bulk run. Store it before moving on.
## Check Progress and Results
Use the submission ID to poll the run. The same endpoint returns both the current progress counters and any results extracted so far.
### Request
```bash title="Check a bulk submission"
curl --location 'https://bulk.mrscraper.com/api/results/v1/bulk-submissions/{SUBMISSION_ID}?limit=25' \
--header 'x-api-key: {MRSCRAPER_API_KEY}' \
--header 'Cookie: sl-session=P89TLJQZiGoIfOVndtHSPg=='
```
| Parameter | Location | Description |
| --------------- | -------- | ------------------------------------------------------------------------ |
| `x-api-key` | header | Your MrScraper API key. |
| `Cookie` | header | Session cookie for the bulk gateway. Send the default value shown above. |
| `SUBMISSION_ID` | path | The ID returned when you submitted the bulk run. |
| `limit` | query | Number of results to return per page. Maximum is `100`. |
### Response While Running
While the run is still in progress, `results` is empty or partially filled and `percent_complete` is below `100`.
```json title="Run still in progress"
{
"data": {
"submission_id": "01M0HDS6DSWSSFTCT1JCDTA0A2",
"engine": "http",
"status": "queued",
"total_urls": 3,
"succeeded": 0,
"failed": 0,
"dead": 0,
"pending": 3,
"percent_complete": 0,
"created_at": "2026-08-21T05:47:57.753168Z",
"started_at": "2026-08-21T05:47:57.783051Z",
"finished_at": null,
"results": [],
"next_cursor": null
},
"message": "run found"
}
```
### Response When Finished
Once every URL has been processed, `percent_complete` reaches `100` and `results` contains one entry per URL.
```json title="Run complete"
{
"data": {
"submission_id": "01M0HD8JB6YXN2RZM2AC48391M",
"engine": "http",
"status": "queued",
"total_urls": 3,
"succeeded": 3,
"failed": 0,
"dead": 0,
"pending": 0,
"percent_complete": 100,
"created_at": "2026-08-21T05:38:52.902189Z",
"started_at": "2026-08-21T05:38:52.939086Z",
"finished_at": null,
"results": [
{
"id": "01M0HD8JBQKH2WFKWZ0KKQ15BB:0",
"job_id": "01M0HD8JBQKH2WFKWZ0KKQ15BB",
"url": "https://books.toscrape.com/catalogue/page-2.html",
"http_status": 200,
"data": {
"first_book": {
"price": "£12.84",
"title": "In Her Wake"
}
},
"raw_ref": "2026/08/21/01M0HD8JBQKH2WFKWZ0KKQ15BB-a0.html.zst",
"screenshot_ref": null,
"engine": "http",
"extracted_at": "2026-08-21T05:39:15.841670Z"
},
{
"id": "01M0HD8JBQAS5DN2ZDWQ7M7MGN:0",
"job_id": "01M0HD8JBQAS5DN2ZDWQ7M7MGN",
"url": "https://books.toscrape.com/catalogue/page-3.html",
"http_status": 200,
"data": {
"first_book": {
"price": "£57.31",
"title": "Slow States of Collapse: Poems"
}
},
"raw_ref": "2026/08/21/01M0HD8JBQAS5DN2ZDWQ7M7MGN-a0.html.zst",
"screenshot_ref": null,
"engine": "http",
"extracted_at": "2026-08-21T05:39:14.414348Z"
},
{
"id": "01M0HD8JBQJ2TRGA8CNKQC9Z2B:0",
"job_id": "01M0HD8JBQJ2TRGA8CNKQC9Z2B",
"url": "https://books.toscrape.com/",
"http_status": 200,
"data": {
"first_book": {
"price": "£51.77",
"title": "A Light in the Attic"
}
},
"raw_ref": "2026/08/21/01M0HD8JBQJ2TRGA8CNKQC9Z2B-a0.html.zst",
"screenshot_ref": null,
"engine": "http",
"extracted_at": "2026-08-21T05:39:14.089989Z"
}
],
"next_cursor": null
},
"message": "run found"
}
```
### Result Fields
| Field | Description |
| ------------------------------------------- | ------------------------------------------------------------------- |
| `total_urls` | Number of URLs in the submission. |
| `succeeded` / `failed` / `dead` / `pending` | Per-URL status counters for the run. |
| `percent_complete` | Progress of the run, from `0` to `100`. |
| `results[].url` | The URL this result was extracted from. |
| `results[].http_status` | HTTP status code returned by the target page. |
| `results[].data` | Data extracted by your workflow steps, keyed by step name. |
| `results[].raw_ref` | Reference to the stored raw page content. |
| `results[].screenshot_ref` | Reference to the stored screenshot, if one was captured. |
| `next_cursor` | Cursor for the next page of results. `null` when there are no more. |
Results are not returned in the order the URLs were submitted. Match each result to its source page using the `url` field rather than its position in the array.
# E-commerce
import { Step, Steps } from 'fumadocs-ui/components/steps';
E-commerce websites are a rich source of product data that can be invaluable for market analysis, price comparison, inventory management, and more.
In this guide, we'll demonstrate how to use the MrScraper's Scraper to gather product details such as names, prices, ratings, and availability from an e-commerce website.
## Scenario
Imagine you're a market analyst looking to gather data on products listed on Tiktok Shop to analyze pricing trends and customer preferences. You want to extract details like product names, prices, ratings, and the number of items sold.
## Create a New AI Listing Scraper
1. Go to the **Scrapers** page by clicking the **triangle icon** on the left sidebar.
2. Click on the **Create AI Scraper +** button.
3. Select the **Listing Scraper** option.
4. In the **Target URL** field, enter the URL of the Tiktok Shop page you want to scrape. For example: `https://shop-id.tokopedia.com/c/phones-electronics/601739?source=ecommerce_mall&enter_method=categories&first_entrance=ecommerce_mall&first_entrance_position=region_redirect_301`.
5. Click on the **Start Scraping** button to start scraping.
**Result :**
```json title="Scraping Result"
{
"mode": "direct",
"count": 71,
"links": [
"https://www.tiktok.com/shop/pdp/nose-ring-by-oufer-20g-halloween-cz-double-hoop-in-316l-stainless-steel/1729608283143704812",
"https://www.tiktok.com/shop/pdp/usb-powered-led-disco-lights-by-unnamed-brand-with-remote-control-strobe-effects/1729483087369179985",
"https://www.tiktok.com/shop/pdp/halloween-pumpkin-night-light-mini-led-dimmable-touch-lamp-for-kids/1731541214379741272",
"https://www.tiktok.com/shop/pdp/soft-funny-throw-blanket-cozy-fleece-for-home-movie-decor/1731291206388977735",
"https://www.tiktok.com/shop/pdp/40oz-sip-sip-hooray-halloween-tumblers-with-lid-straw-durable-glass/1729576207882752721"
],
"products": [
{
"id": "1729608283143704812",
"url": "https://www.tiktok.com/shop/pdp/nose-ring-by-oufer-20g-halloween-cz-double-hoop-in-316l-stainless-steel/1729608283143704812",
"sold": 2500,
"brand": "Oufer Body Piercing Jewelry",
"price": 9.46,
"title": "Oufer 20G Halloween CZ Double Hoop Nose Ring 316L Stainless Steel",
"rating": 4.6,
"section": "TikTok Picks",
"currency": "$",
"sold_raw": "2.5K",
"free_shipping": false,
"original_price": 11.82
},
{
"id":"1729483087369179985"
"url":"https://www.tiktok.com/shop/pdp/usb-powered-led-disco-lights-by-unnamed-brand-with-remote-control-strobe-effects/1729483087369179985"
"sold":11000
"brand":"11.0K sold"
"price":16.65
"title":"1pc All Aluminum One Body Party Disco Light with Remote Control, USB Powered, for Party Birthday Wedding Holiday Christmas Decoration #TOP PICKS"
"rating":4.6
"section":"Oufer 20G Halloween CZ Double Hoop Nose Ring 316L Stainless Steel"
"currency":"$"
"sold_raw":"11.0K"
"free_shipping":false
"original_price":34.69
},
{
"id":"1731541214379741272"
"url":"https://www.tiktok.com/shop/pdp/halloween-pumpkin-night-light-mini-led-dimmable-touch-lamp-for-kids/1731541214379741272"
"sold":1900
"brand":"1.9K sold"
"price":9.99
"title":"Halloween Pumpkin Night Light, Halloween Decorations Outdoor,Mini LED Pumpkin Lamp with 3 Level Dimmable, Nursery Nightlight for Kids, Silicone Rechargeable Bedside Touch Lamp, for Kids TikTokShopBlackFriday"
"rating":4.7
"section":"1pc All Aluminum One Body Party Disco Light with Remote Control, USB Powered, for Party Birthday Wedding Holiday Christmas Decoration #TOP PICKS"
"currency":"$"
"sold_raw":"1.9K"
"free_shipping":false
"original_price":NULL
},
{
"id":"1731291206388977735"
"url":"https://www.tiktok.com/shop/pdp/soft-funny-throw-blanket-cozy-fleece-for-home-movie-decor/1731291206388977735"
"sold":3000
"brand":"3.0K sold"
"price":14.39
"title":"Soft Funny Throw Blanket Horror Icons Flannel Fleece - Cozy Fuzzy Plush Comfy All-Season Sofa Bedroom Dorm Couch Office Car Travel Home Bedding,Comfortable Movie Decor Blanket Men Women Boys Girls Halloween Birthday Fan Gifts"
"rating":4.8
"section":"Halloween Pumpkin Night Light, Halloween Decorations Outdoor,Mini LED Pumpkin Lamp with 3 Level Dimmable, Nursery Nightlight for Kids, Silicone Rechargeable Bedside Touch Lamp, for Kids TikTokShopBlackFriday"
"currency":"$"
"sold_raw":"3.0K"
"free_shipping":true
"original_price":23.98
},
{
"id":"1729576207882752721"
"url":"https://www.tiktok.com/shop/pdp/40oz-sip-sip-hooray-halloween-tumblers-with-lid-straw-durable-glass/1729576207882752721"
"sold":6100
"brand":"6.1K sold"
"price":18.79
"title":"Sip-Sip Hooray! Halloween Tumbler – Cup with Lid & Straw, Spooky Season Iced Coffee Gift, Halloweentok 2024 Reusable Drinkware Insulated Sports Bottle Travel Water Bottle"
"rating":4.7
"section":"Soft Funny Throw Blanket Horror Icons Flannel Fleece - Cozy Fuzzy Plush Comfy All-Season Sofa Bedroom Dorm Couch Office Car Travel Home Bedding,Comfortable Movie Decor Blanket Men Women Boys Girls Halloween Birthday Fan Gifts"
"currency":"$"
"sold_raw":"6.1K"
"free_shipping":false
"original_price":28.56
}
]
}
```
## Filter Out
Next, tell the AI to filter the scraped results based on specific criteria. For this use case, you can use the following prompt:
```txt
take only product with rating 4.7 or more.
```
**Result :**
```json title="Filtered Scraping Result"
{
"mode": "direct",
"products": [
{
"url": "https://www.tiktok.com/shop/pdp/halloween-pumpkin-night-light-mini-led-dimmable-touch-lamp-for-kids/1731541214379741272",
"sold": "1.9K sold",
"price": 9.99,
"title": "Halloween Pumpkin Night Light, Halloween Decorations Outdoor,Mini LED Pumpkin Lamp with 3 Level Dimmable, Nursery Nightlight for Kids, Silicone Rechargeable Bedside Touch Lamp, for Kids TikTokShopBlackFriday",
"rating": 4.7,
"section": "TikTok Picks",
"currency": "$",
"free_shipping": false,
"original_price": null
},
{
"url": "https://www.tiktok.com/shop/pdp/soft-funny-throw-blanket-cozy-fleece-for-home-movie-decor/1731291206388977735",
"sold": "3.0K sold",
"price": 14.39,
"title": "Soft Funny Throw Blanket Horror Icons Flannel Fleece - Cozy Fuzzy Plush Comfy All-Season Sofa Bedroom Dorm Couch Office Car Travel Home Bedding,Comfortable Movie Decor Blanket Men Women Boys Girls Halloween Birthday Fan Gifts",
"rating": 4.8,
"section": "TikTok Picks",
"currency": "$",
"free_shipping": true,
"original_price": 23.98
},
{
"url": "https://www.tiktok.com/shop/pdp/40oz-sip-sip-hooray-halloween-tumblers-with-lid-straw-durable-glass/1729576207882752721",
"sold": "6.1K sold",
"price": 18.79,
"title": "Sip-Sip Hooray! Halloween Tumbler – Cup with Lid & Straw, Spooky Season Iced Coffee Gift, Halloweentok 2024 Reusable Drinkware Insulated Sports Bottle Travel Water Bottle",
"rating": 4.7,
"section": "TikTok Picks",
"currency": "$",
"free_shipping": false,
"original_price": 28.56
},
{
"url": "https://www.tiktok.com/shop/pdp/1729574434882163435",
"sold": "4.3K sold",
"price": 28.79,
"title": "Women's Halloween Themed All Over Hybrid Skull Knit Button Front Cardigan, Casual Drop Shoulder Long Sleeve V Neck Knitwear for Fall, Fashion Ladies' Knit Clothing for Daily Wear",
"rating": 4.8,
"section": "TikTok Picks",
"currency": "$",
"free_shipping": false,
"original_price": 38.39
},
{
"url": "https://www.tiktok.com/shop/pdp/soft-dragon-pattern-throw-blanket-by-brand-for-home-office-travel/1729625176913449761",
"sold": "4.7K sold",
"price": 9.15,
"title": "Dragon Pattern Blanket, 1/2 Counts Soft Throw Blanket, Halloween Decor Warm Napping Blanket for Home Office Travel Camping Dormitory, Slogan Print Blanket",
"rating": 4.9,
"section": "TikTok Picks",
"currency": "$",
"free_shipping": false,
"original_price": null
},
{
"url": "https://www.tiktok.com/shop/pdp/diamond-art-roller-2025-dual-pack-for-smooth-pressing-craft-tools/1732001021448392940",
"sold": null,
"price": 5.3,
"title": "1/2PCS Diamond Art Roller, 2025 New Diamond Painting Roller, Diamond Painting Tools, Essential DIY Craft Tool for Rhinestone Embroidery, Press Roller for Smooth Pressing, Crafting and Diamond Painting Projects",
"rating": 5,
"section": "Savings for you",
"currency": "$",
"free_shipping": false,
"original_price": null
},
{
"url": "https://www.tiktok.com/shop/pdp/kojic-acid-turmeric-toner-fur-gesicht-und-korper-250ml/1731391357821554923",
"sold": "11.8K sold",
"price": 23,
"title": "[NEW] Kojic Acid Turmeric Toner for Face & Body | Daily Toner for Uneven Skin Tone & Texture | Niacinamide, Glycolic Acid for Clear Glass Skin | Korean Skin Care | 250ml",
"rating": 4.7,
"section": "Savings for you",
"currency": "$",
"free_shipping": false,
"original_price": 27
},
{
"url": "https://www.tiktok.com/shop/pdp/chrleisure-fleece-lined-high-waist-leggings-for-women-1-3pcs/1731711198249390235",
"sold": "10.6K sold",
"price": 29.99,
"title": "【TikTokShopBlackFriday】CHRLEISURE 3PCS Thermal Thick FLeece Lined Leggings for Cold Winter Warm, High Waist Women's Cozy Workout Wear Fleece Pants for Yoga Riding Casual Wear",
"rating": 4.7,
"section": "Top deals for you",
"currency": "$",
"free_shipping": true,
"original_price": 37.49
},
{
"url": "https://www.tiktok.com/shop/pdp/dynasty-sweats-by-youngla-100-cotton-baggy-fit-unique-design/1731156978383884791",
"sold": "1.4K sold",
"price": 55,
"title": "2116 - Dynasty Sweats",
"rating": 4.7,
"section": "Top deals for you",
"currency": "$",
"free_shipping": true,
"original_price": null
},
{
"url": "https://www.tiktok.com/shop/pdp/height-adjustable-swivel-chair-by-sweetcrispy-wide-ergonomic-design/1729408738017907174",
"sold": "157.1K sold",
"price": 66.98,
"title": "【Star Furniture】Height Adjustable Criss Cross Chair with No Wheels / with Wheels- Office Wide Swivel Home Office Desk Chairs Reading Chair",
"rating": 4.7,
"section": "Popular items",
"currency": "$",
"free_shipping": true,
"original_price": 115.99
},
{
"url": "https://www.tiktok.com/shop/pdp/power-bank-10000mah-2-pack-by-asperx-with-22-5w-fast-charge-digital-display/1729568096320852893",
"sold": "15.8K sold",
"price": 18.99,
"title": "AsperX 22.5W Fast Charging Power Bank, 2 pack 10000mAh Portable Charger with Digital Display, Battery Pack for Smartphone, Tablet, Perfect Gifts",
"rating": 4.7,
"section": "Popular items",
"currency": "$",
"free_shipping": true,
"original_price": 79.99
},
{
"url": "https://www.tiktok.com/shop/pdp/huloo-sleep-ultra-soft-memory-foam-play-mat-1-3-non-slip-velvet/1730123606468825995",
"sold": "7.1K sold",
"price": 29.39,
"title": "Huloo Sleep Ultra Soft Memory Foam Play Mat for Tummy Time, 1.3\" Thick Non-Slip Crawling Mat, Non-Toxic Velvet Nursery Floor Mat",
"rating": 4.7,
"section": "Popular items",
"currency": "$",
"free_shipping": true,
"original_price": 109.99
},
{
"url": "https://www.tiktok.com/shop/pdp/based-skin-trio-100-pure-hypoclorous-acid-skincare-set/1731806435287666998",
"sold": "5.6K sold",
"price": 34.5,
"title": "BASED Skincare Trio | Daily Skincare Duo + Skin Revival Spray | Facial Cleanser for Breakouts | Daily Moisturizer & Cleanser | For All Skin Types | Non-Toxic, Effective, Safe",
"rating": 4.8,
"section": "Popular items",
"currency": "$",
"free_shipping": true,
"original_price": 58
},
{
"url": "https://www.tiktok.com/shop/pdp/1731997923791180042",
"sold": null,
"price": 15.57,
"title": "Autumn Winter Sexy Elegant Tight Fit Bodycon Dress, One-Step Skirt, Women's Fashion, Comfortable & Stylish, Perfect for Daily Wear(gift)",
"rating": 15,
"section": "Popular items",
"currency": "$",
"free_shipping": false,
"original_price": 24.57
},
{
"url": "https://www.tiktok.com/shop/pdp/energy-sticks-by-bloom-nutrition-10ct-180mg-natural-caffeine-zero-sugar/1730722027877602235",
"sold": "20.8K sold",
"price": 7.59,
"title": "Bloom Nutrition Energy Sticks (10 Sticks) – Focus & Metabolism Support – Natural Caffeine & B Vitamins",
"rating": 4.7,
"section": "International top sellers",
"currency": "$",
"free_shipping": false,
"original_price": 15.99
},
{
"url": "https://www.tiktok.com/shop/pdp/funny-tee-i-hate-my-chungus-life-t-shirt-soft-cotton-fit/1731999740449296622",
"sold": null,
"price": 7.98,
"title": "I hate my chungus life t-shirt (100% cotton), funny tee",
"rating": 7,
"section": "Best sellers",
"currency": "$",
"free_shipping": true,
"original_price": 20.99
},
{
"url": "https://www.tiktok.com/shop/pdp/hooded-plaid-jacket-for-women-by-asvivid-casual-long-sleeve-coat/1729535208059146968",
"sold": "110.6K sold",
"price": 37.04,
"title": "Women's Plaid / Houndstooth Print Button Front Hooded Coat, Casual Longsleeves Pocket Coat for Fall & Winter, Ladies Outerwear for Daily Wear, Womenswear",
"rating": 4.7,
"section": "Best sellers",
"currency": "$",
"free_shipping": false,
"original_price": 53.68
},
{
"url": "https://www.tiktok.com/shop/pdp/christmas-themed-set-festive-practical-design/1731817636155789477",
"sold": null,
"price": 5.03,
"title": "10/20/30Pcs Christmas Elements Four Color Pen Black, Blue, Red, Green Four Color Pen Santa Claus Snowman Christmas Tree Snowflake Deer Various Patterns Christmas Party Small Gifts Gift Fillers Smooth and Constant Oil (Mixed)",
"rating": 5,
"section": "Best sellers",
"currency": "$",
"free_shipping": false,
"original_price": null
}
]
}
```
* Some e-commerce sites show different listings by region. Use MrScraper's [proxy](/docs/features/proxy) to view results from other countries, or your own proxy if needed.
* Schedule your scraper to run daily or weekly to keep your e-commerce data up to date.
## Use the Extracted Data
Now that you have successfully scraped and filtered the e-commerce product data, you can use this information for various purposes such as market analysis, price comparison, inventory management, or even feeding it into your own applications or databases. You can export the data in formats like JSON or CSV for easy integration with other tools.
# Job Listing
import { Step, Steps } from 'fumadocs-ui/components/steps';
Extracting job listings manually from job boards can be tedious and time-consuming. With **MrScraper’s AI Scraper**, you can automate this process entirely — providing only a URL and a short prompt describing what to extract.
In this guide, we’ll walk through a **real-world example** where a recruitment team uses MrScraper to gather and analyze data from a live job board to inform their hiring strategy.
## Scenario
Imagine you’re an HR specialist at a growing tech startup planning to hire a **Data Scientist**.\
Before posting your own job, you want to understand:
* What skills and qualifications are most in-demand
* How other companies describe their Data Scientist roles
* Which cities or companies are hiring for similar positions
## Create a New AI Scraper
1. Go to your **MrScraper Dashboard**.
2. Enter the URL: `https://www.glassdoor.com/Job/indonesia-data-scientist-jobs-SRCH_IL.0,9_IN113_KO10,25.htm`.
3. Select **Super Mode** to get more accurate and structured extraction for job listings.
## Filter Out
Next, tell the AI exactly what kind of job data you want to capture. The prompt defines both the structure of your results and any filters to apply. For this use case, you can use the following prompt:
```md
Extract only job listings with the job title "Data Scientist" that are suitable for fresh graduates or candidates with a minimum of 2 years of experience, and include required skills details.
For each listing, return these fields:
- Job Title
- Company Name
- Location
- Salary
- Job Type
- Experience Level
- Posted Date
- Job Description
- Required Skills
- Job URL
Filter out any listing that does not include required skills information or requires more than 2 years of experience.
```
Here’s a sample output:
```json title="Scraping Result"
{
"mode": "direct",
"results": [
{
"Salary": null,
"Job URL": "https://www.glassdoor.com/job-listing/it-data-scientist-apotek-k-24-JV_KO0,17_KE18,29.htm?jl=1009644720583",
"Job Type": null,
"Location": "Indonesia",
"Job Title": "IT Data Scientist",
"Posted Date": "30d+",
"Company Name": "Apotek K 24",
"Job Description": "Mengolah dan menganalisis data besar dari berbagai sumber (POS, CRM, marketplace, dll) untuk menemukan pola dan insight bisnis. Mengembangkan model statistik dan machine learning (supervised dan unsupervised) untuk kebutuhan forecasting, recommendation, atau clustering. Melakukan feature engineering dan model evaluation untuk memastikan performa model optimal. Berkolaborasi dengan tim Data Engineering untuk integrasi pipeline data dan deployment model. Berkoordinasi dengan tim BI Analyst untuk penerjemahan hasil analitik ke dalam dashboard dan laporan bisnis. Melakukan eksperimen model (A/B testing, hyperparameter tuning) dan dokumentasi hasilnya. Menjaga data quality, model reproducibility, serta model governance sesuai kebijakan perlindungan data perusahaan. Minimum Qualifications: Menguasai Python (NumPy, Pandas, Scikit-learn, TensorFlow/PyTorch, Matplotlib/Seaborn). Memahami konsep statistik, machine learning, dan data preprocessing. Pengalaman dengan SQL dan query optimization. Familiar dengan tools visualisasi (Power BI, Tableau, atau setara). Pengalaman dalam mengelola version control (Git) dan ML lifecycle tools (MLflow, DVC, dsb) menjadi nilai tambah. Memahami time series forecasting, NLP, atau recommender system menjadi nilai plus. Komunikatif dan kolaboratif lintas tim (Engineering, BI, Business Unit). Kompas Gramedia, through its more than 50 years of history, is striving for one goal: enlightening and empowering Indonesia. To ensure that we are able to serve the nation for another 50 years, we are undergoing a digital transformation; strengthening and expanding our solid business pillars by developing new digital business initiatives. Our vision is to enlight all the people in Indonesia with all the knowledge we have.",
"Required Skills": [
"NumPy",
"Pandas",
"Scikit-learn",
"TensorFlow",
"PyTorch",
"Matplotlib",
"Seaborn",
"Python",
"machine learning",
"data preprocessing",
"dengan SQL",
"query optimization",
"Power BI",
"Tableau",
"Git",
"MLflow",
"DVC",
"time series forecasting",
"NLP",
"Engineering",
"BI",
"Business Unit"
],
"Experience Level": "2 years"
}
]
}
```
* Some job sites show different listings by region. Use MrScraper’s [proxy](/docs/features/proxy) to view results from other countries, or your own proxy if needed.
* Schedule your scraper to run daily or weekly to keep your job data up to date.
## Use the Extracted Data
Once you’ve collected the job listings, you can export and use the data directly from the dashboard in your preferred format.
You can use these data for:
* **Job posting optimization**: Identify trending keywords or skills that attract top candidates.
* **Competitor analysis**: See how similar companies describe their open roles.
* **Internal reporting**: Share hiring trends or skill gaps with your HR or analytics team.
# Optimizing Cost
Running scrapers efficiently helps you get the most value out of MrScraper without unnecessary usage costs.\
This guide explains how to **optimize scraping costs** through smart configuration, scraper mode selection, scheduling, and output management.
## 1. Choose the Right Scraper Mode
MrScraper offers two AI Scraper modes that affect both cost and performance:
| Mode | Description | When to Use | Cost Impact |
| -------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ----------- |
| **Cheap Mode** | Fast and lightweight extraction. Suitable for simple, structured pages. | Use for lists or data with consistent structure (e.g., product names, prices). | 💲 Lowest |
| **Super Mode** | More accurate and intelligent extraction. Ideal for complex layouts or nested content. | Use for unstructured data or multiple data types (e.g., job listings, reviews). | 💲💲 Higher |
The cost difference between Cheap Mode and Super Mode depends on the target website. For websites that are easy to access and extract from, both modes may have similar costs. On more complex websites, Super Mode may perform additional attempts and processing to successfully extract data, which can increase token usage and overall cost.
## 2. Limit Extraction Scope
The broader your prompt, the more resources are used.\
Narrowing your extraction target saves cost and improves precision.
| ❌ *Expensive prompt* | ✅ *Optimized prompt* |
| ---------------------------------------------- | ------------------------------------------------------- |
| Extract all details from this e-commerce page. | Extract product name, price, and rating from this page. |
Focus on the **fields you actually need**. If you only need names and prices, don’t extract full descriptions or metadata.
## 3. Reuse and Recycle Results
Each time you run a scraper, you pay for the extraction process.\
Avoid re-running scrapers unnecessarily by reusing existing results.
**Example Workflow:**
* Store your output in a **Database Connection** or export as **CSV/JSON**.
* Only re-run the scraper when the target site changes.
* Use **Scheduling** for incremental updates instead of full refreshes.
## 4. Use Scheduling Strategically
Scraping too frequently can increase costs without adding value.\
Instead, match your schedule to how often the target data changes.
Avoid overlapping schedules. Running multiple scrapers at the same time can spike costs and reduce performance.
## 5. Optimize Proxy Usage
While proxies add flexibility, they can slightly increase scraping overhead.
* Use **MrScraper’s built-in proxy** instead of external providers to save cost and setup time.
* Only enable proxies for websites that require regional access or IP rotation.
* For internal or low-risk pages, disable proxy entirely.
Disabling proxies may change the content returned by websites that serve region-specific data. If you need accurate local pricing, product availability, or search results, use a proxy or Geo Targeting for the target region.
## 6. Monitor Usage
Keep an eye on your scraper usage and performance using the **Analytics** feature.\
Regularly review:
* The number of pages or URLs processed
* Success rate and data completeness
* AI vs. manual scraper distribution
This helps you spot overuse early and plan your scraping strategy efficiently.
Start small. Run initial tests on limited pages using **Cheap Mode**, verify output accuracy, and scale up gradually.
## 7. Leverage Reruns for Lower Costs
If you need to scrape a website repeatedly, use **Rerun** instead of creating a new scraper each time.
MrScraper uses caching to optimize repeated scraping tasks. When you rerun an existing scraper, the platform can reuse previously processed information, often reducing both token usage and execution time compared to a new scraper.
Reruns are ideal for:
* Refreshing previously collected data
* Monitoring pages for updates
* Scheduled scraping workflows
* Recurring extraction from the same website
## 8. Cap Retry Spending with Max Retries and Token Cap
A failed scrape that keeps retrying is one of the easiest ways to spend tokens without getting data back. In the [Playground](/docs/getting-started/playground), the **Basic Settings** panel gives you two limits that bound the cost of a single run.
Turn on **Retry** first, then set either or both:
| Setting | Description |
| --------------- | --------------------------------------------------------------------- |
| **Max retries** | Maximum number of retry attempts after the initial request. |
| **Token cap** | Maximum total tokens the initial request and all its retries can use. |
Retrying stops at whichever comes first: the scrape succeeds, it reaches **Max retries**, or the running token total reaches the **Token cap**. Each attempt's cost is rounded up and added to the running total.
**How to use them to control cost:**
* **Set a token cap when testing an unfamiliar site.** It puts a hard ceiling on a single run, so a page that fails repeatedly can't quietly consume your balance.
* **Lower Max retries on sites that fail consistently.** If a page is blocked, the third and fourth attempt usually fail the same way as the first. Fix the cause with **Super** mode or Geo targeting instead of paying for more attempts.
* **Leave room for at least one retry.** If the first attempt alone costs more than the cap, the scrape runs once and doesn't retry at all. On pages with variable load times or heavy bandwidth, set the cap to a few times your expected per-run cost.
Run a scrape once with no cap to see its typical token cost, then set the cap based on that number rather than guessing.
For worked examples of how the cap interacts with retries, see [Playground Token Cap](/docs/getting-started/api-token#playground-token-cap) in Token Plan.
# Create and Run a Scraper Programmatically
import { Step, Steps } from 'fumadocs-ui/components/steps';
## Overview
This guide shows you how to create an AI scraper in the dashboard and then use it programmatically through the API. This is perfect if you want to set up a scraper once and automate data extraction with simple API calls—no need to configure it every time.
## Prerequisites
Before you start, make sure you have:
* A **MrScraper API token** for authentication. If you don’t have one yet, follow this [guide to create an API token](/docs/getting-started/api-token).
## Verify Your API Token
You can verify your API token and check your account status using the [`/subscription-accounts`](/docs/api/v3/authentication/verify-token):
```bash
curl --location 'https://api.app.mrscraper.com/api/v1/subscription-accounts' \
--header 'accept: */*' \
--header 'x-api-token: '
```
```javascript
const token = "MRSCRAPER_API_TOKEN";
fetch("https://api.app.mrscraper.com/api/v1/subscription-accounts", {
method: "GET",
headers: {
"accept": "*/*",
"x-api-token": token
}
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
```
```python
import requests
token = "MRSCRAPER_API_TOKEN"
headers = {
"accept": "*/*",
"x-api-token": token
}
response = requests.get(
"https://api.app.mrscraper.com/api/v1/subscription-accounts",
headers=headers
)
print(response.json())
```
**Response (200 OK):**
```json
{
"message": "Successful operation!",
"data": {
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"tokenLimit": 10000,
"tokenUsage": 994,
"stripeSubscriptionId": "sub_xxxxxxxxxxxxxxxxxx",
"userId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"stripeStatus": "true",
"quantity": 1,
"endsAt": "2030-12-01T02:05:08.400Z",
"subscriptionItemId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"user": {
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"createdAt": "2025-11-24T01:59:15.866Z",
"createdById": null,
"updatedAt": "2026-01-17T08:11:43.270Z",
"updatedById": null,
"deletedAt": null,
"deletedById": null,
"name": "John Doe",
"email": "johndoe@example.com",
"username": null,
"latestApiToken": "atk_xxxx....",
"gender": null,
"phoneNumber": null,
"address": null,
"birthDate": null,
"avatar": "https://api.app.mrscraper.com/images/users/default-avatar.png",
"otp": null,
"otpExpiredAt": null,
"isVerified": true,
"stripeCustomerId": "cus_xxxxxxxxx",
"googleMail": null,
"googleId": null,
"s3Bucket": null,
"domainTargets": [
"https://books.toscrape.com"
]
},
"rateLimit": null,
"rateTtl": null,
"isEnterprise": true,
"cancelAtPeriodEnd": null,
"currentPeriodStart": null,
"currentPeriodEnd": null,
"proxyDollarPerGB": null,
"isAutoRenew": false,
"updatedAt": "2026-01-18T01:40:21.392Z",
"createdAt": "2025-11-24T02:05:08.470Z"
}
}
```
**Key Response Fields:**
**Subscription Account Fields:**
| Field | Type | Description |
| ---------------------- | ------------ | -------------------------------------------------- |
| `id` | string | Unique identifier for your subscription account |
| `tokenLimit` | integer | Maximum tokens available in your subscription plan |
| `tokenUsage` | integer | Total tokens consumed so far |
| `stripeSubscriptionId` | string | Stripe subscription identifier (for billing) |
| `userId` | string | Your unique user identifier |
| `stripeStatus` | string | Payment status (`"true"` = active) |
| `quantity` | integer | Subscription quantity/seats |
| `endsAt` | string | Subscription expiration date (ISO 8601 format) |
| `subscriptionItemId` | string | Stripe subscription item identifier |
| `rateLimit` | integer/null | API rate limit (requests per window) |
| `rateTtl` | integer/null | Rate limit time window in seconds |
| `isEnterprise` | boolean | Whether account has enterprise features |
| `cancelAtPeriodEnd` | boolean/null | If subscription will cancel at period end |
| `currentPeriodStart` | string/null | Current billing period start date |
| `currentPeriodEnd` | string/null | Current billing period end date |
| `proxyDollarPerGB` | number/null | Custom proxy pricing (enterprise only) |
| `isAutoRenew` | boolean | Whether subscription auto-renews |
**User Object Fields (nested under `data.user`):**
| Field | Type | Description |
| ------------------ | ------- | -------------------------------------------------- |
| `id` | string | Unique user identifier |
| `name` | string | User's full name |
| `email` | string | User's email address |
| `latestApiToken` | string | Your most recently generated API token (truncated) |
| `avatar` | string | URL to user's profile picture |
| `isVerified` | boolean | Whether email is verified |
| `stripeCustomerId` | string | Stripe customer identifier |
| `domainTargets` | array | List of domains you've scraped |
| `createdAt` | string | Account creation timestamp |
| `updatedAt` | string | Last account update timestamp |
**Checking Token Balance:** Use `tokenLimit - tokenUsage` to calculate your remaining tokens. Plan your scraping operations accordingly to avoid running out of tokens.
## Collect URLs from Website
Collect all relevant URLs from your target website using the AI scraper endpoint. You can select the Agent type you want to use from the example below:
### Initial Scrape using General Agent
#### Get All URL
Use the [`/scrapers-ai`](/docs/api/v3/scraper/ai-init) endpoint to create a [General agent](/docs/features/ai-scraper/general) scraper to get only the URLs within the provided link.
```bash
curl --location 'https://api.app.mrscraper.com/api/v1/scrapers-ai' \
--header 'accept: application/json' \
--header 'x-api-token: ' \
--header 'content-type: application/json' \
--data '{
"url": "https://books.toscrape.com",
"agent": "general",
"message": "Extract all data and just only get the urls, include patterns https://books.toscrape.com/catalogue and for exclude patterns https://books.toscrape.com/catalogue/category",
"proxyCountry": ""
}'
```
```javascript
const token = "MRSCRAPER_API_TOKEN";
fetch("https://api.app.mrscraper.com/api/v1/scrapers-ai", {
method: "POST",
headers: {
"accept": "application/json",
"x-api-token": token,
"content-type": "application/json"
},
body: JSON.stringify({
url: "https://books.toscrape.com",
agent: "general",
message: "Extract all data and just only get the urls, include patterns https://books.toscrape.com/catalogue and for exclude patterns https://books.toscrape.com/catalogue/category",
proxyCountry: ""
})
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
```
```python
import requests
token = "MRSCRAPER_API_TOKEN"
url = "https://api.app.mrscraper.com/api/v1/scrapers-ai"
headers = {
"accept": "application/json",
"x-api-token": token,
"content-type": "application/json"
}
payload = {
"url": "https://books.toscrape.com",
"agent": "general",
"message": "Extract all data and just only get the urls, include patterns https://books.toscrape.com/catalogue and for exclude patterns https://books.toscrape.com/catalogue/category",
"proxyCountry": ""
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
```
#### Get Page Details
After collecting URLs, you'll want to extract detailed data from each individual page.
When creating a detail scraper, always use a real detail page URL.
For example, instead of [https://books.toscrape.com](https://books.toscrape.com), use a specific product page like [https://books.toscrape.com/catalogue/a-light-in-the-attic\_1000/index.html](https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html) (from your URL collection step).
Do not use the homepage or listing page—this helps ensure accurate data extraction and prevents setup errors.
Create a new scraper configured for detail extraction:
```bash
curl --location 'https://api.app.mrscraper.com/api/v1/scrapers-ai' \
--header 'accept: application/json' \
--header 'x-api-token: ' \
--header 'content-type: application/json' \
--data '{
"url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"agent": "general",
"message": "Extract data : Title, Product Description, Price (Float), Availability, and Number of reviews",
"proxyCountry": ""
}'
```
```javascript
const token = "MRSCRAPER_API_TOKEN";
fetch("https://api.app.mrscraper.com/api/v1/scrapers-ai", {
method: "POST",
headers: {
"accept": "application/json",
"x-api-token": token,
"content-type": "application/json"
},
body: JSON.stringify({
url: "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
agent: "general",
message: "Extract data : Title, Product Description, Price (Float), Availability, and Number of reviews",
proxyCountry: ""
})
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
```
```python
import requests
token = "MRSCRAPER_API_TOKEN"
url = "https://api.app.mrscraper.com/api/v1/scrapers-ai"
headers = {
"accept": "application/json",
"x-api-token": token,
"content-type": "application/json"
}
payload = {
"url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"agent": "general",
"message": "Extract data : Title, Product Description, Price (Float), Availability, and Number of reviews",
"proxyCountry": ""
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
```
**Response (200 OK):**
```json
{
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"createdAt": "2026-01-18T08:37:38.124Z",
"userId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxx...",
"scraperId": "YOUR_DETAIL_SCRAPER_ID",
"type": "AI",
"url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"status": "Finished",
"tokenUsage": 5,
"data": {
"title": "A Light in the Attic",
"price": "£51.77",
"availability": "In stock (22 available)",
"description": "It's hard to imagine a world without A Light in the Attic...",
"number_of_reviews": "0"
}
}
```
**Request Parameters:**
| Parameter | Type | Required | Description |
| -------------- | ------ | -------- | ------------------------------------------------------------- |
| `url` | string | Yes | Target website URL to scrape |
| `agent` | string | Yes | AI agent to use (e.g., `general`, `listing`, `detail`, `map`) |
| `message` | string | Yes | Natural language instruction describing what to extract |
| `proxyCountry` | string | No | Proxy country code for geo-restricted content |
You'll need this ID (`YOUR_DETAIL_SCRAPER_ID` in this example) for bulk scraping multiple URLs with the same extraction configuration.
### Initial Scrape with Map Agent
Use the [`/scrapers-ai`](/docs/api/v3/scraper/ai-init) endpoint to create a Map agent scraper.
```bash
curl --location 'https://api.app.mrscraper.com/api/v1/scrapers-ai' \
--header 'accept: application/json' \
--header 'x-api-token: ' \
--header 'content-type: application/json' \
--data '{
"agent": "map",
"url": "https://books.toscrape.com",
"maxDepth": 2,
"maxPages": 100,
"limit": 1000,
"includePatterns": "^https:\\/\\/books\\.toscrape\\.com\\/catalogue$",
"excludePatterns": "^https:\\/\\/books\\.toscrape\\.com\\/catalogue\\/category$"
}'
```
```javascript
const token = "MRSCRAPER_API_TOKEN";
fetch("https://api.app.mrscraper.com/api/v1/scrapers-ai", {
method: "POST",
headers: {
"accept": "application/json",
"x-api-token": token,
"content-type": "application/json"
},
body: JSON.stringify({
agent: "map",
url: "https://books.toscrape.com",
maxDepth: 2,
maxPages: 100,
limit: 1000,
includePatterns: "^https:\\/\\/books\\.toscrape\\.com\\/catalogue$",
excludePatterns: "^https:\\/\\/books\\.toscrape\\.com\\/catalogue\\/category$"
})
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
```
```python
import requests
token = "MRSCRAPER_API_TOKEN"
url = "https://api.app.mrscraper.com/api/v1/scrapers-ai"
headers = {
"accept": "application/json",
"x-api-token": token,
"content-type": "application/json"
}
payload = {
"agent": "map",
"url": "https://books.toscrape.com",
"maxDepth": 2,
"maxPages": 100,
"limit": 1000,
"includePatterns": "^https:\\/\\/books\\.toscrape\\.com\\/catalogue$",
"excludePatterns": "^https:\\/\\/books\\.toscrape\\.com\\/catalogue\\/category$"
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
```
**Request Parameters:**
| Parameter | Type | Required | Description |
| ----------------- | ------ | -------- | ------------------------------------------------------- |
| `agent` | string | Yes | Must be `"map"` for map agent |
| `url` | string | Yes | Target website URL to scrape |
| `maxDepth` | number | Yes | Maximum depth to crawl (e.g., `2`) |
| `maxPages` | number | Yes | Maximum number of pages to crawl (e.g., `100`) |
| `limit` | number | Yes | Maximum number of URLs to collect (e.g., `1000`) |
| `includePatterns` | string | No | Regex pattern for URLs to include |
| `excludePatterns` | string | No | Regex pattern for URLs to exclude (can be empty string) |
**Response (200 OK):**
```json
{
"message": "Successful operation!",
"data": {
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxx...",
"createdAt": "2026-01-18T05:01:24.944Z",
"userId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxx...",
"scraperId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxx...",
"type": "AI",
"url": "https://books.toscrape.com",
"status": "Finished",
"error": null,
"tokenUsage": 5,
"data": {
"urls": [
"https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"https://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html",
"https://books.toscrape.com/catalogue/soumission_998/index.html",
...
]
}
}
}
```
You'll need this ID to re-run the scraper later without reconfiguring it.
### Bulk Scrape Multiple URLs
Use the [`/scrapers-ai-rerun/bulk`](/docs/api/v3/scraper/ai-rerun-bulk) endpoint to scrape multiple URLs in a single request:
The bulk endpoint is available only for the General agent.
```bash
curl --location 'https://api.app.mrscraper.com/api/v1/scrapers-ai-rerun/bulk' \
--header 'accept: application/json' \
--header 'x-api-token: ' \
--header 'content-type: application/json' \
--data '{
"scraperId": "YOUR_DETAIL_SCRAPER_ID",
"urls": [
"https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"https://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html",
"https://books.toscrape.com/catalogue/soumission_998/index.html",
...
]
}'
```
```javascript
const token = "MRSCRAPER_API_TOKEN";
const detailScraperId = "YOUR_DETAIL_SCRAPER_ID";
const urls = [
"https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"https://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html",
"https://books.toscrape.com/catalogue/soumission_998/index.html"
];
fetch("https://api.app.mrscraper.com/api/v1/scrapers-ai-rerun/bulk", {
method: "POST",
headers: {
"accept": "application/json",
"x-api-token": token,
"content-type": "application/json"
},
body: JSON.stringify({
scraperId: detailScraperId,
urls: urls
})
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
```
```python
import requests
token = "MRSCRAPER_API_TOKEN"
detail_scraper_id = "YOUR_DETAIL_SCRAPER_ID"
urls = [
"https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"https://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html",
"https://books.toscrape.com/catalogue/soumission_998/index.html",
...
]
url = "https://api.app.mrscraper.com/api/v1/scrapers-ai-rerun/bulk"
headers = {
"accept": "application/json",
"x-api-token": token,
"content-type": "application/json"
}
payload = {
"scraperId": detail_scraper_id,
"urls": urls
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
```
**Request Parameters:**
| Parameter | Type | Required | Description |
| ----------- | ------ | -------- | --------------------------------- |
| `scraperId` | string | Yes | The detail scraper ID from Step 4 |
| `urls` | array | Yes | Array of URLs to scrape |
**Response (200 OK):**
```json
{
"message": "Bulk scraping is Running",
"data": {
"bulkResultId": "YOUR_BULK_RESULT_ID"
}
}
```
Bulk scraping runs in the background. Save the `bulkResultId` to retrieve results later.
## Retrieve Results
There are two ways to retrieve scraping results: get a specific result by its ID, or get all results for a scraper.
### Get Single Result by Result ID
Use the [`/results/{id}`](/docs/api/v3/result/all) endpoint to get the latest single result using a specific `resultId` (the `id` field from the scrape response):
```bash
curl --location 'https://api.app.mrscraper.com/api/v1/results/YOUR_RESULT_ID' \
--header 'accept: application/json' \
--header 'x-api-token: '
```
```javascript
const token = "MRSCRAPER_API_TOKEN";
const resultId = "YOUR_RESULT_ID";
fetch(`https://api.app.mrscraper.com/api/v1/results/${resultId}`, {
method: "GET",
headers: {
"accept": "application/json",
"x-api-token": token
}
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
```
```python
import requests
token = "MRSCRAPER_API_TOKEN"
result_id = "YOUR_RESULT_ID"
url = f"https://api.app.mrscraper.com/api/v1/results/{result_id}"
headers = {
"accept": "application/json",
"x-api-token": token
}
response = requests.get(url, headers=headers)
print(response.json())
```
**Response (200 OK):**
```json
{
"message": "Successful operation!",
"data": {
"createdAt": "2026-01-18T07:28:44.725Z",
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxx...",
"userId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxx...",
"scraperId": "YOUR_SCRAPER_ID",
"type": "Rerun-AI",
"url": "https://books.toscrape.com",
"status": "Finished",
"error": "",
"tokenUsage": 4,
"data": {
"urls": [
"https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"https://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html",
"https://books.toscrape.com/catalogue/soumission_998/index.html",
...
]
},
"htmlPath": "results/.../page.html",
"screenshotPath": "results/.../page.jpg"
}
}
```
### Get All Results by Scraper ID
Use the [`/results`](/docs/api/v3/result/detail) endpoint to retrieve all historical results for a specific scraper with pagination:
```bash
curl --location --globoff 'https://api.app.mrscraper.com/api/v1/results?filters[scraperId]=YOUR_SCRAPER_ID&page=1&pageSize=10&sort=createdAt&sortOrder=DESC' \
--header 'accept: application/json' \
--header 'x-api-token: '
```
```javascript
const token = "MRSCRAPER_API_TOKEN";
const scraperId = "YOUR_SCRAPER_ID";
const params = new URLSearchParams({
'filters[scraperId]': scraperId,
'page': '1',
'pageSize': '10',
'sort': 'createdAt',
'sortOrder': 'DESC'
});
fetch(`https://api.app.mrscraper.com/api/v1/results?${params}`, {
method: "GET",
headers: {
"accept": "application/json",
"x-api-token": token
}
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
```
```python
import requests
token = "MRSCRAPER_API_TOKEN"
scraper_id = "YOUR_SCRAPER_ID"
url = "https://api.app.mrscraper.com/api/v1/results"
headers = {
"accept": "application/json",
"x-api-token": token
}
params = {
"filters[scraperId]": scraper_id,
"page": 1,
"pageSize": 10,
"sort": "createdAt",
"sortOrder": "DESC"
}
response = requests.get(url, headers=headers, params=params)
print(response.json())
```
**Query Parameters:**
| Parameter | Type | Required | Description |
| -------------------- | ------- | -------- | ------------------------------------ |
| `filters[scraperId]` | string | Yes | Filter results by scraper ID |
| `page` | integer | No | Page number (default: 1) |
| `pageSize` | integer | No | Results per page (default: 10) |
| `sort` | string | No | Field to sort by (e.g., `createdAt`) |
| `sortOrder` | string | No | Sort direction: `ASC` or `DESC` |
**Response (200 OK):**
```json
{
"message": "Successful fetch",
"data": [
{
"createdAt": "2026-01-18T07:28:44.725Z",
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxx...",
"scraperId": "YOUR_SCRAPER_ID",
"type": "Rerun-AI",
"url": "https://books.toscrape.com",
"status": "Finished",
"tokenUsage": 4,
"data": {
"urls": ["..."]
}
},
{
"createdAt": "2026-01-18T07:28:04.740Z",
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxx...",
"scraperId": "YOUR_SCRAPER_ID",
"type": "AI",
"url": "https://books.toscrape.com",
"status": "Finished",
"tokenUsage": 5,
"data": {
"urls": ["..."]
}
}
],
"meta": {
"page": 1,
"pageSize": 10,
"total": 2,
"totalPage": 1
}
}
```
### Retrieve Bulk Scraping Results
Bulk scraping is asynchronous, meaning you need to poll the results endpoint to check the status and retrieve the data when processing is complete.
```bash
curl --location 'https://api.app.mrscraper.com/api/v1/results/YOUR_BULK_RESULT_ID' \
--header 'accept: application/json' \
--header 'x-api-token: YOUR_API_TOKEN'
```
```javascript
const token = "YOUR_API_TOKEN";
const bulkResultId = "YOUR_BULK_RESULT_ID";
fetch(`https://api.app.mrscraper.com/api/v1/results/${bulkResultId}`, {
method: "GET",
headers: {
"accept": "application/json",
"x-api-token": token
}
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
```
```python
import requests
token = "MRSCRAPER_API_TOKEN"
bulk_result_id = "YOUR_BULK_RESULT_ID"
url = f"https://api.app.mrscraper.com/api/v1/results/{bulk_result_id}"
headers = {
"accept": "application/json",
"x-api-token": token
}
response = requests.get(url, headers=headers)
print(response.json())
```
**Response (Status: Running):**
```json
{
"message": "Successful operation!",
"data": {
"id": "YOUR_BULK_RESULT_ID",
"status": "Running",
"data": null
}
}
```
**Response (Status: Finished):**
```json
{
"message": "Successful operation!",
"data": {
"createdAt": "2026-01-18T08:38:23.993Z",
"id": "YOUR_BULK_RESULT_ID",
"userId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"scraperId": "YOUR_DETAIL_SCRAPER_ID",
"type": "Bulk-AI",
"status": "Finished",
"tokenUsage": 12,
"data": {
"mergedData": [
{
"title": "A Light in the Attic",
"price": "£51.77",
"availability": "In stock (22 available)",
"description": "It's hard to imagine a world without A Light in the Attic...",
"product_type": "Books",
"upc": "a897fe39b1053632",
"price_excl_tax": "£51.77",
"price_incl_tax": "£51.77",
"tax": "£0.00",
"number_of_reviews": "0"
},
{
"title": "Tipping the Velvet",
"price": "£53.74",
"availability": "In stock (20 available)",
"description": "Erotic and absorbing...Written with starling power...",
"product_type": "Books",
"upc": "90fa61229261140a",
"price_excl_tax": "£53.74",
"price_incl_tax": "£53.74",
"tax": "£0.00",
"number_of_reviews": "0"
},
{
"title": "Soumission",
"price": "£50.10",
"availability": "In stock (20 available)",
"description": "Dans une France assez proche de la nôtre...",
"product_type": "Books",
"upc": "6957f44c3847a760",
"price_excl_tax": "£50.10",
"price_incl_tax": "£50.10",
"tax": "£0.00",
"number_of_reviews": "0"
}
],
"urlDetails": [
{
"url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"status": "Finished",
"error": ""
},
{
"url": "https://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html",
"status": "Finished",
"error": ""
},
{
"url": "https://books.toscrape.com/catalogue/soumission_998/index.html",
"status": "Finished",
"error": ""
}
],
"summary": {
"totalUrls": 3,
"successfulUrls": 3,
"failedUrls": 0,
"totalTokenUsage": 12
}
}
}
}
```
**Key Response Fields:**
| Field | Type | Description |
| ----------------- | ------ | -------------------------------------------------- |
| `status` | string | Current status: `Running`, `Finished`, or `Failed` |
| `data.mergedData` | array | Array of extracted data from all URLs |
| `data.urlDetails` | array | Status details for each individual URL |
| `data.summary` | object | Summary statistics of the bulk operation |
## Re-run Scraper (Optional)
If you want to scrape the same website again with the same configuration, use the [`/scrapers-ai-rerun`](/docs/api/v3/scraper/ai-rerun) endpoint with your saved `scraperId`:
### Re-run General Agent
```bash
curl --location 'https://api.app.mrscraper.com/api/v1/scrapers-ai-rerun' \
--header 'accept: application/json' \
--header 'x-api-token: ' \
--header 'content-type: application/json' \
--data '{
"scraperId": "YOUR_SCRAPER_ID",
"url": "https://books.toscrape.com"
}'
```
```javascript
const token = "MRSCRAPER_API_TOKEN";
const scraperId = "YOUR_SCRAPER_ID";
fetch("https://api.app.mrscraper.com/api/v1/scrapers-ai-rerun", {
method: "POST",
headers: {
"accept": "application/json",
"x-api-token": token,
"content-type": "application/json"
},
body: JSON.stringify({
scraperId: scraperId,
url: "https://books.toscrape.com"
})
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
```
```python
import requests
token = "MRSCRAPER_API_TOKEN"
scraper_id = "YOUR_SCRAPER_ID"
url = "https://api.app.mrscraper.com/api/v1/scrapers-ai-rerun"
headers = {
"accept": "application/json",
"x-api-token": token,
"content-type": "application/json"
}
payload = {
"scraperId": scraper_id,
"url": "https://books.toscrape.com"
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
```
**Request Parameters:**
| Parameter | Type | Required | Description |
| ----------- | ------ | -------- | --------------------------------------- |
| `scraperId` | string | Yes | The scraper ID from your initial scrape |
| `url` | string | Yes | Target URL to scrape |
### Re-run Map Agent
When using a scraper with the **map** agent, you need to provide additional parameters, such as `includePatterns` and `excludePatterns`, to control URL filtering.
```bash
curl --location 'https://api.app.mrscraper.com/api/v1/scrapers-ai-rerun' \
--header 'accept: application/json' \
--header 'x-api-token: ' \
--header 'content-type: application/json' \
--data '{
"scraperId": "YOUR_SCRAPER_ID",
"url": "https://books.toscrape.com",
"maxDepth": 1,
"maxPages": 50,
"limit": 100,
"includePatterns": ["https://books.toscrape.com/catalogue"],
"excludePatterns": ["https://books.toscrape.com/catalogue/category"]
}'
```
```javascript
const token = "MRSCRAPER_API_TOKEN";
const scraperId = "YOUR_SCRAPER_ID";
fetch("https://api.app.mrscraper.com/api/v1/scrapers-ai-rerun", {
method: "POST",
headers: {
"accept": "application/json",
"x-api-token": token,
"content-type": "application/json"
},
body: JSON.stringify({
scraperId: scraperId,
url: "https://books.toscrape.com",
"scraperId": scraper_id,
"url": "https://books.toscrape.com",
maxDepth: 1,
maxPages: 50,
limit: 100,
includePatterns: ["https://books.toscrape.com/catalogue"],
excludePatterns: ["https://books.toscrape.com/catalogue/category"]
})
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
```
```python
import requests
token = "MRSCRAPER_API_TOKEN"
scraper_id = "YOUR_SCRAPER_ID"
url = "https://api.app.mrscraper.com/api/v1/scrapers-ai-rerun"
headers = {
"accept": "application/json",
"x-api-token": token,
"content-type": "application/json"
}
payload = {
"scraperId": scraper_id,
"url": "https://books.toscrape.com",
"maxDepth": 1,
"maxPages": 50,
"limit": 100,
"includePatterns": ["https://books.toscrape.com/catalogue"],
"excludePatterns": ["https://books.toscrape.com/catalogue/category"]
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
```
**Additional Map Agent Parameters:**
| Parameter | Type | Required | Description |
| ----------------- | --------- | -------- | ------------------------------------------------------- |
| `scraperId` | string | Yes | The scraper ID from your initial scrape |
| `url` | string | Yes | Target URL to scrape |
| `maxDepth` | number | Yes | Maximum depth to crawl (e.g., `2`) |
| `maxPages` | number | Yes | Maximum number of pages to crawl (e.g., `100`) |
| `limit` | number | Yes | Maximum number of URLs to collect (e.g., `1000`) |
| `includePatterns` | string\[] | No | Regex pattern for URLs to include |
| `excludePatterns` | string\[] | No | Regex pattern for URLs to exclude (can be empty string) |
> **Note:**\
> When "re-running" with a map agent, you can fine-tune which URLs will be crawled using `includePatterns` and `excludePatterns` while reusing your base scraper logic and configuration.
**Response (200 OK):**
```json
{
"message": "Successful operation!",
"data": {
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxx...",
"createdAt": "2026-01-18T07:28:44.725Z",
"userId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxx...,
"scraperId": "YOUR_SCRAPER_ID",
"type": "Rerun-AI",
"url": "https://books.toscrape.com",
"status": "Finished",
"error": "",
"tokenUsage": 4,
"data": {
"urls": [
"https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"https://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html",
"https://books.toscrape.com/catalogue/soumission_998/index.html",
...
]
},
"htmlPath": "results/.../page.html",
"screenshotPath": "results/.../page.jpg"
}
}
```
* You don’t need to create a new scraper from scratch every time you want to scrape a different—but structurally similar—website or page. If the data format and structure are the same, you can simply *re-run* your existing scraper and provide a new target URL.
* This works for every agents including map agent. For map agents, you can even update the URL and the include/exclude patterns before recreating a new scraper, saving you time and tokens. Try reusing your scrapers for maximum efficiency whenever your targets share the same page layout!
## Complete Workflow Example
Below is a full example that runs all steps in a single automated workflow:
```python
import requests
import json
import time
# Configuration
API_TOKEN = "MRSCRAPER_API_TOKEN"
BASE_URL = "https://api.app.mrscraper.com/api/v1"
headers = {
"accept": "application/json",
"x-api-token": API_TOKEN,
"content-type": "application/json"
}
def step1_verify_token():
"""Step 1: Verify API token and check account status"""
print("🔐 Step 1: Verifying API token...")
response = requests.get(
f"{BASE_URL}/subscription-accounts",
headers={"accept": "*/*", "x-api-token": API_TOKEN}
)
data = response.json()
if response.status_code == 200:
print(f"✓ Token valid! Tokens: {data['data']['tokenUsage']}/{data['data']['tokenLimit']}")
return True
else:
print(f"❌ Token verification failed: {data}")
return False
def step2_collect_urls(target_url, message):
"""Step 2: Create scraper and collect URLs"""
print(f"\n📍 Step 2: Collecting URLs from {target_url}...")
payload = {
"url": target_url,
"agent": "general",
"message": message,
"proxyCountry": ""
}
response = requests.post(f"{BASE_URL}/scrapers-ai", headers=headers, json=payload)
result = response.json()
# cache to a file
with open("step2_collect_urls_response.json", "w") as f:
json.dump(result, f, indent=2)
if "scraperId" in result.get("data", {}):
scraper_id = result["data"]["scraperId"]
print(f"✓ Scraping finished")
print(f"📋 URL Scraper ID: {scraper_id}")
return [], scraper_id
else:
print(f"❌ Failed: {result}")
return [], None
def step3_rerun_collect_urls(url, scraper_id):
"""Step 3: Rerun URL collection scraper"""
print(f"\n🔄 Step 3: Rerunning URL collection scraper {scraper_id}...")
payload = {
"scraperId": scraper_id,
"url": url
}
response = requests.post(f"{BASE_URL}/scrapers-ai-rerun/", headers=headers, json=payload)
result = response.json()
# cache to a file
with open("step3_rerun_collect_urls_response.json", "w") as f:
json.dump(result, f, indent=2)
if result.get("message") == "Successful operation!":
urls = result["data"]["data"]["urls"]
print(f"✓ Rerun collected {len(urls)} URLs")
return urls
else:
print(f"❌ Failed: {result}")
return []
def step4_create_detail_scraper(sample_url, message):
"""Step 4: Create detail scraper"""
print(f"\n🔧 Step 4: Creating detail scraper...")
payload = {
"url": sample_url,
"agent": "general",
"message": message,
"proxyCountry": ""
}
response = requests.post(f"{BASE_URL}/scrapers-ai", headers=headers, json=payload)
result = response.json()
# cache to a file
with open("step4_create_detail_scraper_response.json", "w") as f:
json.dump(result, f, indent=2)
if "scraperId" in result.get("data", {}):
scraper_id = result["data"]["scraperId"]
print(f"✓ Detail scraper created")
print(f"📋 Detail Scraper ID: {scraper_id}")
return scraper_id
else:
print(f"❌ Failed: {result}")
return None
def step5_bulk_scrape(scraper_id, urls):
"""Step 5: Bulk scrape all URLs"""
print(f"\n🤖 Step 5: Starting bulk scrape for {len(urls)} URLs...")
payload = {
"scraperId": scraper_id,
"urls": urls
}
response = requests.post(f"{BASE_URL}/scrapers-ai-rerun/bulk", headers=headers, json=payload)
result = response.json()
# cache to a file
with open("step5_bulk_scrape_response.json", "w") as f:
json.dump(result, f, indent=2)
bulk_result_id = result["data"]["bulkResultId"]
print(f"✓ Bulk scraping started")
print(f"📋 Bulk Result ID: {bulk_result_id}")
return bulk_result_id
def step6_get_results(bulk_result_id, poll_interval=10):
"""Step 6: Poll for results"""
print(f"\n⏳ Step 6: Waiting for results (polling every {poll_interval}s)...")
while True:
response = requests.get(
f"{BASE_URL}/results/{bulk_result_id}",
headers={"accept": "application/json", "x-api-token": API_TOKEN}
)
result = response.json()
status = result["data"]["status"]
if status == "Finished":
print("✅ Scraping completed!")
return result["data"]["data"]
elif status == "Running":
print(f" ⏳ Still running... checking again in {poll_interval}s")
time.sleep(poll_interval)
else:
print(f"❌ Error: {status}")
return None
# Main workflow
if __name__ == "__main__":
print("🚀 Starting N2N Programmatic Workflow\n")
print("=" * 60)
# Step 1: Verify token
if not step1_verify_token():
exit(1)
# Step 2: Collect URLs
url = "https://books.toscrape.com"
urls, url_scraper_id = step2_collect_urls(
url,
"Return array of urls that follow patterns https://books.toscrape.com/catalogue but exclude that has patterns https://books.toscrape.com/catalogue/category"
)
# Step 3: Rerun URL collection scraper
if url_scraper_id:
urls = step3_rerun_collect_urls(url, url_scraper_id)
if not urls:
exit(1)
# Use first 3 URLs for demo
urls = urls[:3]
print(f" Using {len(urls)} URLs for demo")
# Step 4: Create detail scraper
detail_scraper_id = step4_create_detail_scraper(
urls[0],
"Extract all data detail"
)
if not detail_scraper_id:
exit(1)
# Step 5: Bulk scrape
bulk_result_id = step5_bulk_scrape(detail_scraper_id, urls)
bulk_result_id = "a438e4c2-8489-4473-b405-6b4b5e18ed3f"
# Step 6: Get results
results = step6_get_results(bulk_result_id)
if results:
print("\n" + "=" * 60)
print("📊 RESULTS SUMMARY")
print("=" * 60)
print(f"✓ Total items: {len(results['mergedData'])}")
print(f"✓ Successful: {results['summary']['successfulUrls']}")
print(f"✓ Failed: {results['summary']['failedUrls']}")
print(f"✓ Tokens used: {results['summary']['totalTokenUsage']}")
print("\n📦 EXTRACTED DATA:")
print(json.dumps(results['mergedData'], indent=2))
```
```javascript
// Configuration
const API_TOKEN = "MRSCRAPER_API_TOKEN";
const BASE_URL = "https://api.app.mrscraper.com/api/v1";
const fs = require('fs').promises;
const headers = {
"accept": "application/json",
"x-api-token": API_TOKEN,
"content-type": "application/json"
};
// Step 1: Verify API token
async function step1VerifyToken() {
console.log("🔐 Step 1: Verifying API token...");
const response = await fetch(`${BASE_URL}/subscription-accounts`, {
headers: { "accept": "*/*", "x-api-token": API_TOKEN }
});
const data = await response.json();
if (response.ok) {
console.log(`✓ Token valid! Tokens: ${data.data.tokenUsage}/${data.data.tokenLimit}`);
return true;
}
console.log(`❌ Token verification failed:`, data);
return false;
}
// Step 2: Collect URLs
async function step2CollectUrls(targetUrl, message) {
console.log(`\n📍 Step 2: Collecting URLs from ${targetUrl}...`);
const response = await fetch(`${BASE_URL}/scrapers-ai`, {
method: "POST",
headers,
body: JSON.stringify({
url: targetUrl,
agent: "general",
message,
proxyCountry: ""
})
});
const result = await response.json();
// Cache to a file
await fs.writeFile("step2_collect_urls_response.json", JSON.stringify(result, null, 2));
if (result && 'scraperId' in (result.data || {})) {
const scraperId = result.data.scraperId;
console.log(`✓ Scraping finished`);
console.log(`📋 URL Scraper ID: ${scraperId}`);
return { urls: [], scraperId };
}
console.log(`❌ Failed:`, result);
return { urls: [], scraperId: null };
}
// Step 3: Rerun URL collection scraper
async function step3RerunCollectUrls(url, scraperId) {
console.log(`\n🔄 Step 3: Rerunning URL collection scraper ${scraperId}...`);
const response = await fetch(`${BASE_URL}/scrapers-ai-rerun/`, {
method: "POST",
headers,
body: JSON.stringify({
scraperId,
url
})
});
const result = await response.json();
// Cache to a file
await fs.writeFile("step3_rerun_collect_urls_response.json", JSON.stringify(result, null, 2));
if (result.message === "Successful operation!") {
const urls = result.data.data.urls;
console.log(`✓ Rerun collected ${urls.length} URLs`);
return urls;
}
console.log(`❌ Failed:`, result);
return [];
}
// Step 4: Create detail scraper
async function step4CreateDetailScraper(sampleUrl, message) {
console.log(`\n🔧 Step 4: Creating detail scraper...`);
const response = await fetch(`${BASE_URL}/scrapers-ai`, {
method: "POST",
headers,
body: JSON.stringify({
url: sampleUrl,
agent: "general",
message,
proxyCountry: ""
})
});
const result = await response.json();
// Cache to a file
await fs.writeFile("step4_create_detail_scraper_response.json", JSON.stringify(result, null, 2));
if (result && 'scraperId' in (result.data || {})) {
const scraperId = result.data.scraperId;
console.log(`✓ Detail scraper created`);
console.log(`📋 Detail Scraper ID: ${scraperId}`);
return scraperId;
}
console.log(`❌ Failed:`, result);
return null;
}
// Step 5: Bulk scrape
async function step5BulkScrape(scraperId, urls) {
console.log(`\n🤖 Step 5: Starting bulk scrape for ${urls.length} URLs...`);
const response = await fetch(`${BASE_URL}/scrapers-ai-rerun/bulk`, {
method: "POST",
headers,
body: JSON.stringify({ scraperId, urls })
});
const result = await response.json();
// Cache to a file
await fs.writeFile("step5_bulk_scrape_response.json", JSON.stringify(result, null, 2));
const bulkResultId = result.data.bulkResultId;
console.log(`✓ Bulk scraping started`);
console.log(`📋 Bulk Result ID: ${bulkResultId}`);
return bulkResultId;
}
// Step 6: Get results with polling
async function step6GetResults(bulkResultId, pollInterval = 10000) {
console.log(`\n⏳ Step 6: Waiting for results (polling every ${pollInterval/1000}s)...`);
while (true) {
const response = await fetch(`${BASE_URL}/results/${bulkResultId}`, {
headers: { "accept": "application/json", "x-api-token": API_TOKEN }
});
const result = await response.json();
const status = result.data.status;
if (status === "Finished") {
console.log("✅ Scraping completed!");
return result.data.data;
} else if (status === "Running") {
console.log(` ⏳ Still running... checking again in ${pollInterval/1000}s`);
await new Promise(r => setTimeout(r, pollInterval));
} else {
console.log(`❌ Error: ${status}`);
return null;
}
}
}
// Main workflow
(async () => {
console.log("🚀 Starting N2N Programmatic Workflow\n");
console.log("=".repeat(60));
// Step 1: Verify token
if (!await step1VerifyToken()) {
process.exit(1);
}
// Step 2: Collect URLs
const url = "https://books.toscrape.com";
const { urls: initialUrls, scraperId: urlScraperId } = await step2CollectUrls(
url,
"Return array of urls that follow patterns https://books.toscrape.com/catalogue but exclude that has patterns https://books.toscrape.com/catalogue/category"
);
// Step 3: Rerun URL collection scraper
let urls = [];
if (urlScraperId) {
urls = await step3RerunCollectUrls(url, urlScraperId);
}
if (!urls.length) {
process.exit(1);
}
// Use first 3 URLs for demo
urls = urls.slice(0, 3);
console.log(` Using ${urls.length} URLs for demo`);
// Step 4: Create detail scraper
const detailScraperId = await step4CreateDetailScraper(
urls[0],
"Extract all data detail"
);
if (!detailScraperId) {
process.exit(1);
}
// Step 5: Bulk scrape
let bulkResultId = await step5BulkScrape(detailScraperId, urls);
// Optional: Uncomment to use a specific bulk result ID
// bulkResultId = "a438e4c2-8489-4473-b405-6b4b5e18ed3f";
// Step 6: Get results
const results = await step6GetResults(bulkResultId);
if (results) {
console.log("\n" + "=".repeat(60));
console.log("📊 RESULTS SUMMARY");
console.log("=".repeat(60));
console.log(`✓ Total items: ${results.mergedData.length}`);
console.log(`✓ Successful: ${results.summary.successfulUrls}`);
console.log(`✓ Failed: ${results.summary.failedUrls}`);
console.log(`✓ Tokens used: ${results.summary.totalTokenUsage}`);
console.log("\n📦 EXTRACTED DATA:");
console.log(JSON.stringify(results.mergedData, null, 2));
}
})();
```
# Real Estate
import { Step, Steps } from 'fumadocs-ui/components/steps';
Real estate professionals, investors, and analysts can use MrScraper to collect property listings from public real estate websites. Instead of checking hundreds of listings manually, the AI Scraper extracts property details for you using only a URL and a short prompt.
Let's walk through a **real-world example** where you can uses MrScraper to collect data from a live property listing site.
## Scenario
You want to explore the Michigan housing market and compare prices, home sizes, and features across different cities. Rather than visiting multiple listing sites every day, you can use MrScraper to pull structured data directly from Redfin, making it easier to review options and find the best value.
## Create a New AI Scraper
1. Go to the **Scrapers** page by clicking the **triangle icon** on the left sidebar.
2. Click on the **Create AI Scraper +** button.
3. Select the **Listing Scraper** option.
4. In the **URL** field, enter the URL of the Michigan property listings page: `https://www.redfin.com/state/Michigan`.
5. Click on the **Start Scraping** button to start scraping.
**Result :**
```json title="Scraping Result"
{
"mode": "direct",
"properties": [
{
"address": "319 Saint Lawrence Blvd, Northville, MI 48168",
"url": "/MI/Northville/319-Saint-Lawrence-Blvd-48168/home/98741962",
"price": "$510,000",
"beds": "3 beds",
"baths": "3.5 baths",
"sqft": "3,246",
"status": "NEW 10 HRS AGO"
},
{
"address": "20137 W Whipple Dr, Northville, MI 48167",
"url": "/MI/Northville/20137-W-Whipple-Dr-48167/home/75119625",
"price": "$799,900",
"beds": "— beds",
"baths": "— baths",
"sqft": "—",
"status": "NEW 10 HRS AGO"
},
{
"address": "49776 Parkside Dr, Northville, MI 48168",
"url": "/MI/Northville/49776-Parkside-Dr-48168/home/98891697",
"price": "$699,900",
"beds": "4 beds",
"baths": "3.5 baths",
"sqft": "4,492",
"status": "NEW 14 HRS AGO"
},
{
"address": "58543 Navarra Dr, South Lyon, MI 48178",
"url": "/MI/South-Lyon/58543-Navarra-Dr-48178/home/191274082",
"price": "$619,990",
"beds": "5 beds",
"baths": "3 baths",
"sqft": "3,011",
"status": "OPEN SAT, 11:30AM TO 2PM"
},
{
"address": "15943 Morningside, Northville, MI 48168",
"url": "/MI/Northville/15943-Morningside-48168/home/98892034",
"price": "$273,000",
"beds": "2 beds",
"baths": "2 baths",
"sqft": "1,653"
},
{
...
}
],
"total_count": 63,
"links": [
"/MI/Ann-Arbor/1670-W-Ellsworth-Rd-48108/home/99335852",
"/MI/Ann-Arbor/1702-Hill-St-48104/home/99308587",
"/MI/Ann-Arbor/2134-Overlook-Ct-48103/home/99356641",
"/MI/Ann-Arbor/3250-Brackley-Dr-48105/home/143963798",
"/MI/Ann-Arbor/3341-Roseford-Blvd-48105/home/143963723",
"..."
]
}
```
## Filter Out
Tell the AI to filter the scraped results based on specific criteria. For this example, let's filter for smaller, more affordable properties under 2,000 square feet using the following prompt:
```md
Get only properties with less than 2000 square feet
```
Here’s a sample output:
```json title="Filtered Scraping Result"
{
"mode": "direct",
"count": 28,
"properties": [
{
"beds": "2 beds",
"link": "/MI/Northville/15943-Morningside-48168/home/98892034",
"sqft": 1653,
"baths": "2 baths",
"price": "$273,000",
"address": "15943 Morningside, Northville, MI 48168"
},
{
"beds": "3 beds",
"link": "/MI/Northville/9824-Hathaway-Dr-48167/home/99341712",
"sqft": 1000,
"baths": "2 baths",
"price": "$55,000",
"address": "9824 Hathaway Dr, Northville, MI 48167"
},
{
"beds": "2 beds",
"link": "/MI/Northville/42432-Corlina-Dr-48167/home/98883824",
"sqft": 1800,
"baths": "2.5 baths",
"price": "$350,000",
"address": "42432 Corlina Dr, Northville, MI 48167"
},
{
"beds": "2 beds",
"link": "/MI/Novi/39928-Crosswinds-48375/home/61133922",
"sqft": 1100,
"baths": "1.5 baths",
"price": "$210,000",
"address": "39928 Crosswinds, Novi, MI 48375 5004"
},
{
"beds": "3 beds",
"link": "/MI/Novi/22415-Cranbrooke-Dr-48375/home/199166800",
"sqft": 1304,
"baths": "1.5 baths",
"price": "$249,999",
"address": "22415 Cranbrooke Dr, Novi, MI 48375 4502"
},
{
...
}
]
}
```
## Use the Data
The results include smaller homes and condos across cities like Detroit, Ann Arbor, Livonia, Troy, Farmington, Novi, and Northville — making it easy to compare options side by side.
# Sentiment Analysis
import { Step, Steps } from 'fumadocs-ui/components/steps';
Sentiment analysis is a powerful tool for understanding public opinion, customer feedback, and market trends.
## Scenario
You’re a product manager at a laptop company competing with another brand.\
You want to understand what customers think about one of the competitor’s brand gaming laptops available on **Walmart**.\
By analyzing reviews, you can identify what users appreciate (e.g., performance, design) and what frustrates them (e.g., setup issues, reliability).
## Create a New AI Scraper
1. Go to the **Scrapers** page by clicking the **triangle icon** on the left sidebar.
2. Click on the **Create AI Scraper +** button.
3. In the **Target URL** field, enter the URL of the product's review page you want to scrape. For example: `https://www.walmart.com/reviews/product/15843466879?entryPoint=viewAllReviewsTop`.
4. Click on the **Start Scraping** button to start scraping.
**Result :**
```json title="Scraping Result"
{
"reviews": [
{
"date": "Jul 28, 2025",
"text": "Our son ordered this and he is very happy with how it helps him play video games. Can't say I love that he does that, but he said it really does improve the quality and availability of games for him, and he's pretty good about limiting his own time on devices.",
"rating": 5,
"reviewer": "WalmartCustomer"
},
{
"date": "Jul 31, 2025",
"text": "It was a gift for my daughter and she absolutely loves it! Loves it so much I bought a second one for my other daughter so they could play their games together. Great computer for gamers.",
"rating": 5,
"reviewer": "WalmartCustomer"
},
{
"date": "Sep 5, 2025",
"text": "To start, it's an awesome laptop. It fit my budget and can play games and do school work when I need it to. One pay made it very easy to get it without having to spend too much at once (I'm a broke college student). My order also arrived faster than the estimated time which was already pretty quick. Not only that but I got it at a cheap price on clearance.",
"rating": 5,
"reviewer": "WalmartCustomer"
},
{
"date": "Sep 4, 2025",
"text": "It never fails, really. I always seem to be on the receiving end of crappy products. I JUST got this thing TODAY and I can't even get it to setup! Persistent error messages 'Something went wrong' yadayada. This review is staying all the way bad until I get my money back or some reliable customer support cause this is not okay.",
"rating": 1,
"reviewer": "Dominic"
}
]
}
```
## Analyze Sentiment with AI
You can now analyze the sentiment of the extracted user reviews using your preferred AI tool or library. For example, you can use Python's `TextBlob` or `VADER` to classify the sentiment of each review as positive, negative, or neutral.
| Sentiment | Example Review | Insight |
| --------- | -------------------------------------------------------------------------- | ---------------------------------------------------------- |
| Positive | “Great computer for gamers.” | Strong satisfaction with performance |
| Positive | “Awesome laptop... plays games and does school work.” | Product fits well for multitasking |
| Negative | “I JUST got this thing TODAY and I can’t even get it to setup!” | Setup/reliability issues |
| Neutral | “Our son ordered this... he’s happy but I don’t love that he plays games.” | Mixed sentiment; happy performance but concern over gaming |
# Flight Price
import { Step, Steps } from 'fumadocs-ui/components/steps';
Instead of checking flight prices across multiple websites, you can use the AI Scraper to pull flight details, prices, and schedules automatically using only a URL and a short prompt.
Here’s a real-world example of how you can use MrScraper to collect live flight data from a booking site.
## Scenario
You’re building a flight price comparison tool or tracking prices for popular routes.
In this example, you want to monitor flights from New York City to London so travelers can quickly find the best deals.
## Create a New AI Scraper
1. Go to the **Scrapers** page by clicking the **triangle icon** on the left sidebar.
2. Click on the **Create AI Scraper +** button.
3. Select the **Listing Scraper** option.
4. In the **URL** field, enter the URL of the flight search results page. For this example, we'll search for flights from New York City (NYC) to London (LON):
```txt
https://id.trip.com/m/flights/xflightfirst/?triptype=0&classtype=0&classgroupsearch=true&adult=1&child=0&infant=0&from=searchForm&stoptype=0&lowpricesource=searchForm&ddate=2025-11-22&dcitycode=NYC&acitycode=LON&locale=en-ID&curr=IDR&transactionid=20251120174344105
```
5. Click on the **Start Scraping** button to start scraping.
**Result :**
```json title="Scraping Result"
{
"mode": "direct",
"links": [
"flight_card_4",
"flight_card_3",
"flight_card_1",
"flight_card_2",
"flight_card_5"
],
"flights": [
{
"price": "Rp4,960,870",
"airline": "Jetblue Airways",
"aircraft": "Airbus A321neo",
"duration": "7h 21m",
"top_label": "Cheapest nonstop",
"arrival_time": "09:30",
"price_numeric": "4960870",
"departure_time": "21:09",
"original_price": "Rp 5,097,750",
"arrival_airport": "LHR T2",
"next_day_arrival": "+1",
"departure_airport": "JFK T5",
"low_stock_warning": null,
"original_price_numeric": "5097750",
"carry_on_baggage_included": false
},
{
"price": "Rp5,051,840",
"airline": "Jetblue Airways",
"aircraft": "Airbus A321neo",
"duration": "7h 1m",
"top_label": null,
"arrival_time": "22:00",
"price_numeric": "5051840",
"departure_time": "09:59",
"original_price": "Rp 5,191,430",
"arrival_airport": "LHR T2",
"next_day_arrival": null,
"departure_airport": "JFK T5",
"low_stock_warning": null,
"original_price_numeric": "5191430",
"carry_on_baggage_included": false
},
{
"price": "Rp7,248,600",
"airline": "United Airlines",
"aircraft": "Boeing 767-300/300ER",
"duration": "7h 20m",
"top_label": null,
"arrival_time": "06:20",
"price_numeric": "7248600",
"departure_time": "18:00",
"original_price": "Rp 7,453,760",
"arrival_airport": "LHR T2",
"next_day_arrival": "+1",
"departure_airport": "EWR C",
"low_stock_warning": "<5 left",
"original_price_numeric": "7453760",
"carry_on_baggage_included": true
},
{
"price": "Rp7,287,450",
"airline": "American Airlines",
"aircraft": "Boeing 777-300ER",
"duration": "6h 50m",
"top_label": null,
"arrival_time": "09:40",
"price_numeric": "7287450",
"departure_time": "21:50",
"original_price": "Rp 7,493,770",
"arrival_airport": "LHR T3",
"next_day_arrival": "+1",
"departure_airport": "JFK T8",
"low_stock_warning": null,
"original_price_numeric": "7493770",
"carry_on_baggage_included": true
},
{
"price": "Rp7,431,410",
"airline": "Austrian Airlines (Codeshare)",
"aircraft": "Boeing 767-300/300ER",
"duration": "7h 20m",
"top_label": null,
"arrival_time": "06:20",
"price_numeric": "7431410",
"departure_time": "18:00",
"original_price": "Rp 7,642,020",
"arrival_airport": "LHR T2",
"next_day_arrival": "+1",
"departure_airport": "EWR C",
"low_stock_warning": "<5 left",
"original_price_numeric": "7642020",
"carry_on_baggage_included": true
}
],
"total_flights": 5
}
```
## Filter Out
Tell the AI to filter your scraped results based on specific rules. In this example, we filter for flights under Rp 6,000,000 using the following prompt:
```md
Get only flight with cost less than Rp 6.000.000
```
Here’s a sample output:
```json title="Filtered Scraping Result"
{
"mode": "direct",
"count": 2,
"flights": [
{
"price": "Rp4,960,870",
"airline": "Jetblue Airways",
"aircraft": "Airbus A321neo",
"duration": "7h 21m",
"arrival_time": "09:30",
"price_numeric": 4960870,
"departure_time": "21:09",
"arrival_airport": "LHR T2",
"departure_airport": "JFK T5"
},
{
"price": "Rp5,051,840",
"airline": "Jetblue Airways",
"aircraft": "Airbus A321neo",
"duration": "7h 1m",
"arrival_time": "22:00",
"price_numeric": 5051840,
"departure_time": "09:59",
"arrival_airport": "LHR T2",
"departure_airport": "JFK T5"
}
]
}
```
### Step 3: Use the Data
You can now use this clean flight data for price tracking, comparison tools, or travel apps. Filtering helps budget travelers quickly find the cheapest options.
# ClawHub
import { Step, Steps } from 'fumadocs-ui/components/steps';
## ClawHub Integration
[ClawHub](https://clawhub.ai/) is a marketplace of skills and plugins for OpenClaw agents. Skills extend an agent's capabilities across research, integrations, and automation, and are installed from a central registry.
The [**MrScraper skill**](https://clawhub.ai/ai-mrscraper/skills/mrscraper) lets your agent run AI-powered, unblockable web scraping and data extraction using natural language, backed by the MrScraper API.
## Overview
Once installed, your agent can:
* **Unblock pages**: Retrieve HTML from sites that block ordinary requests, using a stealth browser and IP rotation.
* **Create AI scrapers**: Turn a natural-language instruction into a working scraper.
* **Rerun scrapers**: Apply an existing scraper configuration to new URLs, one at a time or in bulk.
* **Run manual scrapers**: Execute browser workflows built from selectors.
* **Fetch results**: Retrieve scrape results, paginated or by ID.
The skill makes direct HTTPS calls to the MrScraper API. There are no bundled scripts and no local installation step beyond installing the skill itself.
## Prerequisites
* An **OpenClaw agent** with the `openclaw` CLI available.
* A [**MrScraper API token**](https://app.mrscraper.com/api-tokens).
## Installation
### Install the skill
```bash
openclaw skills install @ai-mrscraper/mrscraper
```
### Create a MrScraper API token
1. Open the [MrScraper dashboard](https://app.mrscraper.com/).
2. Click your user profile in the top-right corner.
3. Select **API Tokens**.
4. Click **New Token**.
5. Enter a name and an expiration date.
6. Click **Create** and copy the token.
### Store the token
Expose the token to your agent as the `MRSCRAPER_API_TOKEN` environment variable.
```bash
export MRSCRAPER_API_TOKEN="your-token-here"
```
Never expose your API token in client-side code, logs, or commits. Store it in an environment variable or a server-side secret manager.
## Authentication
Every request the skill makes carries these headers:
```http
x-api-token:
accept: application/json
content-type: application/json
```
MrScraper exposes two base URLs:
| API | Base URL | Purpose |
| --------- | ------------------------------- | -------------------------------------------- |
| Unblocker | `https://api.mrscraper.com` | Fetch HTML from blocked pages |
| Platform | `https://api.app.mrscraper.com` | Create, rerun, and read scrapers and results |
## Available Endpoints
### Unblocker
Opens blocked pages using a stealth browser and IP rotation, and returns the page content.
```bash
curl 'https://api.mrscraper.com?url=https%3A%2F%2Fexample.com&timeout=120&geoCode=SG' \
-H "x-api-token: "
```
| Parameter | Required | Default | Description |
| ---------------- | -------- | ------- | ------------------------------------------------ |
| `url` | Yes | — | The target URL, URL-encoded. |
| `timeout` | No | `60` | Maximum seconds to wait for the page to load. |
| `geoCode` | No | — | ISO country code for proxy routing. |
| `blockResources` | No | — | Block images, CSS, and fonts for faster loading. |
### Create AI Scraper
Creates a scraper from a natural-language instruction and runs it.
```bash
curl -X POST "https://api.app.mrscraper.com/api/v1/scrapers-ai" \
-H "x-api-token: " \
-H "Content-Type: application/json" \
-d '{
"url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"message": "Extract title, price, stocks, and rating",
"agent": "general"
}'
```
**Agent types:**
| Agent | Description |
| --------- | ------------------------------------------------------------------------------------ |
| `general` | Standard pages such as product details, articles, and profiles. This is the default. |
| `listing` | Product listings, job boards, search results, and other paginated collections. |
| `map` | Website crawling that follows links to discover pages. |
### Rerun AI Scraper
Applies an existing scraper configuration to a new URL.
```bash
curl -X POST "https://api.app.mrscraper.com/api/v1/scrapers-ai-rerun" \
-H "x-api-token: " \
-H "Content-Type: application/json" \
-d '{
"scraperId": "6695bf87-aaa6-46b0-b1ee-88586b222b0b",
"url": "https://shopee.sg/"
}'
```
### Bulk Rerun AI Scraper
Runs one scraper configuration across multiple URLs in a single request.
```bash
curl -X POST "https://api.app.mrscraper.com/api/v1/scrapers-ai-rerun/bulk" \
-H "x-api-token: " \
-H "Content-Type: application/json" \
-d '{
"scraperId": "6695bf87-aaa6-46b0-b1ee-88586b222b0b",
"urls": [
"https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"https://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html"
]
}'
```
### Manual Scraper Rerun
Executes a browser workflow built from selectors, for cases where you want explicit extraction rules instead of AI.
```bash
curl -X POST "https://api.app.mrscraper.com/api/v1/scrapers-manual-rerun" \
-H "x-api-token: " \
-H "Content-Type: application/json" \
-d '{
"scraperId": "6695bf87-aaa6-46b0-b1ee-88586b222b0b",
"url": "https://books.toscrape.com/",
"workflow": [
{
"type": "extract",
"data": {
"extraction_type": "text",
"name": "book",
"selector": "h3 a"
}
}
]
}'
```
### Fetch Results
Returns paginated scrape results.
```bash
curl -X GET "https://api.app.mrscraper.com/api/v1/results?sortField=updatedAt&sortOrder=DESC&page=1&pageSize=10" \
-H "x-api-token: "
```
### Fetch Result by ID
Returns the detail of a single result.
```bash
curl -X GET "https://api.app.mrscraper.com/api/v1/results/497f6eca-6276-4993-bfeb-53cbbbba6f08" \
-H "x-api-token: "
```
## Map Agent Configuration
When you use the `map` agent, these parameters control how the crawl behaves:
| Parameter | Description |
| ----------------- | --------------------------------------------------------------------------- |
| `maxDepth` | How many levels of links to follow. A value of 1–2 is recommended. |
| `maxPages` | Maximum number of pages to crawl. |
| `limit` | Maximum number of records to extract. |
| `includePatterns` | Regex patterns for URLs to include. Separate multiple patterns with `\|\|`. |
| `excludePatterns` | Regex patterns for URLs to exclude. Separate multiple patterns with `\|\|`. |
Set `maxDepth` to 1 or 2 and cap `maxPages`. Depth grows the crawl exponentially, and an unbounded crawl burns tokens fast.
## Error Handling
The API uses standard HTTP status codes:
| Status | Meaning |
| ------ | ----------------------------- |
| `400` | Invalid request payload. |
| `401` | Missing or invalid API token. |
| `404` | Resource not found. |
| `429` | Rate limit exceeded. |
| `500` | Internal error. |
Retry `429` responses with exponential backoff.
## Data Scope
Data is transmitted only to MrScraper servers. Responses contain the extracted page content and its metadata. Never expose your API token in logs or commits.
# Email
import { Mail, Cog } from 'lucide-react';
import { Step, Steps } from 'fumadocs-ui/components/steps';
## What Are Email Connections?
Email connections let you receive an email notification when specific events happen in your scraper, such as when a scrape starts, completes, or fails.
## Key Features
} title="Instant Notifications">
Get real-time updates on your scraper's status directly in your inbox.
} title="Customizable Alerts">
Choose which events you want to be notified about, such as completion or errors.
## Create an Email Connection
There are two ways to create an email connection in MrScraper:
### 1. Scraper
Select the **scraper** that you want to add an email connection.
**Scraper page** -> **Ellipsis** ( **⋮** ) button -> **Email Notifications** -> **Add new Email Connection**.
**Email Connection page** -> **+ icon** in the top-right corner.
Fill in the email connection details:
* **Email Address**: The email address to which the notification should be sent
Click **Submit** to save your email connection.
### 2. Settings
Open your **MrScraper dashboard**.
Click the **gear icon** -> select **Email Connection**.
**Email Connection page** -> + icon in the top-right corner.
Fill in the email connection details:
* **Email Address**: The email address to which the notification should be sent
Click **Submit** to save your email connection.
## Connect Email Notification to Scraper
After creating the email connection, follow these steps to connect it to your scraper:
Go to your chosen **Scraper** page.
Click the **Ellipsis** ( **⋮** ) button and click **Email Notifications**.
Select the email connection you just created from the dropdown menu.
Click **Save Email Notifications**.
## Example Result
Once the scraper finished, you will receive an email notification. Depending on the email type you selected, the email will contain either the result in the email body or as an attachment. Here's an example of what the email might look like:
# LangChain SDK
The [langchain-mrscraper](https://pypi.org/project/langchain-mrscraper/) package exposes the MrScraper API as LangChain `BaseTool` instances, enabling AI agents to fetch rendered HTML, create and rerun scrapers, and retrieve results. The SDK client (`mrscraper-sdk`) is installed as a dependency.
This integration provides **tools** that agents can explicitly call—not a document loader. For deterministic "URL → documents" ingestion into vector stores, a document loader is typically a better fit. MrScraper may offer that in a separate package later.
## Requirements
* **Python 3.9 or higher**
* LangChain ecosystem packages (installed as dependencies)
See [langchain-mrscraper on PyPI](https://pypi.org/project/langchain-mrscraper/) for the latest release, version history, and installation details.
## Installation
Install the package from PyPI using pip:
```bash
pip install -U langchain-mrscraper
```
This installs both the LangChain integration and the underlying MrScraper SDK client.
## Authentication
Set your API token from the [MrScraper dashboard](/docs/getting-started/api-token) as an environment variable:
```python
import os
os.environ["MRSCRAPER_API_TOKEN"] = "MRSCRAPER_API_TOKEN"
```
You can authenticate in three ways:
1. **Environment variable** (recommended): `MRSCRAPER_API_KEY` or `MRSCRAPER_API_TOKEN`
2. **Toolkit parameter**: `MrScraperToolkit(token="...")`
3. **Function parameter**: `load_mrscraper_tools(mrscraper_api_key="...")`
For more information on generating API tokens, see the [Generate Token](/docs/getting-started/api-token) guide.
## Quick Start
### Using MrScraperToolkit
Load all available tools with the toolkit:
```python
from langchain_mrscraper import MrScraperToolkit
# Using environment variable
tools = MrScraperToolkit().get_tools()
# Or with explicit token
tools = MrScraperToolkit(token="MRSCRAPER_API_TOKEN").get_tools()
```
### Using Convenience Loader
Alternatively, use the convenience function:
```python
from langchain_mrscraper import load_mrscraper_tools
tools = load_mrscraper_tools()
```
### Using with AI Agents
```python
from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI
from langchain_mrscraper import MrScraperToolkit
# Load MrScraper tools
tools = MrScraperToolkit(token="MRSCRAPER_API_TOKEN").get_tools()
# Create agent with OpenAI
agent = create_react_agent(ChatOpenAI(model="gpt-4o-mini"), tools)
# Use the agent
response = agent.invoke({
"messages": [{"role": "user", "content": "Fetch the HTML from https://example.com"}]
})
```
This example requires `langgraph` and `langchain-openai` packages:
```bash
pip install langgraph langchain-openai
```
## Core Methods
The examples below demonstrate each tool individually. Replace placeholders like scraper and result IDs with values from your dashboard or prior API responses.
### Fetch Raw HTML
Fetch fully rendered HTML after JavaScript execution using the stealth browser.
```python
from langchain_mrscraper import load_mrscraper_tools
fetch_html, = load_mrscraper_tools(
token="MRSCRAPER_API_TOKEN",
tool_names=["mrscraper_fetch_html"],
)
output = fetch_html.invoke(
{
"url": "https://example.com/page",
"timeout": 120,
"geo_code": "US",
"block_resources": False,
}
)
print(output)
```
**Parameters:**
| Parameter | Type | Required | Default | Description |
| ----------------- | ------- | -------- | ------- | ----------------------------------------------- |
| `url` | string | Yes | - | Full URL to load |
| `timeout` | integer | No | `120` | Maximum seconds to wait for page load |
| `geo_code` | string | No | `"US"` | Two-letter proxy country code |
| `block_resources` | boolean | No | `False` | Block images, CSS, and fonts for faster loading |
### Create AI Scraper
Create and run an AI scraper using natural language instructions.
```python
from langchain_mrscraper import load_mrscraper_tools
create, = load_mrscraper_tools(
token="MRSCRAPER_API_TOKEN",
tool_names=["mrscraper_create_scraper"],
)
output = create.invoke(
{
"url": "https://example.com/products",
"message": "Extract product names, prices, and ratings.",
"agent": "listing", # "general" | "listing" | "map"
"proxy_country": "US",
"max_depth": 2,
"max_pages": 50,
"limit": 1000,
"include_patterns": "",
"exclude_patterns": "",
}
)
print(output)
```
**Parameters:**
| Parameter | Type | Required | Default | Description |
| ------------------ | ------- | -------- | ----------- | ------------------------------------------------- |
| `url` | string | Yes | - | Target URL to scrape |
| `message` | string | Yes | - | Natural language extraction instructions |
| `agent` | string | No | `"general"` | Agent type: `"general"`, `"listing"`, or `"map"` |
| `proxy_country` | string | No | - | Two-letter country code for proxy |
| `max_depth` | integer | No | `2` | For map agent: link depth to follow |
| `max_pages` | integer | No | `50` | For map/listing agents: maximum pages to scrape |
| `limit` | integer | No | `1000` | For map agent: maximum results to return |
| `include_patterns` | string | No | `""` | For map agent: regex patterns for URLs to include |
| `exclude_patterns` | string | No | `""` | For map agent: regex patterns for URLs to exclude |
**Agent Types:**
| Agent | Best For |
| ----------- | --------------------------------------------- |
| `"general"` | Single pages, product details, articles |
| `"listing"` | Product listings, search results, directories |
| `"map"` | Site crawling, URL discovery, sitemaps |
For detailed information on agents, see [AI Scraper Agents](/docs/features/ai-scraper#ai-scraper-agents).
### Rerun AI Scraper
Rerun an existing AI scraper on a new URL without creating a new scraper configuration.
```python
from langchain_mrscraper import load_mrscraper_tools
rerun_ai, = load_mrscraper_tools(
token="MRSCRAPER_API_TOKEN",
tool_names=["mrscraper_rerun_ai_scraper"],
)
output = rerun_ai.invoke(
{
"scraper_id": "YOUR_AI_SCRAPER_ID",
"url": "https://example.com/another-page",
"max_depth": 2,
"max_pages": 50,
"limit": 1000,
"include_patterns": "",
"exclude_patterns": "",
}
)
print(output)
```
**Parameters:**
| Parameter | Type | Required | Description |
| ------------------ | ------- | -------- | ----------------------------------------------- |
| `scraper_id` | string | Yes | ID of the existing AI scraper |
| `url` | string | Yes | New URL to scrape |
| `max_depth` | integer | No | For map agents: link depth to follow |
| `max_pages` | integer | No | For map/listing agents: maximum pages to scrape |
| `limit` | integer | No | For map agents: maximum results to return |
| `include_patterns` | string | No | For map agents: URL patterns to include |
| `exclude_patterns` | string | No | For map agents: URL patterns to exclude |
### Bulk Rerun AI Scraper
Run an existing AI scraper on multiple URLs in a single request.
```python
from langchain_mrscraper import load_mrscraper_tools
bulk_ai, = load_mrscraper_tools(
token="MRSCRAPER_API_TOKEN",
tool_names=["mrscraper_bulk_rerun_ai_scraper"],
)
output = bulk_ai.invoke(
{
"scraper_id": "YOUR_AI_SCRAPER_ID",
"urls": [
"https://example.com/a",
"https://example.com/b",
],
}
)
print(output)
```
**Parameters:**
| Parameter | Type | Required | Description |
| ------------ | ------ | -------- | ----------------------------- |
| `scraper_id` | string | Yes | ID of the existing AI scraper |
| `urls` | array | Yes | List of URLs to scrape |
This is more efficient than calling `mrscraper_rerun_ai_scraper` once per URL. Use [Get Result by ID](#get-result-by-id) to retrieve individual results.
### Rerun Manual Scraper
Rerun an existing manual scraper (created in the MrScraper dashboard) on a new URL.
```python
from langchain_mrscraper import load_mrscraper_tools
rerun_manual, = load_mrscraper_tools(
token="MRSCRAPER_API_TOKEN",
tool_names=["mrscraper_rerun_manual_scraper"],
)
output = rerun_manual.invoke(
{
"scraper_id": "YOUR_MANUAL_SCRAPER_ID",
"url": "https://example.com/target",
}
)
print(output)
```
**Parameters:**
| Parameter | Type | Required | Description |
| ------------ | ------ | -------- | ------------------------------------------- |
| `scraper_id` | string | Yes | ID of the manual scraper from the dashboard |
| `url` | string | Yes | URL to scrape |
### Bulk Rerun Manual Scraper
Run an existing manual scraper on multiple URLs in a single request.
```python
from langchain_mrscraper import load_mrscraper_tools
bulk_manual, = load_mrscraper_tools(
token="MRSCRAPER_API_TOKEN",
tool_names=["mrscraper_bulk_rerun_manual_scraper"],
)
output = bulk_manual.invoke(
{
"scraper_id": "YOUR_MANUAL_SCRAPER_ID",
"urls": [
"https://example.com/one",
"https://example.com/two",
],
}
)
print(output)
```
**Parameters:**
| Parameter | Type | Required | Description |
| ------------ | ------ | -------- | ------------------------------------------- |
| `scraper_id` | string | Yes | ID of the manual scraper from the dashboard |
| `urls` | array | Yes | List of URLs to scrape |
This is more efficient than calling `mrscraper_rerun_manual_scraper` once per URL. Use [Get Result by ID](#get-result-by-id) to retrieve individual results.
### Retrieving Results
#### Get All Results
Retrieve a paginated list of scraping results with filtering and sorting options.
```python
from langchain_mrscraper import load_mrscraper_tools
list_results, = load_mrscraper_tools(
token="MRSCRAPER_API_TOKEN",
tool_names=["mrscraper_get_all_results"],
)
output = list_results.invoke(
{
"sort_field": "updatedAt",
"sort_order": "DESC",
"page_size": 10,
"page": 1,
"search": None,
"date_range_column": None,
"start_at": None,
"end_at": None,
}
)
print(output)
```
**Parameters:**
| Parameter | Type | Required | Default | Description |
| ------------------- | ------- | -------- | ------------- | ----------------------------------- |
| `sort_field` | string | No | `"updatedAt"` | Field to sort by |
| `sort_order` | string | No | `"DESC"` | Sort direction: `"ASC"` or `"DESC"` |
| `page_size` | integer | No | `10` | Number of results per page |
| `page` | integer | No | `1` | Page number (starting at 1) |
| `search` | string | No | `None` | Optional free-text filter |
| `date_range_column` | string | No | `None` | Date field to filter by |
| `start_at` | string | No | `None` | Start date (ISO 8601 format) |
| `end_at` | string | No | `None` | End date (ISO 8601 format) |
**Supported `sort_field` values:**
`"createdAt"`, `"updatedAt"`, `"id"`, `"type"`, `"url"`, `"status"`, `"error"`, `"tokenUsage"`, `"runtime"`
#### Get Result by ID
Fetch a single scraping result using its unique ID.
```python
from langchain_mrscraper import load_mrscraper_tools
get_one, = load_mrscraper_tools(
token="MRSCRAPER_API_TOKEN",
tool_names=["mrscraper_get_result_by_id"],
)
output = get_one.invoke({"result_id": "YOUR_RESULT_ID"})
print(output)
```
**Parameters:**
| Parameter | Type | Required | Description |
| ----------- | ------ | -------- | ------------------------------- |
| `result_id` | string | Yes | Unique identifier of the result |
## Tool Loading Options
You can obtain tools in several ways:
**1. Toolkit (Recommended)**
```python
from langchain_mrscraper import MrScraperToolkit
tools = MrScraperToolkit(token="MRSCRAPER_API_TOKEN").get_tools()
```
**2. Convenience Loader**
```python
from langchain_mrscraper import load_mrscraper_tools
tools = load_mrscraper_tools(token="MRSCRAPER_API_TOKEN")
```
**3. Selective Tool Loading**
```python
from langchain_mrscraper import load_mrscraper_tools
tools = load_mrscraper_tools(
token="MRSCRAPER_API_TOKEN",
tool_names=[
"mrscraper_fetch_html",
"mrscraper_get_result_by_id",
],
)
```
**4. Per-Tool Constructors**
```python
from langchain_mrscraper.tools import MrScraperFetchHtmlTool
fetch_html = MrScraperFetchHtmlTool(token="MRSCRAPER_API_TOKEN")
```
All tools return JSON strings (pretty-printed) from the MrScraper API, making them easy to parse and process in your agent workflows.
## Async Usage
All tools implement `_arun` for async callers. In async code, you can use the tool's async entry point when your LangChain version supports it:
```python
import asyncio
from langchain_mrscraper import load_mrscraper_tools
async def async_scrape():
fetch_html, = load_mrscraper_tools(
token="MRSCRAPER_API_TOKEN",
tool_names=["mrscraper_fetch_html"],
)
# Use ainvoke for async execution
output = await fetch_html.ainvoke({
"url": "https://example.com",
"timeout": 120,
})
print(output)
asyncio.run(async_scrape())
```
Check your LangChain version to confirm `ainvoke` is available on `BaseTool`. Most recent versions include async support.
## Best Practices
### Token Management
Store your API token securely:
```python
import os
from pathlib import Path
# Load from .env file
from dotenv import load_dotenv
load_dotenv()
token = os.getenv("MRSCRAPER_API_KEY")
```
### Error Handling
Implement error handling in your agent workflows:
```python
from langchain_mrscraper import load_mrscraper_tools
try:
fetch_html, = load_mrscraper_tools(
token="MRSCRAPER_API_TOKEN",
tool_names=["mrscraper_fetch_html"],
)
output = fetch_html.invoke({"url": "https://example.com"})
except Exception as e:
print(f"Scraping error: {e}")
```
### Tool Selection
Only load the tools your agent needs:
```python
# Good: Only load needed tools
tools = load_mrscraper_tools(
tool_names=["mrscraper_fetch_html", "mrscraper_create_scraper"]
)
# Avoid: Loading all tools when only using a few
tools = MrScraperToolkit().get_tools() # All 8 tools
```
# Node.js SDK
The official `@mrscraper/sdk` package allows you to fetch HTML, run AI scrapers, rerun existing scrapers, and retrieve results from your Node.js applications.
## Requirements
* **Node.js 18 or latest**
* **ES Modules enabled** in your `package.json`
```json title="package.json"
{
"type": "module"
}
```
See [@mrscraper/sdk on npm](https://www.npmjs.com/package/@mrscraper/sdk) for the latest release, version history, and installation details.
## Installation
Install the SDK using npm:
```bash
npm install @mrscraper/sdk
```
## Authentication
Set your API token as an environment variable. You can get your API token from the [MrScraper dashboard](https://app.mrscraper.com).
```bash
export MRSCRAPER_API_TOKEN=MRSCRAPER_API_TOKEN
```
Every SDK method accepts an optional `token` parameter if you need to override `MRSCRAPER_API_TOKEN` for specific requests.
For more information on generating API tokens, see the [Generate Token](/docs/getting-started/api-token) guide.
## Quick Start
```ts
import {
fetchHtml,
createAiScraper,
MrScraperError,
} from "@mrscraper/sdk";
try {
// 1. Fetch raw HTML from a URL
const html = await fetchHtml({
url: "https://example.com",
});
console.log(html);
// 2. Create an AI scraper (listing agent)
const scraper = await createAiScraper({
url: "https://example.com/products",
message: "Extract all product names and prices",
agent: "listing",
});
console.log(scraper);
} catch (err) {
if (err instanceof MrScraperError) {
console.error(`[${err.status ?? "network"}] ${err.message}`);
} else {
throw err;
}
}
```
## Core Methods
### Fetch Raw HTML
Fetch rendered HTML or JSON text from a target URL using the MrScraper stealth browser.
```ts
import { fetchHtml } from "@mrscraper/sdk";
const html = await fetchHtml({
url: "https://example.com",
timeout: 120,
geoCode: "US",
blockResources: false,
// token: "optional_override_token"
});
```
**Parameters:**
| Parameter | Type | Required | Default | Description |
| ---------------- | ------- | -------- | ------- | ------------------------------------------------ |
| `url` | string | Yes | - | URL to fetch |
| `timeout` | number | No | `120` | Timeout in seconds (1-600) |
| `geoCode` | string | No | `"US"` | Two-letter ISO country code for proxy |
| `blockResources` | boolean | No | `false` | Block images, fonts, and CSS for faster fetching |
| `token` | string | No | - | Per-request token override |
### Create AI Scraper
Create and run a new AI-powered scraper using natural language instructions.
**Agent Types:**
| Agent | Best For | Additional Parameters |
| ----------- | --------------------------------------------- | ------------------------------------------------------------------------- |
| `"general"` | Single pages, product details, articles | None |
| `"listing"` | Product listings, search results, directories | `max_pages` |
| `"map"` | Site crawling, URL discovery, sitemaps | `max_depth`, `max_pages`, `limit`, `include_patterns`, `exclude_patterns` |
For detailed information on agents, see [AI Scraper Agents](/docs/features/ai-scraper#ai-scraper-agents).
#### General/Listing Agent Example
```ts
import { createAiScraper } from "@mrscraper/sdk";
const scraper = await createAiScraper({
url: "https://example.com/products",
message: "Extract all product names and prices",
agent: "listing",
proxyCountry: "US",
// token: "optional_override_token"
});
```
#### Map Agent Example
```ts
import { createAiScraper } from "@mrscraper/sdk";
const mapResult = await createAiScraper({
url: "https://example.com",
agent: "map",
maxDepth: 2,
maxPages: 50,
limit: 1000,
includePatterns: "/blog",
excludePatterns: "/admin",
// token: "optional_override_token"
});
```
**Parameters:**
| Parameter | Type | Required | Default | Description |
| ----------------- | ------------------------------------- | -------- | ----------- | ---------------------------------------------- |
| `url` | string | Yes | - | Target URL to scrape |
| `message` | string | No | `""` | Natural language instructions for extraction |
| `agent` | `"general"` \| `"listing"` \| `"map"` | No | `"general"` | Agent type to use |
| `proxyCountry` | string \| null | No | - | Country code for proxy (e.g., `"US"`, `"GB"`) |
| `maxDepth` | number | No | `2` | For map agent: link depth to follow |
| `maxPages` | number | No | `50` | For map/listing agent: maximum pages to scrape |
| `limit` | number | No | `1000` | For map agent: maximum results to return |
| `includePatterns` | string | No | `""` | For map agent: URL patterns to include (regex) |
| `excludePatterns` | string | No | `""` | For map agent: URL patterns to exclude (regex) |
| `token` | string | No | - | Per-request token override |
### Rerun AI Scraper
Rerun an existing AI scraper on a new URL without creating a new scraper configuration.
```ts
import { rerunAiScraper } from "@mrscraper/sdk";
const result = await rerunAiScraper({
scraperId: "your-scraper-id",
url: "https://example.com/new-page",
maxDepth: 2,
maxPages: 50,
limit: 1000,
includePatterns: "",
excludePatterns: "",
// token: "optional_override_token"
});
```
**Parameters:**
| Parameter | Type | Required | Default | Description |
| ----------------- | ------ | -------- | ------- | ----------------------------------------------- |
| `scraperId` | string | Yes | - | ID of the existing scraper |
| `url` | string | Yes | - | New URL to scrape |
| `maxDepth` | number | No | `2` | For map agents: link depth to follow |
| `maxPages` | number | No | `50` | For map/listing agents: maximum pages to scrape |
| `limit` | number | No | `1000` | For map agents: maximum results to return |
| `includePatterns` | string | No | `""` | For map agents: URL patterns to include |
| `excludePatterns` | string | No | `""` | For map agents: URL patterns to exclude |
| `token` | string | No | - | Per-request token override |
### Bulk Rerun AI Scraper
Run an existing AI scraper on multiple URLs in a single request.
```ts
import { bulkRerunAiScraper } from "@mrscraper/sdk";
const bulkResult = await bulkRerunAiScraper({
scraperId: "your-scraper-id",
urls: ["https://example.com/page1", "https://example.com/page2"],
// token: "optional_override_token"
});
```
**Parameters:**
| Parameter | Type | Required | Description |
| ----------- | --------- | -------- | ----------------------------- |
| `scraperId` | string | Yes | ID of the existing AI scraper |
| `urls` | string\[] | Yes | Array of URLs to scrape |
| `token` | string | No | Per-request token override |
Bulk operations are more efficient than individual rerun calls. Use this method when scraping multiple URLs to reduce API calls and improve performance.
### Rerun Manual Scraper
Rerun an existing manual scraper (created in the MrScraper dashboard) on a new URL.
```ts
import { rerunManualScraper } from "@mrscraper/sdk";
const result = await rerunManualScraper({
scraperId: "your-manual-scraper-id",
url: "https://example.com/target",
// token: "optional_override_token"
});
```
**Parameters:**
| Parameter | Type | Required | Description |
| ----------- | ------ | -------- | ------------------------------------------- |
| `scraperId` | string | Yes | ID of the manual scraper from the dashboard |
| `url` | string | Yes | URL to scrape |
| `token` | string | No | Per-request token override |
### Bulk Rerun Manual Scraper
Run an existing manual scraper on multiple URLs in a single request.
```ts
import { bulkRerunManualScraper } from "@mrscraper/sdk";
const bulk = await bulkRerunManualScraper({
scraperId: "your-manual-scraper-id",
urls: ["https://example.com/a", "https://example.com/b"],
// token: "optional_override_token"
});
```
**Parameters:**
| Parameter | Type | Required | Description |
| ----------- | --------- | -------- | ------------------------------------------- |
| `scraperId` | string | Yes | ID of the manual scraper from the dashboard |
| `urls` | string\[] | Yes | Array of URLs to scrape |
| `token` | string | No | Per-request token override |
### Retrieving Results
#### Get All Results
Retrieve a paginated list of scraping results with filtering and sorting options.
```ts
import { getAllResults } from "@mrscraper/sdk";
const results = await getAllResults({
sortField: "updatedAt",
sortOrder: "DESC",
pageSize: 10,
page: 1,
search: "example.com",
dateRangeColumn: "createdAt",
startAt: "2024-01-01T00:00:00Z",
endAt: "2024-12-31T23:59:59Z",
// token: "optional_override_token"
});
```
**Parameters:**
| Parameter | Type | Required | Default | Description |
| ----------------- | ------------------- | -------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sortField` | string | No | `"updatedAt"` | Field to sort by. **Supported values:** `"createdAt"`, `"updatedAt"`, `"id"`, `"type"`, `"url"`, `"status"`, `"error"`, `"tokenUsage"`, `"runtime"` |
| `sortOrder` | `"ASC"` \| `"DESC"` | No | `"DESC"` | Sort direction |
| `pageSize` | number | No | `10` | Number of results per page |
| `page` | number | No | `1` | Page number to retrieve |
| `search` | string | No | `""` | Keyword to filter results |
| `dateRangeColumn` | string | No | - | Date field to filter by |
| `startAt` | string | No | - | Start date for filtering (ISO 8601 format) |
| `endAt` | string | No | - | End date for filtering (ISO 8601 format) |
| `token` | string | No | - | Per-request token override |
#### Get Result by ID
Retrieve a single scraping result using its unique ID.
```ts
import { getResultById } from "@mrscraper/sdk";
const result = await getResultById({
resultId: "your-result-id",
// token: "optional_override_token"
});
```
**Parameters:**
| Parameter | Type | Required | Description |
| ---------- | ------ | -------- | ------------------------------- |
| `resultId` | string | Yes | Unique identifier of the result |
| `token` | string | No | Per-request token override |
## Error Handling
All SDK methods throw `MrScraperError` for API, network, or timeout failures.
### Exception Properties
| Property | Type | Description |
| --------- | ------------------- | ------------------------------------------------------------------------ |
| `message` | string | Human-readable error message |
| `status` | number \| undefined | HTTP status code (401, 429, 500, etc.) or `undefined` for network errors |
| `name` | string | Always `"MrScraperError"` |
### Example Error Handling
```ts
import { fetchHtml, MrScraperError } from "@mrscraper/sdk";
try {
await fetchHtml({ url: "https://example.com" });
} catch (err) {
if (err instanceof MrScraperError) {
console.error(`Error: ${err.message}`);
console.error(`Status: ${err.status ?? "network error"}`);
} else {
// Handle unexpected errors
throw err;
}
}
```
### Best Practices
* Always wrap SDK calls in try-catch blocks
* Check `err instanceof MrScraperError` before accessing error properties
* Log errors with appropriate context for debugging
* Implement retry logic for network errors (when `status` is `undefined`)
* Verify your API token if you encounter status `401`
## Migration from Firecrawl
If you're migrating from the [Firecrawl Node SDK](https://docs.firecrawl.dev/sdks/node), use this mapping to find equivalent MrScraper methods.
| Firecrawl Method | MrScraper Equivalent |
| ------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- |
| [Scrape a URL](https://docs.firecrawl.dev/sdks/node#scraping-a-url) with HTML output | [`fetchHtml`](#fetch-raw-html) |
| [Scrape a URL](https://docs.firecrawl.dev/sdks/node#scraping-a-url) with structured JSON | [`createAiScraper`](#create-ai-scraper) with `agent: "general"` or [`rerunAiScraper`](#rerun-ai-scraper) |
| [Crawl a website](https://docs.firecrawl.dev/sdks/node#crawling-a-website) or [map URLs](https://docs.firecrawl.dev/sdks/node#mapping-a-website) | [`createAiScraper`](#create-ai-scraper) with `agent: "map"` or [`rerunAiScraper`](#rerun-ai-scraper) with map options |
| [Batch scrape](https://docs.firecrawl.dev/sdks/node#batch-scrape) | [`bulkRerunAiScraper`](#bulk-rerun-ai-scraper) or [`bulkRerunManualScraper`](#bulk-rerun-manual-scraper) |
| Scrape listing/pagination pages | [`createAiScraper`](#create-ai-scraper) with `agent: "listing"` and `maxPages` parameter |
### Key Differences
* **Agent-Based Approach**: MrScraper uses specialized agents (`general`, `listing`, `map`) instead of format-based parameters.
* **Natural Language Instructions**: Instead of defining extraction schemas, use the `message` parameter to describe what data you want in plain English.
* **Pagination Handling**: Use `agent: "listing"` with `maxPages` to automatically handle paginated content.
# Python SDK
The [mrscraper-sdk](https://pypi.org/project/mrscraper-sdk/) is a typed Python client for the MrScraper web scraping API. All client methods are **async** and must be used with `asyncio` or another async runtime.
## Requirements
* **Python 3.9 or latest**
* Basic familiarity with async/await syntax in Python
See the [mrscraper-sdk on PyPI](https://pypi.org/project/mrscraper-sdk/) for the latest release, version history, and metadata.
## Installation
Install the SDK from PyPI using pip:
```bash
pip install mrscraper-sdk
```
Import the client in your Python code:
```python
from mrscraper import MrScraper
```
## Authentication
Initialize the client with your MrScraper API token. You can get your API token from the [MrScraper dashboard](https://app.mrscraper.com).
```python
from mrscraper import MrScraper
client = MrScraper(token="MRSCRAPER_API_TOKEN")
```
Store your API token in environment variables rather than hardcoding it in your source code:
```python
import os
from mrscraper import MrScraper
client = MrScraper(token=os.getenv("MRSCRAPER_API_TOKEN"))
```
For more information on generating API tokens, see the [Generate Token](/docs/getting-started/api-token) guide.
## Core Methods
### Fetch Raw HTML
Use `fetch_html` to load a page with the MrScraper stealth browser and return rendered HTML content.
```python
import asyncio
from mrscraper import MrScraper
async def main():
client = MrScraper(token="MRSCRAPER_API_TOKEN")
result = await client.fetch_html(
"https://example.com/product",
geo_code="US",
timeout=120,
block_resources=False,
)
print(result["data"]) # raw HTML string
asyncio.run(main())
```
**Parameters:**
| Parameter | Type | Required | Description |
| ----------------- | ------- | -------- | -------------------------------------------------------------- |
| `url` | string | Yes | Target page URL to fetch |
| `timeout` | integer | No | Request timeout in seconds (default: 60) |
| `geo_code` | string | No | Geographic/proxy region (e.g., `"US"`, `"GB"`, `"SG"`) |
| `block_resources` | boolean | No | When `True`, blocks images, CSS, and fonts to reduce bandwidth |
### Create AI Scraper
Create and run an AI-powered scraper using natural language instructions. The response includes scraper metadata and an ID for future reruns.
```python
result = await client.create_scraper(
url="https://example.com/products",
message="Extract all product names, prices, and ratings",
agent="listing", # "general" | "listing" | "map"
proxy_country="US",
)
scraper_id = result["data"]["data"]["id"]
print("Scraper ID:", scraper_id)
```
**Parameters:**
| Parameter | Type | Required | Description |
| --------------- | ------ | -------- | ----------------------------------------------------------------------- |
| `url` | string | Yes | Target URL to scrape |
| `message` | string | Yes | Natural language instructions for data extraction |
| `agent` | string | No | Agent type: `"general"`, `"listing"`, or `"map"` (default: `"general"`) |
| `proxy_country` | string | No | Country code for proxy (e.g., `"US"`, `"GB"`) |
**Agent Types:**
| Agent | Best For | Additional Parameters |
| ----------- | --------------------------------------------- | ------------------------------------------------------------------------- |
| `"general"` | Single pages, product details, articles | None |
| `"listing"` | Product listings, search results, directories | `max_pages` |
| `"map"` | Site crawling, URL discovery, sitemaps | `max_depth`, `max_pages`, `limit`, `include_patterns`, `exclude_patterns` |
For detailed information on agents, see [AI Scraper Agents](/docs/features/ai-scraper#ai-scraper-agents).
### Rerun AI Scraper
Rerun an existing AI scraper on a new URL without creating a new scraper configuration.
```python
result = await client.rerun_scraper(
scraper_id="scraper_12345",
url="https://example.com/products?page=2",
)
```
**Parameters:**
| Parameter | Type | Required | Description |
| ------------------ | ------- | -------- | -------------------------------------------------- |
| `scraper_id` | string | Yes | ID of the existing scraper |
| `url` | string | Yes | New URL to scrape |
| `max_depth` | integer | No | For map agents: link depth to follow |
| `max_pages` | integer | No | For map/listing agents: maximum pages to scrape |
| `limit` | integer | No | For map agents: maximum results to return |
| `include_patterns` | list | No | For map agents: regex patterns for URLs to include |
| `exclude_patterns` | list | No | For map agents: regex patterns for URLs to exclude |
### Bulk Rerun AI Scraper
Run an existing AI scraper on multiple URLs in a single request.
```python
result = await client.bulk_rerun_ai_scraper(
scraper_id="scraper_12345",
urls=[
"https://example.com/products/item1",
"https://example.com/products/item2",
"https://example.com/products/item3",
],
)
```
**Parameters:**
| Parameter | Type | Required | Description |
| ------------ | ------ | -------- | ---------------------------------- |
| `scraper_id` | string | Yes | ID of the existing AI scraper |
| `urls` | list | Yes | List of URLs to scrape (non-empty) |
Bulk operations are more efficient than individual rerun calls. Use this method when scraping multiple URLs to reduce API calls and improve performance.
### Rerun Manual Scraper
Rerun an existing manual scraper (created in the MrScraper dashboard) on a new URL.
```python
result = await client.rerun_manual_scraper(
scraper_id="manual_scraper_67890",
url="https://example.com/products/new-item",
)
```
**Parameters:**
| Parameter | Type | Required | Description |
| ------------ | ------ | -------- | --------------------------------- |
| `scraper_id` | string | Yes | ID of the existing manual scraper |
| `url` | string | Yes | New URL to scrape |
See [Manual Rerun](/docs/api/v3/scraper/manual-rerun) in the API docs for more details.
### Bulk Rerun Manual Scraper
Run an existing manual scraper on multiple URLs in a single request.
```python
result = await client.bulk_rerun_manual_scraper(
scraper_id="manual_scraper_67890",
urls=[
"https://www.example.com/products/item1",
"https://www.example.com/products/item2",
"https://www.example.com/products/item3",
],
)
```
**Parameters:**
| Parameter | Type | Required | Description |
| ------------ | ------ | -------- | ------------------------------------------- |
| `scraper_id` | string | Yes | ID of the manual scraper from the dashboard |
| `urls` | list | Yes | List of URLs to scrape (non-empty) |
### Retrieving Results
#### Get All Results
Retrieve a paginated list of scraping results with filtering and sorting options.
```python
page = await client.get_all_results(
sort_field="updatedAt",
sort_order="DESC",
page_size=20,
page=1,
search="product",
date_range_column="updatedAt",
start_at="2026-01-01",
end_at="2026-01-31",
)
print(page["data"])
```
**Parameters:**
| Parameter | Type | Required | Description |
| ------------------- | ------- | -------- | ----------------------------------------------------- |
| `sort_field` | string | No | Field to sort by (e.g., `"updatedAt"`, `"createdAt"`) |
| `sort_order` | string | No | Sort direction: `"ASC"` or `"DESC"` |
| `page_size` | integer | No | Number of results per page (default: 20) |
| `page` | integer | No | Page number to retrieve (default: 1) |
| `search` | string | No | Keyword to filter results (optional) |
| `date_range_column` | string | No | Date field to filter by (e.g., `"updatedAt"`) |
| `start_at` | string | No | Start date for filtering (ISO 8601 format) |
| `end_at` | string | No | End date for filtering (ISO 8601 format) |
* The `search` parameter is optional. Omit it if you don't need keyword filtering and only want date-based or paginated results.
* Related REST documentation: [Get All Results in Range](/docs/api/v3/result/all).
#### Get Result by ID
Retrieve a single scraping result using its unique ID.
```python
result = await client.get_result_by_id("result_12345")
print(result["data"])
```
**Parameters:**
| Parameter | Type | Required | Description |
| ----------- | ------ | -------- | ------------------------------- |
| `result_id` | string | Yes | Unique identifier of the result |
Related REST documentation: [Result Detail](/docs/api/v3/result/detail)
## Error Handling
The SDK raises typed exceptions from `mrscraper.exceptions` for different error scenarios.
### Exception Types
| Exception | When It's Raised |
| --------------------- | ------------------------------------------------- |
| `MrScraperError` | Base class for all SDK errors |
| `AuthenticationError` | Invalid or missing API token (HTTP 401) |
| `APIError` | Non-success API response (exposes `.status_code`) |
| `NetworkError` | Network timeouts or connection failures |
### Example Error Handling
```python
from mrscraper.exceptions import AuthenticationError, APIError, NetworkError
try:
result = await client.fetch_html("https://example.com")
except AuthenticationError:
print("Authentication failed. Check your API token at https://app.mrscraper.com")
except APIError as e:
print(f"API error {e.status_code}: {e}")
except NetworkError as e:
print(f"Network problem: {e}")
```
### Best Practices
* Always wrap SDK calls in try-except blocks
* Log errors with appropriate context for debugging
* Implement retry logic for `NetworkError` exceptions
* Verify your API token if you encounter `AuthenticationError`
## Migration from Firecrawl
If you're migrating from the [Firecrawl Python SDK](https://docs.firecrawl.dev/sdks/python), use this mapping to find equivalent MrScraper methods.
| Firecrawl Method | MrScraper Equivalent |
| --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| [Scrape a URL](https://docs.firecrawl.dev/sdks/python#scraping-a-url) with HTML output | [`fetch_html`](#fetch-raw-html) |
| [Scrape a URL](https://docs.firecrawl.dev/sdks/python#scraping-a-url) with structured JSON | [`create_scraper`](#create-ai-scraper) with `agent="general"` or [`rerun_scraper`](#rerun-ai-scraper) |
| [Crawl a website](https://docs.firecrawl.dev/sdks/python#crawl-a-website) or [map URLs](https://docs.firecrawl.dev/sdks/python#map-a-website) | [`create_scraper`](#create-ai-scraper) with `agent="map"` or [`rerun_scraper`](#rerun-ai-scraper) with map options |
| [Batch scrape](https://docs.firecrawl.dev/sdks/python#batch-scrape) | [`bulk_rerun_ai_scraper`](#bulk-rerun-ai-scraper) or [`bulk_rerun_manual_scraper`](#bulk-rerun-manual-scraper) |
| Scrape listing/pagination pages | [`create_scraper`](#create-ai-scraper) with `agent="listing"` and `max_pages` parameter |
### Key Differences
* **Agent-Based Approach**: MrScraper uses specialized agents (`general`, `listing`, `map`) instead of format-based parameters.
* **Natural Language Instructions**: Instead of defining extraction schemas, use the `message` parameter to describe what data you want in plain English.
* **Pagination Handling**: Use `agent="listing"` with `max_pages` to automatically handle paginated content.
# SQL/Database
import { SquaresUnite, ChartBar, Cog } from 'lucide-react';
import { Step, Steps } from 'fumadocs-ui/components/steps';
## What Are SQL Connections?
SQL connections allow your MrScraper scrapers to send data directly to an external SQL database. This is useful for storing scraped data in a structured format and enables further analysis and reporting.
## Key Features
} title="Centralized Data Storage">
Store all your scraped data in one place for easy access and management.
} title="Data Analysis">
Use SQL queries to analyze and manipulate your scraped data.
} title="Automation">
Automatically insert scraped data into your database without manual intervention.
## Create an SQL Connection
Follow these steps to create an SQL connection in MrScraper:
Open your **MrScraper dashboard**.
Click the **gear icon** on the left panel and select **SQL Connection**.
On the **SQL Connection page**, click the + icon in the top-right corner.
Fill in the SQL connection details:
* **SQL Driver**: Choose `PostgreSQL`, `MySQL`, `MariaDB`, `SQL Server`, `SQLite`, or `Oracle`
* **Host**: Enter the hostname or IP address of your SQL server
* **Port**: Enter the port number for your SQL server
* **Username**: Enter your SQL database username
* **Password**: Enter your SQL database password
* **Database Name**: Enter the name of the database you want to connect to
* **Default Table**: Enter the name of the table where the data will be inserted
Click **Submit** to save your SQL connection.
## Connect SQL Connection to Scraper
After creating the SQL connection, follow these steps to connect it to your scraper:
Go to your chosen **Scraper** page.
Click the **Ellipsis** ( **⋮** ) button and click **Database Integration**.
Enable the **Database Integration** toggle.
Select the SQL connection you just created from the dropdown menu.
Click **Save Database Settings**.
## Example Result
Once the scraper finishes, the scraped data will be automatically inserted into the specified table in your SQL database. You can then query and analyze the data using your preferred SQL tools. Here's an example of what the data might look like in a PostgreSQL database:
```sql title="Table containing scraping results"
scraping=# select * from books;
title
---------------------------------------
A Light in the ...
Tipping the Velvet
Soumission
Sharp Objects
Sapiens: A Brief History ...
The Requiem Red
The Dirty Little Secrets ...
The Coming Woman: A ...
The Boys in the ...
The Black Maria
Starving Hearts (Triangular Trade ...
Shakespeare’s Sonnets
Set Me Free
Scott Pilgrim’s Precious Little ...
Rip it Up and ...
Our Band Could Be ...
Olio
Mesaerion: The Best Science ...
Libertarianism for Beginners
It’s Only the Himalayas
(20 rows)
```
# Webhook
import { Webhook, Cog } from 'lucide-react';
import { Step, Steps } from 'fumadocs-ui/components/steps';
## What Are Webhooks?
Webhooks let you automatically send HTTP requests to another API when specific events happen in your scraper — such as when a scrape starts, completes, or fails.
## Webhook Integration Benefits
} title="Real-Time Notifications">
Get instant updates on your scraper's status by sending data to your preferred endpoint.
} title="Customizable Events">
Choose which events trigger the webhook, allowing for tailored integrations.
## Setting Up a Webhook
Follow these steps to create and connect a webhook in MrScraper:
Open your **MrScraper dashboard**.
Click the **gear icon** on the left panel and select **Webhooks**.
On the **Webhooks page**, click the + icon in the top-right corner.
Fill in the webhook details:
* **Request Type**: Choose `POST` or `PUT`
* **Event**: Select when the webhook should trigger (e.g., *Scraping Started*, *Scraping Completed*, *Scraping Failed*)
* **Name**: Give your webhook a descriptive name
* **URL**: Enter the endpoint of your external webhook app
* **Headers**: (Optional) Add any custom headers
Click **Submit** to save your webhook.
Go to your **Scraper** page, Click**Ellipsis** ( **⋮** ) button and click **Webhooks**.
Under **Webhook Settings**, select the webhook you just created and click **Save Webhook Settings**.
After connecting your scraper to a webhook, you'll receive a webhook payload each time a scrape runs. For example:
```json title="Webhook Example"
{
"event": "scrape_completed",
"message": "Scraper completed successfully",
"scraperId": "53542173-0b75-4f86-b001-15b7dbbc2ee4",
"scraperName": "All-in-One E-Commerce Laptop Test Site",
"timestamp": "2025-10-29T10:10:29.134Z",
"data": {
"userId": "0e264d60-fe1c-4033-a323-d2e5de5f7e0b",
"scraperId": "53542173-0b75-4f86-b001-15b7dbbc2ee4",
"type": "AI",
"url": "https://webscraper.io/test-sites/e-commerce/allinone/computers/laptops",
"status": "Finished",
"error": null,
"tokenUsage": 4,
"runtime": null,
"data": "{\"1\":{\"id\":\"1\",\"source\":\"table\",\"headers\":[\"Price\",\"Product Name\",\"Description\",\"Reviews\"],\"rows\":[[\"$295.99\",\"Asus VivoBook...\",\"Asus VivoBook X441NA-GA190 Chocolate Black, 14\\\", Celeron N3450, 4GB, 128GB SSD, Endless OS, ENG kbd\",\"14 reviews\"],[\"$299\",\"Prestigio Smar...\",\"Prestigio SmartBook 133S Dark Grey, 13.3\\\" FHD IPS, Celeron N3350 1.1GHz, 4GB, 32GB, Windows 10 Pro + Office 365 1 gadam\",\"8 reviews\"],[\"$299\",\"Prestigio Smar...\",\"Prestigio SmartBook 133S Gold, 13.3\\\" FHD IPS, Celeron N3350 1.1GHz, 4GB, 32GB, Windows 10 Pro + Office 365 1 gadam\",\"12 reviews\"],[\"$306.99\",\"Aspire E1-510\",\"15.6\\\", Pentium N3520 2.16GHz, 4GB, 500GB, Linux\",\"2 reviews\"],[\"$321.94\",\"Lenovo V110-15...\",\"Lenovo V110-15IAP, 15.6\\\" HD, Celeron N3350 1.1GHz, 4GB, 128GB SSD, Windows 10 Home\",\"5 reviews\"],[\"$356.49\",\"Lenovo V110-15...\",\"Asus VivoBook 15 X540NA-GQ008T Chocolate Black, 15.6\\\" HD, Pentium N4200, 4GB, 500GB, Windows 10 Home, En kbd\",\"6 reviews\"],[\"$364.46\",\"Hewlett Packar...\",\"Hewlett Packard 250 G6 Dark Ash Silver, 15.6\\\" HD, Celeron N3060 1.6GHz, 4GB, 128GB SSD, DOS\",\"12 reviews\"],[\"$372.7\",\"Acer Aspire 3...\",\"Acer Aspire 3 A315-31 Black, 15.6\\\" HD, Celeron N3350 1.1GHz, 4GB, 128GB SSD, Windows 10 Home\",\"2 reviews\"],[\"$379.94\",\"Acer Aspire A3...\",\"Acer Aspire A315-31-C33J Black 15.6\\\", HD, Celeron N3350, 4GB DDR3L, 128GB, Windows 10 Home, ENG\",\"0 reviews\"],[\"$379.95\",\"Acer Aspire ES...\",\"Acer Aspire ES1-572 Black, 15.6\\\" HD, Core i3-6006U, 4GB, 128GB SSD, Linux\",\"9 reviews\"],[\"$391.48\",\"Acer Aspire 3...\",\"Acer Aspire 3 A315-31 Black, 15.6\\\" HD, Pentium N4200 1.1GHz, 4GB, 128GB SSD, Windows 10 Home\",\"10 reviews\"],[\"$393.88\",\"Acer Aspire 3...\",\"Acer Aspire 3 A315-21, 15.6\\\", AMD A4-9120. 4GB. 128GB SSD, Linux\",\"9 reviews\"],[\"$399\",\"Asus VivoBook...\",\"Asus VivoBook Max X541NA-GQ041 Black Chocolate, 15.6\\\" HD, Pentium N4200 1.1GHz, 4GB, 500GB, Windows 10 Home\",\"4 reviews\"],[\"$399.99\",\"Asus VivoBook...\",\"Asus VivoBook E502NA-GO022T Dark Blue, 15.6\\\" HD, Pentium N4200 1.1GHz, 4GB, 128GB SSD, Windows 10 Home, En/Ru kbd\",\"3 reviews\"],[\"$404.23\",\"Lenovo ThinkPa...\",\"Lenovo ThinkPad E31-80, 13.3\\\" HD, Celeron 3855U 1.6GHz, 4GB, 128GB SSD, Windows 10 Home\",\"12 reviews\"],[\"$408.98\",\"Acer Aspire 3...\",\"Acer Aspire 3 A315-31 Black, 15.6\\\" HD, Pentium N4200 1.1GHz, 4GB, 128GB SSD, Windows 10 Home\",\"10 reviews\"],[\"$409.63\",\"Lenovo V110-15...\",\"Lenovo V110-15ISK, 15.6\\\" HD, Core i3-6006U, 8GB, 128GB SSD, Windows 10 Home\",\"9 reviews\"],[\"$410.46\",\"Acer Aspire ES...\",\"Acer Aspire ES1-732 Black, 17.3\\\" HD+, Celeron, N3350, 4GB, 1TB, Windows 10 Home\",\"14 reviews\"],[\"$410.66\",\"Asus VivoBook...\",\"Asus VivoBook 15 X540NA-GQ026T Chocolate Black, 15.6\\\" HD, Pentium N4200, 4GB, 128GB SSD, Windows 10 Home, En/Ru kbd\",\"4 reviews\"],[\"$416.99\",\"Packard 255 G2\",\"15.6\\\", AMD E2-3800 1.3GHz, 4GB, 500GB, Windows 8.1\",\"2 reviews\"],[\"$433.3\",\"Asus EeeBook R...\",\"Asus EeeBook R416NA-FA014T, 14\\\" FHD, Pentium N4200, 4GB, 128GB eMMC, Windows 10 Home, Eng kbd\",\"1 reviews\"],[\"$436.29\",\"Acer Aspire 3...\",\"Acer Aspire 3 A315-51, 15.6\\\" HD, Core i3-6006U, 4GB, 1TB, Windows 10 Home\",\"1 reviews\"],[\"$436.29\",\"Acer Aspire ES...\",\"Acer Aspire ES1-572 Black, 15.6\\\" HD, Core i3-6006U, 4GB, 500GB, Windows 10 Home\",\"2 reviews\"],[\"$439.73\",\"Acer Extensa 1...\",\"Acer Extensa 15 (2540) Black, 15.6\\\" HD, Core i5-7200U, 4GB, 500GB, Linux\",\"6 reviews\"],[\"$454.62\",\"Acer Aspire ES...\",\"Acer Aspire ES1-572 Black, 15.6\\\" HD, Core i5-7200U, 4GB, 500GB, Linux\",\"9 reviews\"],[\"$454.73\",\"Lenovo V110-15...\",\"Lenovo V110-15ISK, 15.6\\\" HD, Core i3-6006U, 4GB, 128GB SSD, Windows 10 Pro\",\"2 reviews\"],[\"$457.38\",\"Acer Aspire A3...\",\"Acer Aspire A315-51-33TG, Black 15.6\\\" HD, Core i3-7100U, 4GB DDR4, 128GB SSD, Windows 10 Home, ENG\",\"9 reviews\"],[\"$465.95\",\"Lenovo V110-15...\",\"Lenovo V110-15IKB, 15.6\\\" HD, Core i5-7200U, 4GB, 500GB, DOS\",\"7 reviews\"],[\"$468.56\",\"Asus VivoBook...\",\"Asus VivoBook 15 X540UA-DM260 Chocolate Black, 15.6\\\" FHD, Core i3-6006U, 4GB, 256GB SSD, Endless OS, En kbd\",\"1 reviews\"],[\"$469.1\",\"Acer Aspire ES...\",\"Acer Aspire ES1-572 Black, 15.6\\\" HD, Core i3-6006U, 4GB, 128GB SSD, Windows 10 Home\",\"5 reviews\"],[\"$484.23\",\"Lenovo V510 Bl...\",\"Lenovo V510 Black, 14\\\" HD, Core i3-6006U, 4GB, 128GB SSD, Windows 10 Home\",\"8 reviews\"],[\"$485.9\",\"Acer Aspire ES...\",\"Acer Aspire ES1-572 Black, 15.6\\\" HD, Core i5-7200U, 4GB, 128GB SSD, Linux\",\"6 reviews\"],[\"$487.8\",\"Lenovo V510 Bl...\",\"Lenovo V510 Black, 15.6\\\" HD, Core i3-6006U, 4GB, 128GB SSD, Windows 10 Home\",\"9 reviews\"],[\"$488.64\",\"Acer Swift 1 S...\",\"Acer Swift 1 SF113-31 Silver, 13.3\\\" FHD, Pentium N4200, 4GB, 128GB SSD, Windows 10 Home\",\"4 reviews\"],[\"$488.78\",\"Dell Vostro 15\",\"Dell Vostro 15 (3568) Black, 15.6\\\" FHD, Core i5-7200U, 4GB, 128GB SSD, Radeon R5 M420 2GB, Linux\",\"14 reviews\"],[\"$494.71\",\"Acer Aspire 3...\",\"Acer Aspire 3 A315-51 Black, 15.6\\\" FHD, Core i3-7100U, 4GB, 500GB + 128GB SSD, Windows 10 Home\",\"2 reviews\"],[\"$497.17\",\"Dell Vostro 15...\",\"Dell Vostro 15 (3568) Red, 15.6\\\" HD, Core i5-7200U, 4GB, 1TB, Radeon R5 M420 2GB, Linux\",\"9 reviews\"],[\"$498.23\",\"Lenovo V510 Bl...\",\"Lenovo V510 Black, 15.6\\\" FHD, Core i3-7100U, 4GB, 128GB SSD, Windows 10 Pro\",\"5 reviews\"],[\"$520.99\",\"HP 250 G3\",\"15.6\\\", Core i5-4210U, 4GB, 500GB, Windows 8.1\",\"13 reviews\"],[\"$564.98\",\"Acer Spin 5\",\"Acer Spin 5 SP513-51 Black, 13.3\\\" FHD Touch, Core i3-7100U, 4GB, 128GB SSD, Windows 10 Home\",\"0 reviews\"],[\"$577.99\",\"HP 350 G1\",\"15.6\\\", Core i5-4200U, 4GB, 750GB, Radeon HD8670M 2GB, Windows\",\"10 reviews\"],[\"$581.99\",\"Aspire E1-572G\",\"15.6\\\", Core i5-4200U, 8GB, 1TB, Radeon R7 M265, Windows 8.1\",\"2 reviews\"],[\"$609.99\",\"Pavilion\",\"15.6\\\", Core i5-4200U, 6GB, 750GB, Windows 8.1\",\"4 reviews\"],[\"$679\",\"Acer Aspire A5...\",\"Acer Aspire A515-51-5654, Black, 15.6\\\", FHD, Core i5-8250U, 8GB DDR4, 256GB SSD, Windows 10 Home, ENG\",\"9 reviews\"],[\"$679\",\"Dell Inspiron...\",\"Dell Inspiron 15 (5567) Fog Gray, 15.6\\\" FHD, Core i5-7200U, 8GB, 1TB, Radeon R7 M445 4GB, Linux\",\"7 reviews\"],[\"$729\",\"Asus VivoBook...\",\"Asus VivoBook S14 (S406UA-BV041T) Starry Grey, 14\\\", Core i5-8250U, 8GB, 256GB SSD, Windows 10 Home, Eng kbd\",\"2 reviews\"],[\"$739.99\",\"ProBook\",\"14\\\", Core i5 2.6GHz, 4GB, 500GB, Win7 Pro 64bit\",\"8 reviews\"],[\"$745.99\",\"Inspiron 15\",\"Moon Silver, 15.6\\\", Core i7-4510U, 8GB, 1TB, Radeon HD R7 M265 2GB,\",\"12 reviews\"],[\"$799\",\"Asus ROG STRIX...\",\"Asus ROG STRIX GL553VD-DM256, 15.6\\\" FHD, Core i5-7300HQ, 8GB, 1TB, GeForce GTX 1050 2GB, No OS\",\"7 reviews\"],[\"$809\",\"Acer Nitro 5 A...\",\"Acer Nitro 5 AN515-51, 15.6\\\" FHD IPS, Core i5-7300HQ, 8GB, 1TB, GeForce GTX 1050 2GB, Windows 10 Home\",\"0 reviews\"],[\"$899\",\"Asus ROG STRIX...\",\"Asus ROG STRIX GL553VD-DM256, 15.6\\\" FHD, Core i5-7300HQ, 8GB, 1TB, GeForce GTX 1050 2GB, No OS + Windows 10 Home\",\"7 reviews\"],[\"$999\",\"Lenovo ThinkPa...\",\"Lenovo ThinkPad L570, 15.6\\\" FHD, Core i7-7500U, 8GB, 256GB SSD, Windows 10 Pro\",\"11 reviews\"],[\"$1033.99\",\"ThinkPad Yoga\",\"12.5\\\" Touch, Core i3-4010U, 4GB, 500GB + 16GB SSD Cache,\",\"13 reviews\"],[\"$1096.02\",\"Lenovo ThinkPa...\",\"Lenovo ThinkPad L460, 14\\\" FHD IPS, Core i7-6600U, 8GB, 256GB SSD, Windows 10 Pro\",\"14 reviews\"],[\"$1098.42\",\"Dell Inspiron...\",\"Dell Inspiron 15 (7567) Black, 15.6\\\" FHD, Core i5-7300HQ, 8GB, 256GB SSD, GeForce GTX 1050 4GB, Windows 10 Home\",\"7 reviews\"],[\"$1099\",\"MSI GL72M 7RDX\",\"MSI GL72M 7RDX, 17.3\\\" FHD, Core i5-7300HQ, 8GB, 1TB + 128GB SSD, GeForce GTX 1050 2GB, Windows 10 Home\",\"1 reviews\"],[\"$1099\",\"MSI GL72M 7RDX\",\"Asus ROG Strix GL553VD-DM535T, 15.6\\\" FHD, Core i7-7700HQ, 8GB, 1TB + 128GB SSD, GeForce GTX 1050 2GB, Windows 10 Home, Eng kbd\",\"9 reviews\"],[\"$1101.83\",\"Asus ROG Strix...\",\"Apple MacBook Air 13.3\\\", Core i5 1.8GHz, 8GB, 128GB SSD, Intel HD 4000, RUS\",\"4 reviews\"],[\"$1102.66\",\"Dell Latitude...\",\"Dell Latitude 5280, 12.5\\\" HD, Core i5-7300U, 8GB, 256GB SSD, Windows 10 Pro\",\"8 reviews\"],[\"$1110.14\",\"Dell Latitude...\",\"Dell Latitude 5480, 14\\\" FHD, Core i5-7300U, 8GB, 500GB, Linux + Windows 10 Home\",\"4 reviews\"],[\"$1112.91\",\"Lenovo Legion...\",\"Lenovo Legion Y520-15IKBM, Black, 15.6\\\" FHD IPS, Core i5-7300HQ, 8 GB, 128GB SSD + 2 TB HDD, NVIDIA GeForce GTX 1060 6 GB, FreeDOS + Windows 10 Home\",\"1 reviews\"],[\"$1114.55\",\"Toshiba Porteg...\",\"Toshiba Portege Z30-C-16J Grey, 13.3\\\" FHD, Core i5-6200U, 8GB, 256GB SSD, Windows 10 Pro\",\"0 reviews\"],[\"$1115.87\",\"Acer Predator...\",\"Acer Predator Helios 300 (PH317-51), 17.3\\\" FHD IPS, Core i5-7300HQ, 8GB, 1TB + 128GB SSD, GeForce GTX 1050Ti 4GB, Windows 10 Home\",\"1 reviews\"],[\"$1115.87\",\"Acer Aspire 7...\",\"Acer Aspire 7 A715-71G, 15.6\\\" FHD IPS, Core i7-7700HQ, 8GB, 128GB SSD + 1TB HDD, GTX 1050 Ti 4GB, Windows 10 Home\",\"4 reviews\"],[\"$1116.99\",\"Dell Inspiron...\",\"Dell Inspiron 17 2in1 (7779) Silver, 17.3\\\" FHD Touch, Core i5-7200U, 12GB, 1TB, GeForce GT940MX 2GB, Windows 10 Home\",\"10 reviews\"],[\"$1117.99\",\"Dell Latitude...\",\"Dell Latitude 5480, 14\\\" FHD, Core i5-7300U, 8GB, 256GB SSD, Windows 10 Pro\",\"14 reviews\"],[\"$1118.99\",\"Lenovo Legion...\",\"Lenovo Legion Y520, 15.6\\\" FHD, Core i7-7700HQ, 8GB, 128 GB SSD + 1TB HDD, GTX 1050 4GB, Windows 10 Home\",\"13 reviews\"],[\"$1119.99\",\"Asus ROG Strix...\",\"Asus ROG Strix GL702VM-GC146T, 17.3\\\" FHD, Core i7-7700HQ, 8GB, 1TB + 128GB SSD, GeForce GTX 1060 3GB, Windows 10 Home, Eng kbd\",\"10 reviews\"],[\"$1120.99\",\"Asus ROG Strix...\",\"Asus ROG Strix GL702ZC-GC154T, 17.3\\\" FHD, Ryzen 7 1700, 16GB, 256GB + 1TB HDD, Radeon RX 580 4GB, Windows 10 Home\",\"7 reviews\"],[\"$1121.99\",\"Asus ROG Strix...\",\"Asus ROG Strix GL702ZC-GC209T, 17.3\\\" FHD IPS, Ryzen 7 1700, 16GB, 256GB SSD + 1TB HDD, Radeon RX 580 4GB, Windows 10 Home\",\"8 reviews\"],[\"$1122.99\",\"Asus ROG Strix...\",\"Asus ROG Strix SCAR Edition GL503VM-ED115T, 15.6\\\" FHD 120Hz, Core i7-7700HQ, 16GB, 256GB SSD + 1TB SSHD, GeForce GTX 1060 6GB, Windows 10 Home\",\"8 reviews\"],[\"$1123.99\",\"Asus ROG Strix...\",\"Asus ROG Strix GL702ZC-GC154T, 17.3\\\" FHD, Ryzen 7 1700, 16GB, 256GB + 1TB HDD, Radeon RX 580 4GB, Windows 10 Home\",\"7 reviews\"],[\"$1124.99\",\"Asus ROG Strix...\",\"Asus ROG Strix GL702ZC-GC209T, 17.3\\\" FHD IPS, Ryzen 7 1700, 16GB, 256GB SSD + 1TB HDD, Radeon RX 580 4GB, Windows 10 Home\",\"8 reviews\"],[\"$1125.99\",\"Asus ROG Strix...\",\"Asus ROG Strix SCAR Edition GL503VM-ED115T, 15.6\\\" FHD 120Hz, Core i7-7700HQ, 16GB, 256GB SSD + 1TB SSHD, GeForce GTX 1060 6GB, Windows 10 Home\",\"8 reviews\"],[\"$1126.99\",\"Asus ROG Strix...\",\"Asus ROG Strix GL702ZC-GC154T, 17.3\\\" FHD, Ryzen 7 1700, 16GB, 256GB + 1TB HDD, Radeon RX 580 4GB, Windows 10 Home\",\"7 reviews\"],[\"$1127.99\",\"Asus ROG Strix...\",\"Asus ROG Strix GL702ZC-GC209T, 17.3\\\" FHD IPS, Ryzen 7 1700, 16GB, 256GB SSD + 1TB HDD, Radeon RX 580 4GB, Windows 10 Home\",\"8 reviews\"],[\"$1128.99\",\"Asus ROG Strix...\",\"Asus ROG Strix SCAR Edition GL503VM-ED115T, 15.6\\\" FHD 120Hz, Core i7-7700HQ, 16GB, 256GB SSD + 1TB SSHD, GeForce GTX 1060 6GB, Windows 10 Home\",\"8 reviews\"],[\"$1129.99\",\"Asus ROG Strix...\",\"Asus ROG Strix GL702ZC-GC154T, 17.3\\\" FHD, Ryzen 7 1700, 16GB, 256GB + 1TB HDD, Radeon RX 580 4GB, Windows 10 Home\",\"7 reviews\"],[\"$1130.99\",\"Asus ROG Strix...\",\"Asus ROG Strix GL702ZC-GC209T, 17.3\\\" FHD IPS, Ryzen 7 1700, 16GB, 256GB SSD + 1TB HDD, Radeon RX 580 4GB, Windows 10 Home\",\"8 reviews\"],[\"$1131.99\",\"Asus ROG Strix...\",\"Asus ROG Strix SCAR Edition GL503VM-ED115T, 15.6\\\" FHD 120Hz, Core i7-7700HQ, 16GB, 256GB SSD + 1TB SSHD, GeForce GTX 1060 6GB, Windows 10 Home\",\"8 reviews\"],[\"$1132.99\",\"Asus ROG Strix...\",\"Asus ROG Strix GL702ZC-GC154T, 17.3\\\" FHD, Ryzen 7 1700, 16GB, 256GB + 1TB HDD, Radeon RX 580 4GB, Windows 10 Home\",\"7 reviews\"],[\"$1133.99\",\"Asus ROG Strix...\",\"Asus ROG Strix GL702ZC-GC209T, 17.3\\\" FHD IPS, Ryzen 7 1700, 16GB, 256GB SSD + 1TB HDD, Radeon RX 580 4GB, Windows 10 Home\",\"8 reviews\"],[\"$1134.99\",\"Asus ROG Strix...\",\"Asus ROG Strix SCAR Edition GL503VM-ED115T, 15.6\\\" FHD 120Hz, Core i7-7700HQ, 16GB, 256GB SSD + 1TB SSHD, GeForce GTX 1060 6GB, Windows 10 Home\",\"8 reviews\"],[\"$1135.99\",\"Asus ROG Strix...\",\"Asus ROG Strix GL702ZC-GC154T, 17.3\\\" FHD, Ryzen 7 1700, 16GB, 256GB + 1TB HDD, Radeon RX 580 4GB, Windows 10 Home\",\"7 reviews\"],[\"$1136.99\",\"Asus ROG Strix...\",\"Asus ROG Strix GL702ZC-GC209T, 17.3\\\" FHD IPS, Ryzen 7 1700, 16GB, 256GB SSD + 1TB HDD, Radeon RX 580 4GB, Windows 10 Home\",\"8 reviews\"],[\"$1137.99\",\"Asus ROG Strix...\",\"Asus ROG Strix SCAR Edition GL503VM-ED115T, 15.6\\\" FHD 120Hz, Core i7-7700HQ, 16GB, 256GB SSD + 1TB SSHD, GeForce GTX 1060 6GB, Windows 10 Home\",\"8 reviews\"],[\"$1138.99\",\"Asus ROG Strix...\",\"Asus ROG Strix GL702ZC-GC154T, 17.3\\\" FHD, Ryzen 7 1700, 16GB, 256GB + 1TB HDD, Radeon RX 580 4GB, Windows 10 Home\",\"7 reviews\"],[\"$1139.99\",\"Asus ROG Strix...\",\"Asus ROG Strix GL702ZC-GC209T, 17.3\\\" FHD IPS, Ryzen 7 1700, 16GB, 256GB SSD + 1TB HDD, Radeon RX 580 4GB, Windows 10 Home\",\"8 reviews\"]],\"name\":\"Laptops\"}}",
"htmlPath": "results/d287adc4-9d11-41ed-8245-de05d577c286/page.html",
"recordingPath": null,
"screenshotPath": "results/d287adc4-9d11-41ed-8245-de05d577c286/screenshot.jpg",
"dataPath": null,
"createdById": null,
"updatedById": null,
"deletedById": null,
"id": "68d3e07c-fab3-4b4a-9c54-b796cd64fe73",
"createdAt": "2025-10-29T10:10:29.036Z",
"updatedAt": "2025-10-29T10:10:29.036Z",
"deletedAt": null
}
}
```
# Zapier
import { Step, Steps } from 'fumadocs-ui/components/steps';
Zapier is a powerful automation tool that allows you to connect different apps and services together. By integrating MrScraper with Zapier, you can automate workflows and streamline your data extraction processes.
## What is the MrScraper Zapier Integration?
The MrScraper Zapier integration connects MrScraper with Zapier, allowing you to trigger scraping jobs, automate data collection, and build workflows using MrScraper actions and triggers.
### Available Triggers
* **New Result**: Triggers when a new scraping result (succeeded or failed) is available.
* **Scrape Completed**: Triggers when a scrape job completes successfully.
* **Scrape Failed**: Triggers when a scrape job fails.
* **Scrape Started**: Triggers when a scrape job starts.
* **Specific Scraper New Result**: Triggers when a new scraping result (succeeded or failed) is available for a specific scraper.
### Available Actions
* **Get Latest Result**: Fetch the most recent result from a specified MrScraper scraper.
* **Run AI Scraper**: Trigger an AI scraper run with optional URL overrides.
* **Run Manual Scraper**: Trigger a manual scraper run with optional URL overrides.
## Why Use Zapier with MrScraper?
Integrating MrScraper with Zapier offers several benefits:
* **Automation**: Automate repetitive tasks such as data extraction and processing.
* **Flexibility**: Connect MrScraper with over 3,000 apps available on Zapier.
* **Efficiency**: Save time by eliminating manual data handling.
## Prerequisites
Before you start, make sure you have:
* [A **MrScraper API token**](https://app.mrscraper.com/api-tokens).
* [A **MrScraper scraper** with API access enabled](https://app.mrscraper.com/scrapers).
* Access to **Zapier**.
## Integration Steps
### Add MrScraper Node
1. Open the **zapier editor**.
2. Click on **Add a Step** and select **MrScraper** from the list of available apps.
### Configure Trigger (Optional)
1. Add an account by entering your **MrScraper API token**.
2. Select one of the available trigger events:
* **New Result**
* **Scrape Completed**
* **Scrape Failed**
* **Scrape Started**
* **Specific Scraper New Result**
3. For most triggers, no additional fields are required.
4. If you choose **Specific Scraper New Result**, configure the required field below:
| Parameter | Required | Description |
| -------------- | -------- | ------------------------------------------------------------------------------------------------ |
| **Scraper ID** | Yes | The ID of the scraper you want to listen to. You can find this on the scraper page in MrScraper. |
### Configure the MrScraper Action Node
1. Choose the desired action (e.g., **Get Latest Result**).
2. Configure the action parameters as needed.
#### Get Latest Result
| Parameter | Required | Description |
| -------------- | -------- | --------------------------------------------------------------------------------------------- |
| **Scraper ID** | Yes | The ID of the AI scraper you want to run. You can find this on the scraper page in MrScraper. |
#### Run AI Scraper
| Parameter | Required | Description |
| -------------- | -------- | ------------------------------------------------------------------------------------------------- |
| **Scraper ID** | Yes | The ID of the manual scraper you want to run. You can find this on the scraper page in MrScraper. |
| **URL** | Yes | Override the default target URL for this run. |
#### Run Manual Scraper
| Parameter | Required | Description |
| -------------- | -------- | ------------------------------------------------------------------------------------------ |
| **Scraper ID** | Yes | The ID of the scraper you want to run. You can find this on the scraper page in MrScraper. |
| **URL** | Yes | Override the default target URL for this run. |
## Example Workflows
### Scheduled Scraping to Google Sheets
This workflow automatically runs a scraper on a schedule and saves the results to Google Sheets. Perfect for tracking prices, monitoring listings, or collecting data over time.
#### Set Up the Schedule
1. Add a **Schedule** node.
2. Configure the interval (e.g., every hour, daily, weekly).
#### Run the Scraper
1. Add the **MrScraper** node.
2. Select **Run AI/Manual Scraper** as the Action event.
3. Enter your **Scraper ID** and **URL**.
#### Fetch the Results
1. Add another **MrScraper** node.
2. Select **Get Latest Result** as the resource.
3. Enter the same **Scraper ID**.
#### Save to Google Sheets
1. Add a **Google Sheets** node.
2. Select **Create Spreadsheet Row** action.
### Multi-URL Scraping Loop
This workflow scrapes multiple URLs from a list and processes each result.
This flow is ideal for batch scraping tasks.
#### Prepare the URL List
1. Add a **Schedule** node.
2. Add a **Line Items From CSV** node to generate a list of URLs.:
```csv
https://example.com/page1
https://example.com/page2
https://example.com/page3
```
#### Loop Through URLs
1. Add a **Create Loop From Text** node to iterate through each URL.
2. Set **Values to Loop** to the output of the previous node (Line Items From CSV in Files > Line Items).
#### Scrape Each URL
1. Add the **MrScraper** node inside the loop.
2. Select **Run AI/Manual Scraper** as the Action event.
3. Use the URL from the previous step.
#### Save Results
1. Add a **Google Sheets** node.
2. Select **Create Spreadsheet Row** action.
# v3.4.14
import { Sparkles, TrendingUp } from 'lucide-react';
Version **v3.4.14** introduces a new **Agent Setup** page for AI workflows, and major enhancements to **Analytics** with per-use-case scoping, scraper type filtering, and token consumption tracking.
## New Features
### Agent Setup
A new [**Agent Setup**](https://app.mrscraper.com/setup) page provides a centralized starting point for connecting MrScraper with supported AI coding agents and harnesses.
It includes setup guidance and ready-to-use configuration details, making it easier to get an agent connected and start scraping from an AI-assisted workflow.
### Token Usage Analytics Chart
[Analytics](https://app.mrscraper.com/analytic) now includes a dedicated **Token Usage** chart alongside scraping activity charts. It shows token consumption over time and respects the selected filters, including scraper type, domain, action, date range, and API token.
The Token Usage chart has independent visualization and interval controls, making it easier to compare token-consumption patterns over time.
## Improvements & Updates
### Playground Analytics per Use Case
Playground now includes an **Analytics** tab for each use case. Analytics automatically scopes data to the active scraper type, keeping metrics for Scrape HTML, Scrape JSON, Screenshot, and other use cases separate.
The view focuses on the last 24 hours of activity and includes a link to the full [Analytics](https://app.mrscraper.com/analytic) page for deeper exploration.
* [Scrape HTML](https://app.mrscraper.com/playground?useCase=unblocker)
* [Scrape Markdown](https://app.mrscraper.com/playground?useCase=markdown)
* [Get Screenshot](https://app.mrscraper.com/playground?useCase=screenshot)
* [Scrape JSON](https://app.mrscraper.com/playground?useCase=extract)
* [Listing Page](https://app.mrscraper.com/playground?useCase=listing)
* [Scrape Sitemap](https://app.mrscraper.com/playground?useCase=sitemap)
### Scraper Type Filter in Analytics
The [Analytics](https://app.mrscraper.com/analytic) dashboard now includes a **Scraper type** filter. Users can filter metrics and charts by the scraper type used, making it easier to analyze activity for a specific workflow.
Available filter options are based on scraper result types present in the user’s account.
### New on Marketplace
[Marketplace](https://app.mrscraper.com/marketplace) now have a **New on Marketplace** section on the bottom of the page for APIs published in the last 14 days. The new APIs also have a `NEW` tag on the top right of the card.
# AI Search
AI Search PDP Cache agents take a natural-language **query** and return an AI-generated text answer. Instead of scraping a single detail page, they call an AI provider (with optional web search) and return the answer as Markdown text. They are suitable for research, product lookups, or general knowledge questions.
## Common Response Fields
The AI Search PDP Cache agents return the following top-level fields:
| Field | Type | Description |
| ------------ | ---------------- | --------------------------------------------------------------- |
| `success` | boolean | Whether the request completed successfully |
| `message` | string | Status message (e.g. `Successfully scraped`) |
| `data` | object \| string | The generated answer. Shape depends on the provider (see below) |
| `tokenUsage` | number | Number of tokens consumed by the run |
The `data` field differs by provider:
* **Gemini** returns an **object** with `query` and `text`:
| Field | Type | Description |
| ------------ | ------ | ------------------------------------- |
| `data.query` | string | The original query that was submitted |
| `data.text` | string | AI-generated answer in Markdown |
* **GPT** returns the answer **directly as a string** (Markdown). When web search is used, sources are appended as inline Markdown reference links (e.g. `[1]: https://...`).
## Example Providers
AI Search PDP agents are typically available for major AI providers, for example:
* **Gemini** — Ask a query to Gemini and receive an AI-generated text answer.
* **GPT** — Performs a web search using GPT and returns an AI-generated text answer with sources.
Check the [Marketplace](https://app.mrscraper.com/marketplace) for the full list of supported AI Search providers.
# Article
Article PDP Cache agents extract structured data from article and news detail pages, such as headlines, content, publication dates, authors, media, and breadcrumbs.
## Common Response Fields
The Article PDP Cache agents return the following fields:
| Field | Type | Description |
| ------------------ | ------ | ----------------------------------------------------------------------- |
| `headline` | string | Article headline or title |
| `articleBody` | string | Full text content of the article |
| `articleBodyHtml` | string | HTML markup of the article body |
| `description` | string | Short summary or description of the article |
| `datePublished` | string | Publication date in ISO 8601 format |
| `datePublishedRaw` | string | Publication date as displayed on the page |
| `dateModified` | string | Last modified date in ISO 8601 format |
| `dateModifiedRaw` | string | Last modified date as displayed on the page |
| `authors` | array | List of article authors. Each item: `name` (string), `nameRaw` (string) |
| `inLanguage` | string | Language code of the article (e.g., en) |
| `breadcrumbs` | array | Navigation breadcrumb trail. Each item: `url` (string), `name` (string) |
| `mainImage` | object | Primary image. Structure: `url` (string) |
| `images` | array | All images in the article. Each item: `url` (string) |
| `videos` | array | All videos in the article. Each item: `url` (string) |
| `audios` | array | All audio files in the article. Each item: `url` (string) |
| `url` | string | URL of the article page |
| `canonicalUrl` | string | Canonical URL of the article |
## Example Domains / Websites
Article PDP agents are typically available for commonly used news and blog domains, for example:
* **BBC** — e.g. `https://www.bbc.com/news/...`, `https://www.bbc.co.uk/news/articles/...`
* **The New York Times** — e.g. `https://www.nytimes.com/...`
* **Medium** — e.g. `https://medium.com/...`
* **Reuters** — e.g. `https://www.reuters.com/...`
* **The Guardian** — e.g. `https://www.theguardian.com/...`
* **CNN** — e.g. `https://edition.cnn.com/...`
* **TechCrunch** — e.g. `https://techcrunch.com/...`
* **Wikipedia** — e.g. `https://en.wikipedia.org/wiki/...`
Exact availability depends on the [Marketplace](https://app.mrscraper.com/marketplace). Check the marketplace for the full list of supported article domains.
# Hotel
Hotel PDP Cache agents extract structured data from hotel and accommodation detail pages, including property details, pricing, reviews, facilities, room types, and nearby points of interest.
## Common Response Fields
The Hotel PDP Cache agents return the following fields:
| Field | Type | Description |
| -------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | string | Hotel or accommodation name |
| `about` | string | Description and overview of the property |
| `address` | string | Full street address |
| `location` | string | City, area, or region name |
| `coordinates` | object | `latitude` (number), `longitude` (number) |
| `stars` | number | Star rating of the property (1–5) |
| `year_opened` | number | Year the property was opened |
| `check_in` | string | Check-in time instructions |
| `check_out` | string | Check-out time instructions |
| `contact` | object | `email` (string), `phone` (string) |
| `host` | object | `name`, `joined`, `response_time` (for homestays/apartments) |
| `pricing` | object | `currency`, `original_price`, `starting_price`, `discounted_price` |
| `review_stats` | object | `overall_score`, `total_reviews`, `score_breakdown`, `category_summaries` |
| `highlights` | array | Key selling points (strings) |
| `review_highlights` | array | Snippets of positive feedback (strings) |
| `reviews` | array | Objects: `date`, `title`, `rating`, `content`, `country`, `reviewer`, `room_type`, `trip_type`, `stay_duration` |
| `popular_facilities` | array | Flat list of popular facilities (strings) |
| `facilities` | object | `dining`, `internet`, `services`, `recreation`, `room_amenities`, `transportation`, `access_and_security`, `cleanliness_and_safety` (each array of strings) |
| `policies` | object | `pets`, `deposit`, `smoking`, `children`, `breakfast`, `cancellation`, `check_in_instructions` |
| `room_types` | array | Objects: `name`, `size`, `prices` (with `adults`, `kids`, `price_total`, `breakfast_included`, `cancellation_policy`, etc.), `bed_type`, `features` |
| `location_nearby` | object | `airports`, `culinary`, `shopping`, `hospitals`, `landmarks`, `attractions`, `cash_withdrawal`, `public_transport`, `convenience_stores` (each array of `{ name, distance }`) |
## Example Domains / URLs
Hotel PDP agents are typically available for major booking and travel domains, for example:
* **Booking.com** — e.g. `https://www.booking.com/hotel/...`
* **Expedia** — e.g. `https://www.expedia.com/...`
* **Agoda** — e.g. `https://www.agoda.com/...`
* **Trip.com** — e.g. `https://www.trip.com/...`
* **Hotels.com** — e.g. `https://www.hotels.com/...`
Check the [Marketplace](https://app.mrscraper.com/marketplace) for the full list of supported hotel domains.
# Job Posting
Job Posting PDP Cache agents extract structured data from **job detail pages**, including title, description, employment type, hiring organization, salary, location, and dates.
## Common Response Fields
The Job Posting PDP Cache agents return the following fields:
| Field | Type | Description |
| -------------------- | ------ | ---------------------------------------------------------------------------------- |
| `jobTitle` | string | Title of the job posting |
| `datePublished` | string | Publication date in ISO 8601 format |
| `datePublishedRaw` | string | Publication date as displayed on the page |
| `validThrough` | string | Expiration date of the job posting in ISO 8601 format |
| `description` | string | Full job description text |
| `descriptionHtml` | string | HTML markup of the job description |
| `employmentType` | string | Type of employment (e.g., Full-time, Part-time) |
| `hiringOrganization` | object | `name` (string) — Company or organization name |
| `baseSalary` | object | `raw` (string), `currency` (ISO 4217), `valueMax` (string), `currencyRaw` (string) |
| `jobLocation` | object | `raw` (string) — Location as displayed |
| `url` | string | URL of the job posting page |
## Example Domains / URLs
Job posting PDP agents are typically available for major job boards and career sites, for example:
* **LinkedIn** — e.g. `https://www.linkedin.com/jobs/view/...`
* **Indeed** — e.g. `https://www.indeed.com/viewjob?jk=...`
* **Glassdoor** — e.g. `https://www.glassdoor.com/job-listing/...`
* **Monster** — e.g. `https://www.monster.com/jobs/...`
* **ZipRecruiter** — e.g. `https://www.ziprecruiter.com/jobs/...`
* **CareerBuilder** — e.g. `https://www.careerbuilder.com/job/...`
Check the [Marketplace](https://app.mrscraper.com/marketplace) for the full list of supported job posting domains.
# Product
Product PDP Cache agents extract structured data from **e-commerce product detail pages**, including product info, price, media, description, specifications, variants, seller, ratings, shipping, and warranty.
## Common Response Fields
The Product PDP Cache agents return the following fields:
| Field | Type | Description |
| ---------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `product_info` | object | `name`, `brand`, `category`, `condition`, `breadcrumbs` (array of `{ url, name }`) |
| `sku` | string | Stock Keeping Unit identifier |
| `mpn` | string | Manufacturer Part Number |
| `gtin` | array | Global Trade Item Numbers. Each item: `type` (e.g. isbn13, ean13, upc), `value` (number) |
| `price` | object | `currency`, `current_price`, `is_flash_sale`, `original_price`, `currency_symbol`, `discount_percentage` |
| `wholesale_tiers` | array | Objects: `min_qty`, `price_per_unit` |
| `stock_status` | object | `status` (e.g. in\_stock, out\_of\_stock, pre\_order), `quantity` |
| `media` | array | Objects: `url`, `type` (image/video), `is_thumbnail` |
| `description` | object | `full_text`, `html_content`, `key_features` (array of strings) |
| `specifications` | array | Objects: `name`, `value` |
| `variants` | array | Objects: `mpn`, `sku`, `url`, `gtin`, `name`, `media`, `price`, `option` (array of strings), `product_url`, `stock_status`, `additionalProperties` |
| `seller` | object | `id`, `name`, `type`, `badges`, `rating`, `location`, `sold_count`, `product_count` |
| `rating_summary` | object | `sold_count`, `rating_count`, `review_count`, `average_rating` |
| `rating_distribution` | object | `1`, `2`, `3`, `4`, `5` — each with `count` and `percentage` |
| `shipping_info` | object | `weight`, `dimensions`, `free_shipping`, `fulfillment_type` |
| `warranty_and_returns` | object | `has_warranty`, `warranty_type`, `warranty_period`, `return_policy_text` |
## Example Domains / URLs
Product PDP agents are typically available for major e-commerce and marketplace domains, for example:
* **Amazon** — e.g. `https://www.amazon.com/dp/...`, `https://www.amazon.co.uk/dp/...`
* **Walmart** — e.g. `https://www.walmart.com/ip/...`
* **eBay** — e.g. `https://www.ebay.com/itm/...`
* **Tokopedia** — e.g. `https://www.tokopedia.com/...`
* **Shopee** — e.g. `https://shopee.co.id/...`
* **Lazada** — e.g. `https://www.lazada.com/...`
* **AliExpress** — e.g. `https://www.aliexpress.com/item/...`
Check the [Marketplace](https://app.mrscraper.com/marketplace) for the full list of supported product domains.
# Property
Property PDP Cache agents extract structured data from **real estate listing detail pages**, including address, price, property details, lot info, interior/exterior features, rooms, parking, utilities, financial data, agents, schools, community, area statistics, and climate risks.
## Common Response Fields
The Property PDP Cache agents return the following fields:
| Field | Type | Description |
| ------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `title` | string | Listing title or marketing headline |
| `mls_number` | string | Multiple Listing Service identifier |
| `status` | string | e.g. For Sale, Active, Pending, Sold |
| `price` | object | `amount`, `currency`, `display_price`, `price_per_sqft` |
| `address` | object | `city`, `unit`, `state`, `county`, `island`, `street`, `country`, `latitude`, `longitude`, `zip_code`, `maps_link`, `full_address` |
| `property_details` | object | `sq_ft`, `stories`, `bedrooms`, `bathrooms`, `furnished`, `year_built`, `property_type`, `bathrooms_full`, `property_style`, `bedrooms_details`, `bathrooms_partial`, `construction_materials` |
| `lot_info` | object | `views`, `zoning`, `waterfront`, `lot_size_sqft`, `lot_size_text`, `lot_size_acres` |
| `description` | string | Full marketing description |
| `dates` | object | `sold`, `posted`, `updated`, `days_on_market` |
| `interior_features` | object | `cooling`, `heating`, `kitchen`, `laundry`, `basement`, `flooring`, `appliances`, `fireplaces`, `other_interior`, `security_features`, `fireplace_features` |
| `rooms` | array | Objects: `name`, `level`, `features`, `dimensions` |
| `exterior_features` | object | `pool`, `roof`, `fencing`, `patio_porch`, `other_structures` |
| `parking` | object | `type`, `spaces`, `has_garage`, `description` |
| `utilities` | object | `sewer`, `water`, `electricity`, `energy_info`, `available_utilities` |
| `financial` | object | `hoa_fee`, `annual_tax`, `hoa_includes`, `tax_property_id`, `tax_assessed_value`, `estimated_monthly_payment` |
| `tax_history` | array | Objects: `year`, `amount`, `assessment`, `change_percentage` |
| `price_history` | array | Objects: `date`, `event`, `price`, `source` |
| `agents` | array | Objects: `name`, `role`, `email`, `phone`, `agency`, `profile_url` |
| `school_district` | string | School district name |
| `nearby_schools` | object | List with `name`, `type`, `grades`, `distance` |
| `community` | object | `name`, `features`, `security` |
| `area_statistics` | object | `people` (median\_age, population, income, etc. by zip/city/county/national), `sun_exposure`, `annual_precipitation` |
| `climate_risks` | object | `air_quality`, `fire_factor`, `heat_factor`, `wind_factor`, `flood_factor` |
| `lifestyle` | array | Objects: `score`, `category`, `description` |
| `nearby_amenities` | array | Objects: `name`, `category`, `distance` |
| `metadata` | object | `url`, `views`, `source`, `favorites` |
## Example Domains / URLs
Property PDP agents are typically available for major real estate portals, for example:
* **Zillow** — e.g. `https://www.zillow.com/homedetails/...`
* **Realtor.com** — e.g. `https://www.realtor.com/realestateandhomes-detail/...`
* **Redfin** — e.g. `https://www.redfin.com/...`
* **Trulia** — e.g. `https://www.trulia.com/p/...`
* **Rightmove** (UK) — e.g. `https://www.rightmove.co.uk/properties/...`
* **Domain** (AU) — e.g. `https://www.domain.com.au/...`
Check the [Marketplace](https://app.mrscraper.com/marketplace) for the full list of supported property domains.
# Restaurant
Restaurant PDP Cache agents extract structured data from **restaurant detail pages**, including name, rank, cuisine, address, contact, hours, features, description, ratings, review counts, and reviews.
## Common Response Fields
The Restaurant PDP Cache agents return the following fields:
| Field | Type | Description |
| ----------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------- |
| `name` | string | Restaurant name |
| `rank` | string | Ranking in area (e.g. #14 of 769 Restaurants in Kuta) |
| `cuisine` | array | Cuisine types (strings) |
| `address` | string | Full street address |
| `map_link` | string | Google Maps directions link |
| `phone` | string | Contact phone number |
| `email` | string | Contact email address |
| `website` | string | Official website URL |
| `hours` | object | Opening hours by day (e.g. Monday, Tuesday, …, Sunday) |
| `features` | array | Features and amenities (dietary options, meal types, payment methods) |
| `description` | string | Restaurant description and overview |
| `rating` | number | Overall rating (0–5 scale) |
| `rating_distribution` | object | `Food`, `Value`, `Service`, `Atmosphere` (each number 0–5) |
| `reviews_count` | number | Total number of reviews |
| `reviews_distribution` | object | `Excellent`, `Good`, `Average`, `Poor`, `Terrible` (counts) |
| `review_summary` | string | AI-generated summary of guest reviews |
| `review_summary_distribution` | object | Sentiment keyword by category: `Food`, `Value`, `Service`, `Location`, `Atmosphere` |
| `reviews` | object | Structure: `title`, `rating`, `content`, `review_date`, `reviewer_name`, `rating_distribution` (key-value rating by category) |
## Example Domains / URLs
Restaurant PDP agents are typically available for major review and dining platforms, for example:
* **TripAdvisor** — e.g. `https://www.tripadvisor.com/Restaurant_Review-...`
* **Yelp** — e.g. `https://www.yelp.com/biz/...`
* **OpenTable** — e.g. `https://www.opentable.com/...`
* **TheFork** — e.g. `https://www.thefork.com/...`
* **Zomato** — e.g. `https://www.zomato.com/...`
* **Google Maps** (restaurant listings) — e.g. `https://www.google.com/maps/place/...`
Check the [Marketplace](https://app.mrscraper.com/marketplace) for the full list of supported restaurant domains.
# Tour
Tour PDP Cache agents extract structured data from **tour and activity detail pages**, including title, about, provider, location, age range, duration, start time, languages, price, availability, highlights, included/excluded items, meeting and pickup, itinerary, accessibility, review stats, reviews, photos, FAQ, and policies.
## Common Response Fields
The Tour PDP Cache agents return the following fields:
| Field | Type | Description |
| -------------------- | ------- | ---------------------------------------------------------------------------------------------------------------- |
| `title` | string | Tour title as displayed on the page |
| `about` | string | Full tour description and overview |
| `provider` | object | `logo`, `name`, `contact` (email, phone, website) |
| `location` | object | `city`, `country`, `coordinates` (latitude, longitude), `meeting_point` |
| `age_range` | object | `min_age`, `max_age` (numbers) |
| `duration` | string | Total tour duration (e.g. 3–4 hours) |
| `start_time` | string | Start time for the tour |
| `mobile_ticket` | boolean | Whether mobile ticket is required |
| `languages` | object | `live_guide`, `audio_guide`, `written_guide` (arrays of language strings) |
| `price` | object | `currency`, `original_price`, `starting_price`, `discounted_price`, `price_per_person` |
| `availability` | object | `max_group_size`, `available_dates`, `free_cancellation`, `instant_confirmation`, `reserve_now_pay_later` |
| `highlights` | array | Key selling points (strings) |
| `included` | array | Items included in the tour (strings) |
| `excluded` | array | Items not included (strings) |
| `meeting_and_pickup` | object | `start_point` (type, address, details, pickup\_details, pickup\_offered), `end_point` (array of address/details) |
| `itinerary` | array | Objects: `duration`, `stop_name`, `description`, `admission_included` |
| `additional_info` | array | Important notes (strings) |
| `accessibility` | object | `stroller_accessible`, `near_public_transport`, `wheelchair_accessible` (booleans) |
| `review_stats` | object | `overall_score`, `total_reviews`, `rating_breakdown` (1\_star … 5\_star) |
| `reviews` | array | Objects: `date`, `title`, `rating`, `content`, `country`, `reviewer`, `trip_type` |
| `photos` | array | Image URLs (strings) |
| `faq` | array | Objects: `question`, `answer` |
| `policies` | object | `child_policy`, `refund_policy`, `weather_policy`, `cancellation_policy` |
## Example Domains / URLs
Tour PDP agents are typically available for major tour and activity platforms, for example:
* **Viator** — e.g. `https://www.viator.com/tours/...`
* **GetYourGuide** — e.g. `https://www.getyourguide.com/...`
* **TripAdvisor (Experiences)** — e.g. `https://www.tripadvisor.com/Attraction_ProductReview-...`
* **Klook** — e.g. `https://www.klook.com/activity/...`
Check the [Marketplace](https://app.mrscraper.com/marketplace) for the full list of supported tour domains.
# Authentication
import { Info, AlertCircle } from 'lucide-react';
## Authentication Formats
Residential Proxy uses a flexible username-based authentication system where your username pattern determines the proxy configuration. All proxies connect through the same endpoint but behave differently based on your username structure.
## Connection Format
All Residential Proxy connections use the following format:
```
username:password@proxy.mrscraper.com:10000
```
The **username** controls:
* Proxy type
* Country targeting
* Session persistence
* Session duration
* IP rotation behavior
## Authentication Patterns
### 1. Default (United States)
The simplest format uses just your username and password without any modifiers.
**Format:**
```
username:password@proxy.mrscraper.com:10000
```
**Behavior:**
* Residential Proxy falls back to **United States (`us`)** IPs
* IP rotates on each new request
* No session persistence
**Example:**
```bash
curl -x "user123:pass456@proxy.mrscraper.com:10000" https://api.ipify.org
```
**Note:** The UI always requires a country selection; only manual username configuration lets you omit it. Omitting it is not random assignment — it resolves to the US, so state the country explicitly whenever the target region matters.
### 2. Country-Specific Proxy
Target a specific country using ISO 3166 country codes.
**Format:**
```
username-country-{iso3166}:password@proxy.mrscraper.com:10000
```
**Parameters:**
* `{iso3166}`: 2-letter ISO 3166 country code (e.g., `US`, `GB`, `DE`, `JP`)
**Behavior:**
* All requests use IPs from the specified country
* IP rotates on each new request
* No session persistence
**Examples:**
United States
Great Britain
Germany
Japan
```bash
# Target US proxies
user123-country-us:pass456@proxy.mrscraper.com:10000
```
```bash
# Target GB proxies
user123-country-gb:pass456@proxy.mrscraper.com:10000
```
```bash
# Target German proxies
user123-country-de:pass456@proxy.mrscraper.com:10000
```
```bash
# Target Japanese proxies
user123-country-jp:pass456@proxy.mrscraper.com:10000
```
**Use Cases:**
* Accessing geo-restricted content
* Testing localized websites
* Market research in specific regions
* Price comparison across countries
### 3. Session-Based Static Proxy
Maintain the same IP across multiple requests using session IDs.
**Format:**
```
username-country-{iso3166}-sessid-{session_id}:password@proxy.mrscraper.com:10000
```
**Parameters:**
* `{iso3166}`: 2-letter ISO 3166 country code
* `{session_id}`: Any alphanumeric string (e.g., `session1`, `user_alpha`, `x9`)
**Behavior:**
* Same IP for all requests with the same `session_id`
* **Default session duration: 10 minutes**
* After expiration, a new IP is assigned
* Different `session_id` values get different IPs
**Examples:**
Session Alpha
Session Beta
Session Custom
```bash
# Session ID: alpha1
user123-country-us-sessid-alpha1:pass456@proxy.mrscraper.com:10000
```
```bash
# Session ID: beta2
user123-country-gb-sessid-beta2:pass456@proxy.mrscraper.com:10000
```
```bash
# Session ID: my_custom_session
user123-country-de-sessid-my_custom_session:pass456@proxy.mrscraper.com:10000
```
**Python Example:**
```python
import requests
proxy = {
'http': 'http://user123-country-us-sessid-session1:pass456@proxy.mrscraper.com:10000',
'https': 'http://user123-country-us-sessid-session1:pass456@proxy.mrscraper.com:10000'
}
# All these requests use the same IP
for i in range(5):
response = requests.get('https://api.ipify.org', proxies=proxy)
print(f"Request {i+1}: {response.text}") # Same IP for all
```
**Use Cases:**
* Account management and login sessions
* Shopping cart operations
* Dashboard interactions
* Form submissions requiring consistent IP
### 4. Custom Session Duration
Control exactly how long a session IP persists.
**Format:**
```
username-country-{iso3166}-sessid-{session_id}-sesstime-{minutes}:password@proxy.mrscraper.com:10000
```
**Parameters:**
* `{iso3166}`: 2-letter ISO 3166 country code
* `{session_id}`: Alphanumeric session identifier
* `{minutes}`: Session duration in minutes (integer)
**Behavior:**
* Same IP for all requests with the same `session_id`
* Session expires after `{minutes}` minutes
* New IP assigned after expiration
* Maximum flexibility for session management
**Examples:**
30 Minutes
60 Minutes
5 Minutes
```bash
# Session lasts 30 minutes
user123-country-jp-sessid-x9-sesstime-30:pass456@proxy.mrscraper.com:10000
```
```bash
# Session lasts 1 hour
user123-country-ca-sessid-long1-sesstime-60:pass456@proxy.mrscraper.com:10000
```
```bash
# Short 5-minute session
user123-country-fr-sessid-quick-sesstime-5:pass456@proxy.mrscraper.com:10000
```
**Node.js Example:**
```javascript
const axios = require('axios');
// 20-minute session proxy
const proxy = {
host: 'proxy.mrscraper.com',
port: 10000,
auth: {
username: 'user123-country-us-sessid-node_session-sesstime-20',
password: 'pass456'
}
};
async function testProxy() {
for (let i = 0; i < 10; i++) {
const response = await axios.get('https://api.ipify.org', { proxy });
console.log(`Request ${i+1}: ${response.data}`);
// Wait 2 minutes between requests
await new Promise(resolve => setTimeout(resolve, 120000));
}
}
testProxy();
```
**Use Cases:**
* Long scraping sessions
* Extended browsing sessions
* Multi-step workflows
* Testing with specific time constraints
## Authentication Summary
| Format | Country | Session | Duration | Rotation |
| ---------------------------------------------------- | ------------ | ------- | -------- | ------------- |
| `username:password` | US (default) | No | N/A | Every request |
| `username-country-{code}` | Specific | No | N/A | Every request |
| `username-country-{code}-sessid-{id}` | Specific | Yes | 10 min | After expiry |
| `username-country-{code}-sessid-{id}-sesstime-{min}` | Specific | No | Custom | After expiry |
## Best Practices
### Session ID Naming
* Use descriptive names: `user_john`, `checkout_session`, `scraper_1`
* Avoid special characters (stick to alphanumeric and underscores)
* Keep IDs under 50 characters for compatibility
### Security Considerations
* Never hardcode credentials in source code
* Use environment variables for username/password
* Rotate session IDs regularly
* Monitor proxy usage for anomalies
## Testing Your Configuration
Test your proxy configuration with a simple cURL command:
```bash
curl -x "username-country-us:password@proxy.mrscraper.com:10000" https://api.ipify.org
```
This returns your current proxy IP address. Run it multiple times to verify rotation behavior:
```bash
# Test rotation
for i in {1..5}; do
echo "Request $i:"
curl -x "user-country-us:pass@proxy.mrscraper.com:10000" https://api.ipify.org
echo ""
done
```
For session-based proxies, you should see the same IP across all requests:
```bash
# Test session persistence
for i in {1..5}; do
echo "Request $i:"
curl -x "user-country-us-sessid-test1:pass@proxy.mrscraper.com:10000" https://api.ipify.org
echo ""
done
```
## Common Errors
### Authentication Failed
* Verify your username and password are correct
* Check for typos in the format pattern
* Ensure no extra spaces in the username
### Country Not Supported
* Verify the country code is valid ISO 3166 format
* Check that the country is in Residential Proxy's coverage area
* Try a different country code
### Session Expired
* Increase `sesstime` value if sessions expire too quickly
* Implement automatic reconnection in your code
* Use the same `session_id` to maintain the session
# Country Codes
import { MapPin, Search, AlertCircle } from 'lucide-react';
## Country Codes (ISO 3166)
Residential Proxy uses **ISO 3166-1 alpha-2** country codes to target specific geographic locations. This standardized format ensures compatibility and consistency across all proxy configurations.
## What are ISO 3166 Country Codes?
ISO 3166-1 alpha-2 is an international standard that uses **two-letter codes** to represent countries and territories. Residential Proxy adopts this standard for country targeting in proxy configurations.
**Format:**
* Always **2 letters**
* Case-insensitive (but lowercase is recommended)
* Based on English country names
**Examples:**
* `us` → United States
* `gb` → United Kingdom
* `de` → Germany (Deutschland)
* `jp` → Japan
## How to Use Country Codes
Country codes are inserted into your proxy username using the `-country-` parameter.
**Basic Format:**
```bash
username-country-{code}:password@proxy.mrscraper.com:10000
```
**Examples:**
United States
United Kingdom
Germany
Japan
```bash
user123-country-us:pass456@proxy.mrscraper.com:10000
```
```bash
user123-country-gb:pass456@proxy.mrscraper.com:10000
```
```bash
user123-country-de:pass456@proxy.mrscraper.com:10000
```
```bash
user123-country-jp:pass456@proxy.mrscraper.com:10000
```
## Popular Country Codes
### North America
| Country | Code | Example |
| ------------- | ---- | ------------------------------------------------ |
| United States | `us` | `user-country-us:pass@proxy.mrscraper.com:10000` |
| Canada | `ca` | `user-country-ca:pass@proxy.mrscraper.com:10000` |
| Mexico | `mx` | `user-country-mx:pass@proxy.mrscraper.com:10000` |
### Europe
| Country | Code | Example |
| -------------- | ---- | ------------------------------------------------ |
| United Kingdom | `gb` | `user-country-gb:pass@proxy.mrscraper.com:10000` |
| Germany | `de` | `user-country-de:pass@proxy.mrscraper.com:10000` |
| France | `fr` | `user-country-fr:pass@proxy.mrscraper.com:10000` |
| Spain | `es` | `user-country-es:pass@proxy.mrscraper.com:10000` |
| Italy | `it` | `user-country-it:pass@proxy.mrscraper.com:10000` |
| Netherlands | `nl` | `user-country-nl:pass@proxy.mrscraper.com:10000` |
| Poland | `pl` | `user-country-pl:pass@proxy.mrscraper.com:10000` |
| Sweden | `se` | `user-country-se:pass@proxy.mrscraper.com:10000` |
| Switzerland | `ch` | `user-country-ch:pass@proxy.mrscraper.com:10000` |
| Belgium | `be` | `user-country-be:pass@proxy.mrscraper.com:10000` |
| Austria | `at` | `user-country-at:pass@proxy.mrscraper.com:10000` |
| Norway | `no` | `user-country-no:pass@proxy.mrscraper.com:10000` |
| Denmark | `dk` | `user-country-dk:pass@proxy.mrscraper.com:10000` |
| Finland | `fi` | `user-country-fi:pass@proxy.mrscraper.com:10000` |
| Ireland | `ie` | `user-country-ie:pass@proxy.mrscraper.com:10000` |
| Portugal | `pt` | `user-country-pt:pass@proxy.mrscraper.com:10000` |
| Greece | `gr` | `user-country-gr:pass@proxy.mrscraper.com:10000` |
| Czech Republic | `cz` | `user-country-cz:pass@proxy.mrscraper.com:10000` |
| Romania | `ro` | `user-country-ro:pass@proxy.mrscraper.com:10000` |
| Hungary | `hu` | `user-country-hu:pass@proxy.mrscraper.com:10000` |
| Bulgaria | `bg` | `user-country-bg:pass@proxy.mrscraper.com:10000` |
| Croatia | `hr` | `user-country-hr:pass@proxy.mrscraper.com:10000` |
| Serbia | `rs` | `user-country-rs:pass@proxy.mrscraper.com:10000` |
| Slovakia | `sk` | `user-country-sk:pass@proxy.mrscraper.com:10000` |
| Slovenia | `si` | `user-country-si:pass@proxy.mrscraper.com:10000` |
### Asia
| Country | Code | Example |
| -------------------- | ---- | ------------------------------------------------ |
| Japan | `jp` | `user-country-jp:pass@proxy.mrscraper.com:10000` |
| China | `cn` | `user-country-cn:pass@proxy.mrscraper.com:10000` |
| India | `in` | `user-country-in:pass@proxy.mrscraper.com:10000` |
| South Korea | `kr` | `user-country-kr:pass@proxy.mrscraper.com:10000` |
| Singapore | `sg` | `user-country-sg:pass@proxy.mrscraper.com:10000` |
| Indonesia | `id` | `user-country-id:pass@proxy.mrscraper.com:10000` |
| Thailand | `th` | `user-country-th:pass@proxy.mrscraper.com:10000` |
| Vietnam | `vn` | `user-country-vn:pass@proxy.mrscraper.com:10000` |
| Malaysia | `my` | `user-country-my:pass@proxy.mrscraper.com:10000` |
| Philippines | `ph` | `user-country-ph:pass@proxy.mrscraper.com:10000` |
| Hong Kong | `hk` | `user-country-hk:pass@proxy.mrscraper.com:10000` |
| Taiwan | `tw` | `user-country-tw:pass@proxy.mrscraper.com:10000` |
| Pakistan | `pk` | `user-country-pk:pass@proxy.mrscraper.com:10000` |
| Bangladesh | `bd` | `user-country-bd:pass@proxy.mrscraper.com:10000` |
| Israel | `il` | `user-country-il:pass@proxy.mrscraper.com:10000` |
| United Arab Emirates | `ae` | `user-country-ae:pass@proxy.mrscraper.com:10000` |
| Saudi Arabia | `sa` | `user-country-sa:pass@proxy.mrscraper.com:10000` |
| Turkey | `tr` | `user-country-tr:pass@proxy.mrscraper.com:10000` |
### Oceania
| Country | Code | Example |
| ----------- | ---- | ------------------------------------------------ |
| Australia | `au` | `user-country-au:pass@proxy.mrscraper.com:10000` |
| New Zealand | `nz` | `user-country-nz:pass@proxy.mrscraper.com:10000` |
### South America
| Country | Code | Example |
| --------- | ---- | ------------------------------------------------ |
| Brazil | `br` | `user-country-br:pass@proxy.mrscraper.com:10000` |
| Argentina | `ar` | `user-country-ar:pass@proxy.mrscraper.com:10000` |
| Chile | `cl` | `user-country-cl:pass@proxy.mrscraper.com:10000` |
| Colombia | `co` | `user-country-co:pass@proxy.mrscraper.com:10000` |
| Peru | `pe` | `user-country-pe:pass@proxy.mrscraper.com:10000` |
| Venezuela | `ve` | `user-country-ve:pass@proxy.mrscraper.com:10000` |
### Africa
| Country | Code | Example |
| ------------ | ---- | ------------------------------------------------ |
| South Africa | `za` | `user-country-za:pass@proxy.mrscraper.com:10000` |
| Egypt | `eg` | `user-country-eg:pass@proxy.mrscraper.com:10000` |
| Nigeria | `ng` | `user-country-ng:pass@proxy.mrscraper.com:10000` |
| Kenya | `ke` | `user-country-ke:pass@proxy.mrscraper.com:10000` |
| Morocco | `ma` | `user-country-ma:pass@proxy.mrscraper.com:10000` |
## Finding Country Codes
If you need a country code not listed above, you can:
1. **Search Online**: Use "ISO 3166-1 alpha-2 \[country name]"
2. **Check Wikipedia**: [ISO 3166-1 alpha-2 on Wikipedia](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)
3. **Common Patterns**: Usually the first two letters of the English country name
**Common Code Notes:**
* 🇬🇧 United Kingdom: `gb` (Great Britain) - this is the official ISO 3166 code
* 🇨🇭 Switzerland: `ch` (from Latin *Confoederatio Helvetica*)
* 🇬🇷 Greece: `gr` (from Greek)
* 🇰🇷 South Korea: `kr` (from **K**o**r**ea)
## Country Code Best Practices
### Case Sensitivity
Country codes are **case-insensitive**, but lowercase is recommended for consistency:
```bash
# All valid, but lowercase is preferred
user-country-us:pass@proxy.mrscraper.com:10000 # ✅ Recommended
user-country-US:pass@proxy.mrscraper.com:10000 # ✅ Valid
user-country-Us:pass@proxy.mrscraper.com:10000 # ✅ Valid but inconsistent
```
### Validation
Always verify your country code is correct before deployment:
```python
import requests
def test_country_proxy(country_code):
"""Test if a country code works with Residential Proxy"""
proxy = {
'http': f'http://user-country-{country_code}:pass@proxy.mrscraper.com:10000',
'https': f'http://user-country-{country_code}:pass@proxy.mrscraper.com:10000'
}
try:
response = requests.get('https://api.ipify.org', proxies=proxy, timeout=10)
print(f"✅ Country '{country_code}' works! IP: {response.text}")
return True
except Exception as e:
print(f"❌ Country '{country_code}' failed: {e}")
return False
# Test multiple countries
countries = ['us', 'gb', 'de', 'jp', 'au']
for country in countries:
test_country_proxy(country)
```
## Omitting the Country Code
The country parameter is optional. When you **don't specify** one, requests fall back to **United States (`us`)** IPs:
```bash
# No country specified = United States IPs
username:password@proxy.mrscraper.com:10000
# Equivalent to
username-country-us:password@proxy.mrscraper.com:10000
```
**Note:** The Residential Proxy UI always requires a country selection; only manual username configuration lets you omit it. Because omitting it still resolves to the US, set the country explicitly whenever the target region matters — relying on the default hides that intent from your code.
## Code Examples
### Python: Multi-Country Scraping
```python
import requests
from concurrent.futures import ThreadPoolExecutor
countries = ['us', 'gb', 'de', 'fr', 'jp', 'au']
def scrape_with_country(country_code):
"""Scrape using a specific country proxy"""
proxy = {
'http': f'http://user-country-{country_code}:pass@proxy.mrscraper.com:10000',
'https': f'http://user-country-{country_code}:pass@proxy.mrscraper.com:10000'
}
response = requests.get('https://example.com', proxies=proxy)
print(f"Scraped from {country_code.upper()}: {len(response.text)} bytes")
return response.text
# Scrape from all countries in parallel
with ThreadPoolExecutor(max_workers=len(countries)) as executor:
results = list(executor.map(scrape_with_country, countries))
```
### Node.js: Dynamic Country Selection
```javascript
const axios = require('axios');
const countries = ['us', 'gb', 'de', 'fr', 'jp'];
async function scrapeFromCountry(countryCode) {
const proxy = {
host: 'proxy.mrscraper.com',
port: 10000,
auth: {
username: `user-country-${countryCode}`,
password: 'pass123'
}
};
try {
const response = await axios.get('https://example.com', { proxy });
console.log(`Scraped from ${countryCode.toUpperCase()}: ${response.data.length} bytes`);
return response.data;
} catch (error) {
console.error(`Error with ${countryCode}:`, error.message);
}
}
// Scrape from multiple countries
async function scrapeAll() {
for (const country of countries) {
await scrapeFromCountry(country);
}
}
scrapeAll();
```
## Complete Country Code Reference
Below is the complete list of all ISO 3166-1 alpha-2 country codes supported by Residential Proxy:
**View All Country Codes (240+ countries)**
\- Click to expand
| Country | Code | | Country | Code |
| ------------------------------ | ---- | - | ------------------------- | ---- |
| Afghanistan | `af` | | Liechtenstein | `li` |
| Åland Islands | `ax` | | Lithuania | `lt` |
| Albania | `al` | | Luxembourg | `lu` |
| Algeria | `dz` | | Macao | `mo` |
| American Samoa | `as` | | North Macedonia | `mk` |
| Andorra | `ad` | | Madagascar | `mg` |
| Angola | `ao` | | Malawi | `mw` |
| Anguilla | `ai` | | Malaysia | `my` |
| Antarctica | `aq` | | Maldives | `mv` |
| Antigua and Barbuda | `ag` | | Mali | `ml` |
| Argentina | `ar` | | Malta | `mt` |
| Armenia | `am` | | Marshall Islands | `mh` |
| Aruba | `aw` | | Martinique | `mq` |
| Australia | `au` | | Mauritania | `mr` |
| Austria | `at` | | Mauritius | `mu` |
| Azerbaijan | `az` | | Mayotte | `yt` |
| Bahamas | `bs` | | Mexico | `mx` |
| Bahrain | `bh` | | Micronesia | `fm` |
| Bangladesh | `bd` | | Moldova | `md` |
| Barbados | `bb` | | Monaco | `mc` |
| Belarus | `by` | | Mongolia | `mn` |
| Belgium | `be` | | Montenegro | `me` |
| Belize | `bz` | | Montserrat | `ms` |
| Benin | `bj` | | Morocco | `ma` |
| Bermuda | `bm` | | Mozambique | `mz` |
| Bhutan | `bt` | | Myanmar | `mm` |
| Bolivia | `bo` | | Namibia | `na` |
| Bonaire | `bq` | | Nauru | `nr` |
| Bosnia and Herzegovina | `ba` | | Nepal | `np` |
| Botswana | `bw` | | Netherlands | `nl` |
| Bouvet Island | `bv` | | New Caledonia | `nc` |
| Brazil | `br` | | New Zealand | `nz` |
| British Indian Ocean Territory | `io` | | Nicaragua | `ni` |
| Brunei | `bn` | | Niger | `ne` |
| Bulgaria | `bg` | | Nigeria | `ng` |
| Burkina Faso | `bf` | | Niue | `nu` |
| Burundi | `bi` | | Norfolk Island | `nf` |
| Cambodia | `kh` | | Northern Mariana Islands | `mp` |
| Cameroon | `cm` | | Norway | `no` |
| Canada | `ca` | | Oman | `om` |
| Cape Verde | `cv` | | Pakistan | `pk` |
| Cayman Islands | `ky` | | Palau | `pw` |
| Central African Republic | `cf` | | Palestine | `ps` |
| Chad | `td` | | Panama | `pa` |
| Chile | `cl` | | Papua New Guinea | `pg` |
| China | `cn` | | Paraguay | `py` |
| Christmas Island | `cx` | | Peru | `pe` |
| Cocos Islands | `cc` | | Philippines | `ph` |
| Colombia | `co` | | Pitcairn | `pn` |
| Comoros | `km` | | Poland | `pl` |
| Congo | `cg` | | Portugal | `pt` |
| Congo (DRC) | `cd` | | Puerto Rico | `pr` |
| Cook Islands | `ck` | | Qatar | `qa` |
| Costa Rica | `cr` | | Réunion | `re` |
| Côte d'Ivoire | `ci` | | Romania | `ro` |
| Croatia | `hr` | | Russian Federation | `ru` |
| Cuba | `cu` | | Rwanda | `rw` |
| Curaçao | `cw` | | Saint Barthélemy | `bl` |
| Cyprus | `cy` | | Saint Helena | `sh` |
| Czech Republic | `cz` | | Saint Kitts and Nevis | `kn` |
| Denmark | `dk` | | Saint Lucia | `lc` |
| Djibouti | `dj` | | Saint Martin | `mf` |
| Dominica | `dm` | | Saint Pierre and Miquelon | `pm` |
| Dominican Republic | `do` | | Saint Vincent | `vc` |
| Ecuador | `ec` | | Samoa | `ws` |
| Egypt | `eg` | | San Marino | `sm` |
| El Salvador | `sv` | | Sao Tome and Principe | `st` |
| Equatorial Guinea | `gq` | | Saudi Arabia | `sa` |
| Eritrea | `er` | | Senegal | `sn` |
| Estonia | `ee` | | Serbia | `rs` |
| Eswatini | `sz` | | Seychelles | `sc` |
| Ethiopia | `et` | | Sierra Leone | `sl` |
| Falkland Islands | `fk` | | Singapore | `sg` |
| Faroe Islands | `fo` | | Sint Maarten | `sx` |
| Fiji | `fj` | | Slovakia | `sk` |
| Finland | `fi` | | Slovenia | `si` |
| France | `fr` | | Solomon Islands | `sb` |
| French Guiana | `gf` | | Somalia | `so` |
| French Polynesia | `pf` | | South Africa | `za` |
| French Southern Territories | `tf` | | South Georgia | `gs` |
| Gabon | `ga` | | South Sudan | `ss` |
| Gambia | `gm` | | Spain | `es` |
| Georgia | `ge` | | Sri Lanka | `lk` |
| Germany | `de` | | Sudan | `sd` |
| Ghana | `gh` | | Suriname | `sr` |
| Gibraltar | `gi` | | Svalbard and Jan Mayen | `sj` |
| Greece | `gr` | | Sweden | `se` |
| Greenland | `gl` | | Switzerland | `ch` |
| Grenada | `gd` | | Syria | `sy` |
| Guadeloupe | `gp` | | Taiwan | `tw` |
| Guam | `gu` | | Tajikistan | `tj` |
| Guatemala | `gt` | | Tanzania | `tz` |
| Guernsey | `gg` | | Thailand | `th` |
| Guinea | `gn` | | Timor-Leste | `tl` |
| Guinea-Bissau | `gw` | | Togo | `tg` |
| Guyana | `gy` | | Tokelau | `tk` |
| Haiti | `ht` | | Tonga | `to` |
| Heard Island | `hm` | | Trinidad and Tobago | `tt` |
| Holy See | `va` | | Tunisia | `tn` |
| Honduras | `hn` | | Turkey | `tr` |
| Hong Kong | `hk` | | Turkmenistan | `tm` |
| Hungary | `hu` | | Turks and Caicos Islands | `tc` |
| Iceland | `is` | | Tuvalu | `tv` |
| India | `in` | | Uganda | `ug` |
| Indonesia | `id` | | Ukraine | `ua` |
| Iran | `ir` | | United Arab Emirates | `ae` |
| Iraq | `iq` | | United Kingdom | `gb` |
| Ireland | `ie` | | United States | `us` |
| Isle of Man | `im` | | US Minor Outlying Islands | `um` |
| Israel | `il` | | Uruguay | `uy` |
| Italy | `it` | | Uzbekistan | `uz` |
| Jamaica | `jm` | | Vanuatu | `vu` |
| Japan | `jp` | | Venezuela | `ve` |
| Jersey | `je` | | Vietnam | `vn` |
| Jordan | `jo` | | Virgin Islands (British) | `vg` |
| Kazakhstan | `kz` | | Virgin Islands (U.S.) | `vi` |
| Kenya | `ke` | | Wallis and Futuna | `wf` |
| Kiribati | `ki` | | Western Sahara | `eh` |
| North Korea | `kp` | | Yemen | `ye` |
| South Korea | `kr` | | Zambia | `zm` |
| Kuwait | `kw` | | Zimbabwe | `zw` |
| Kyrgyzstan | `kg` | | | |
| Laos | `la` | | | |
| Latvia | `lv` | | | |
| Lebanon | `lb` | | | |
| Lesotho | `ls` | | | |
| Liberia | `lr` | | | |
| Libya | `ly` | | | |
**Note:** Not all countries may have proxy coverage. Availability depends on Residential Proxy's network infrastructure in each region. Contact support to verify coverage for specific countries.
## Common Errors
### Invalid Country Code
**Error:** Connection fails or times out
**Cause:** Country code doesn't exist or is misspelled
**Solution:** Verify the code against ISO 3166-1 alpha-2 standard
```bash
# ❌ Wrong
user-country-usa:pass@proxy.mrscraper.com:10000 # Should be 'us', not 'usa'
# ✅ Correct
user-country-us:pass@proxy.mrscraper.com:10000
```
### Country Not Supported
**Error:** Connection fails or times out
**Cause:** Country code is valid but not in Residential Proxy's coverage
**Solution:** Try a nearby country or contact support
### Wrong Country Format
**Error:** Authentication fails
**Cause:** Incorrect parameter name or position
**Solution:** Use `-country-` exactly as shown
```bash
# ❌ Wrong formats
user-c-us:pass@proxy.mrscraper.com:10000 # Wrong parameter name
user-us-country:pass@proxy.mrscraper.com:10000 # Wrong order
# ✅ Correct format
user-country-us:pass@proxy.mrscraper.com:10000
```
# IP Authorization
import { ShieldCheck, Key, Globe, Server, CheckCircle2, Clock, AlertTriangle, Info, Terminal, HelpCircle } from 'lucide-react';
import { Step, Steps } from 'fumadocs-ui/components/steps';
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';
IP Authorization (IP Whitelisting) allows you to authorize trusted IP addresses to connect to **MrScraper Residential Proxy** without providing proxy credentials (`username:password`) for every request.
When your server or network IP address is added to the authorized list, MrScraper automatically recognizes incoming traffic from that IP and validates access.
## Why Use IP Authorization?
While standard proxy authentication relies on credentials embedded within each request URL, IP Authorization authenticates connections at the network layer based on your source IP.
}>
Eliminate the need to store, pass, or hardcode proxy usernames and passwords in application code or scripts.
}>
Ideal for cloud instances, VPS deployments, and automated web scrapers running from fixed server IPs.
}>
Seamlessly connect tools, third-party software, and legacy systems that don't support custom proxy auth strings.
### Comparison: Credential Auth vs. IP Authorization
| Feature | Credential Authentication | IP Authorization |
| :------------------------- | :----------------------------------- | :----------------------- |
| **Authentication Method** | Username & Password | IP Address Whitelist |
| **Setup Location** | Client Code / Request URL | MrScraper Dashboard |
| **Dynamic Server Support** | Yes (Works from any IP) | Requires Fixed Server IP |
| **Credential Storage** | Stored in code / environment | Not required in code |
| **Targeting Modifiers** | Embedded in username (`-country-us`) | Proxy request headers |
## 1. Finding Your Public IP Address
Before configuring IP Authorization, you must identify the **public IPv4 address** of the machine, server, or cloud instance that will connect to the proxy.
**Important:** You must authorize your **Public IP**, not internal/private addresses such as `192.168.x.x`, `10.x.x.x`, or `172.16.x.x`.
Run one of the following commands from your server terminal to determine your public IP:
cURL (Linux/macOS)
cURL (Alternative)
PowerShell (Windows)
```bash
curl -4 https://api.ipify.org
```
```bash
curl -4 https://ifconfig.me
```
```powershell
(Invoke-WebRequest -UseBasicParsing -Uri "https://api.ipify.org").Content
```
## 2. Adding an Authorized IP
Follow these steps to add a new trusted IP address to your whitelist:
### Open Proxy Settings
Log in to your [MrScraper Dashboard](https://app.mrscraper.com) and navigate to the **Residential Proxy** section from the sidebar.
### Select IP Authorization
Click on the **IP Authorization** tab to view your current whitelisted IP addresses.
### Enter Your Public IP
Paste your public IPv4 address into the **Add new IP** input field.
### Confirm and Add
Click the **Add IP** button. Your IP will immediately appear in the authorized IPs table.
## 3. IP Status Lifecycle
Once an IP address is added, it transitions through two statuses:
| Status | Description | Action Required |
| :--------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------- | :------------------------------------------------ |
| Applying | The system is propagating your IP across global edge nodes. This usually takes **up to 2 minutes**. | Wait briefly before initiating proxy connections. |
| Active | The IP address is fully authorized and active across all proxy clusters. | Ready to connect without credentials. |
If an IP status remains in **Applying** for more than 5 minutes, try refreshing your browser or contact MrScraper support.
## 4. Connecting via Authorized IP
Once your status is **Active**, you can send proxy traffic directly through `proxy.mrscraper.com:10000` without passing credentials in the URL.
```bash
# Connect directly without username/password
curl -x proxy.mrscraper.com:10000 https://api.ipify.org
```
```python
import requests
# Set proxy host and port without credentials
proxies = {
'http': 'http://proxy.mrscraper.com:10000',
'https': 'http://proxy.mrscraper.com:10000'
}
response = requests.get('https://api.ipify.org', proxies=proxies)
print(f"Connected successfully via IP Auth. Response IP: {response.text}")
```
```javascript
const axios = require('axios');
axios.get('https://api.ipify.org', {
proxy: {
host: 'proxy.mrscraper.com',
port: 10000
}
})
.then(response => console.log('Response IP:', response.data))
.catch(error => console.error('Error:', error.message));
```
```go
package main
import (
"fmt"
"io"
"net/http"
"net/url"
)
func main() {
proxyURL, _ := url.Parse("http://proxy.mrscraper.com:10000")
client := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(proxyURL),
},
}
resp, err := client.Get("https://api.ipify.org")
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Printf("Connected via IP Auth. Output: %s\n", string(body))
}
```
```php
```
## 5. Country & Session Targeting
With IP Authorization, configure country and session targeting with headers sent to the **proxy connection**. Do not add targeting modifiers to a username or password.
| Header | Example | Purpose |
| :----------------- | :-------- | :------------------------------------------------------------ |
| `X-Proxy-Country` | `us` | Select the proxy country using its country code. |
| `X-Proxy-Sessid` | `abcd123` | Keep a consistent proxy session with the supplied session ID. |
| `X-Proxy-Sesstime` | `10` | Set the session lifetime in minutes. |
Configure these values through your HTTP client's proxy-header or equivalent proxy-connection header option. They must be sent to the proxy, not as ordinary headers to the destination website.
For example, the proxy connection should include headers equivalent to:
```text
X-Proxy-Country: us
X-Proxy-Sessid: abcd123
X-Proxy-Sesstime: 10
```
If your client does not support proxy-specific headers, use a client or adapter that can set headers on the proxy connection. Keep the proxy host, port, and IP Authorization setup unchanged.
## 6. Managing Whitelisted IPs
You can manage existing authorized IPs directly from the IP Authorization table:
### Copying an IP Address
Click the **Copy** icon in the Action column next to any authorized IP to quickly copy it to your clipboard for verification or sharing with team members.
### Removing an IP Address
To remove access for a server or IP:
1. Locate the IP address in the IP Authorization list.
2. Click the **Delete** icon in the Action column.
3. Confirm the removal prompt. Access will be revoked within 2 minutes.
## 7. Security Best Practices
**Security Warning:** Anyone issuing requests from an authorized IP address can consume your proxy bandwidth. Treat an authorized IP address with the same security diligence as secret credentials.
* **Fixed IPs Only:** Only whitelist static public IPs assigned to dedicated servers, cloud instances (AWS EC2, DigitalOcean, GCP), or office routers.
* **Avoid Public & Dynamic IPs:** Never authorize dynamic home connections, public Wi-Fi networks, or shared VPN endpoints.
* **Regular Audits:** Periodically review your whitelist and delete unused IPs or those belonging to decommissioned servers.
* **Immediate Deletion:** Promptly remove server IPs when terminating cloud instances or ending vendor contracts.
## Frequently Asked Questions
This error occurs if your request is originating from an IP address that is not listed in your whitelist, or if the IP status is still in the **Applying** state. Ensure your current public IP matches the whitelist entry and that the status has changed to **Active**.
IP Authorization is intended for static/fixed IP addresses. If your home or server IP changes frequently (dynamic IP), we recommend using standard **Username & Password Authentication** instead.
Currently, IP Authorization only requires specific single IPv4 addresses (`/32`).
Adding or removing an IP address typically takes **around 2 minutes** to propagate across all edge nodes globally.
# Proxy Types
import { RefreshCw, Pin } from 'lucide-react';
Residential Proxy offers **Static** and **Rotating** proxies, each designed for different use cases. Choose the right type based on whether you need consistent IP sessions or maximum distribution.
## Proxy Protocols
Residential Proxy supports both HTTP and SOCKS5 connections:
| Protocol | Proxy URL prefix | Port | Best for |
| ---------- | ---------------- | ------- | ------------------------------------------------------------------------ |
| **HTTP** | `http://` | `10000` | HTTP requests, browser automation, and standard scraping clients |
| **SOCKS5** | `socks5://` | `10001` | Applications that require SOCKS5 support or proxying traffic beyond HTTP |
The full proxy URL uses this format:
```text
{protocol}://username:password@proxy.mrscraper.com:{port}
```
For example:
```text
http://user-country-us:pass@proxy.mrscraper.com:10000
socks5://user-country-us:pass@proxy.mrscraper.com:10001
```
## Static vs Rotating Proxies
### Static Proxy
A static proxy maintains the same IP address throughout a session. By using a session ID, all requests within that session are routed through the same IP until the session expires.
**Key Features:**
* Same IP address for all requests within the session
* Configurable session duration (default: 10 minutes)
* Consistent identity across requests
* Ideal for stateful operations
**Authentication Format:**
```bash
http://username-country-{code}-sessid-{id}-sesstime-{minutes}:password@proxy.mrscraper.com:10000
socks5://username-country-{code}-sessid-{id}-sesstime-{minutes}:password@proxy.mrscraper.com:10001
```
**Example:**
```python
import requests
# Static proxy with 30-minute session
proxy = {
'http': 'http://user-country-us-sessid-stable1-sesstime-30:pass@proxy.mrscraper.com:10000',
'https': 'http://user-country-us-sessid-stable1-sesstime-30:pass@proxy.mrscraper.com:10000'
}
# All requests use the same IP
for i in range(10):
response = requests.get('https://api.ipify.org', proxies=proxy)
print(f"Request {i+1}: {response.text}") # Same IP every time
```
**Perfect For:**
| **Account Operations** | **Stable Scraping Sessions** | **Financial Transactions** |
| -------------------------------- | ----------------------------------------- | ----------------------------------- |
| ✅ Login and authentication flows | ✅ Multi-page form submissions | ✅ Payment processing |
| ✅ Session-based interactions | ✅ Workflows requiring consistent identity | ✅ Banking operations |
| ✅ Account management dashboards | ✅ APIs that track IP changes | ✅ Any flow requiring IP consistency |
| ✅ Shopping cart operations | ✅ Testing session persistence | |
**Tip:** Start with a 10-minute session for testing. Increase duration for longer workflows, but keep it under 60 minutes for optimal IP freshness.
### Rotating Proxy
A rotating proxy automatically changes IP addresses either on every request or when the session expires, assigning a new IP to each request or session.
**Key Features:**
* Different IP for each request (or after session expiry)
* Maximum distribution across IP pool
* Reduces detection risk
* Ideal for high-volume operations
**Authentication Format (No Session):**
```bash
http://username-country-{code}:password@proxy.mrscraper.com:10000
socks5://username-country-{code}:password@proxy.mrscraper.com:10001
```
**Example:**
```python
import requests
# Rotating proxy - new IP each request
proxy = {
'http': 'http://user-country-us:pass@proxy.mrscraper.com:10000',
'https': 'http://user-country-us:pass@proxy.mrscraper.com:10000'
}
# Each request gets a different IP
for i in range(10):
response = requests.get('https://api.ipify.org', proxies=proxy)
print(f"Request {i+1}: {response.text}") # Different IP each time
```
**Perfect For:**
| **Large-Scale Scraping** | **Avoiding Rate Limits** | **Reducing Bans** |
| ----------------------------- | ---------------------------------- | ------------------------------------ |
| ✅ Crawling thousands of pages | ✅ Bypassing per-IP restrictions | ✅ Appearing as different users |
| ✅ High-volume data extraction | ✅ Distributing load across IPs | ✅ Avoiding IP-based blacklists |
| ✅ Distributed scraping tasks | ✅ Reducing ban risk | ✅ Scraping aggressive anti-bot sites |
| ✅ Avoiding rate limits | ✅ Testing rate limiting mechanisms | ✅ Market research at scale |
**Note:** Rotating proxies are not suitable for workflows requiring session persistence, such as login flows or multi-step forms.
## Comparison
| Feature | Static Proxy | Rotating Proxy |
| -------------------- | -------------------------------- | ------------------------------------------ |
| **IP Behavior** | Same IP per session | New IP per request |
| **Session Support** | ✅ Yes (via session ID) | ❌ No session needed |
| **Use Case** | Login flows, stateful operations | High-volume scraping, rate limit avoidance |
| **Session Duration** | Configurable (default 10 min) | N/A |
| **Best For** | Consistency required | Maximum distribution |
## Which Type Should I Use?
}>
* Login and authentication flows
* Shopping carts and multi-step forms
* Sites that track IP changes
* Session-based operations
}>
* Large-scale scraping (1000+ pages)
* Bypassing rate limits
* Maximum IP distribution
* No session persistence needed
# Overview
import { Globe, Smartphone, Lock, Timer, RotateCcw, Shield } from 'lucide-react';
import { Database, UserCog, Share2 } from 'lucide-react';
import { Step, Steps } from 'fumadocs-ui/components/steps';
MrScraper provides enterprise-grade proxy solutions designed for web scraping, data collection, and anonymous browsing. Static and rotating configurations, and global coverage, that delivers the reliability and flexibility your projects need.
## What is MrScraper's Residential Proxy?
MrScraper's Residential Proxy is a premium proxy service offering:
* **Residential Proxies**: Access real user IPs from residential ISPs
* **Static & Rotating Options**: Choose between persistent IPs or automatic rotation
* **Global Coverage**: Support for 100+ countries using ISO 3166 country codes
* **Session Management**: Control IP persistence with custom session IDs and durations
* **Easy Integration**: Simple authentication format compatible with any HTTP/HTTPS client
## Key Features
} href="/docs/residential-proxy/configuration/proxy-types">
Choose between Static and Rotating proxies for different use cases.
} href="/docs/residential-proxy/configuration/authentication">
Learn how to configure proxy authentication with username patterns.
} href="/docs/residential-proxy/configuration/authentication#3-session-based-static-proxy">
Maintain persistent IPs with custom session IDs and durations.
} href="/docs/residential-proxy/configuration/country-codes">
Target specific countries using ISO 3166 country codes.
## Proxy Endpoint
All Residential Proxy services connect through a single endpoint:
```
proxy.mrscraper.com:10000
```
Your authentication credentials (username and password) determine:
* Proxy type
* Country targeting
* Session persistence
* Rotation behavior
## Common Use Cases
}>
Use rotating proxies to avoid rate limits and IP bans when scraping large amounts of data.
}>
Use static session-based proxies to maintain consistent IPs for account operations and dashboards.
}>
Use country-specific proxies to view localized content and pricing.
## Quick Start
### Get Your Credentials
Obtain your MrScraper username and password from your account dashboard.
### Choose Your Configuration
Decide on your [proxy type](/docs/residential-proxy/configuration/proxy-types), [country](/docs/residential-proxy/configuration/country-codes), and whether you need session persistence.
### Format Your Authentication
Build your username string according to the [authentication format](/docs/residential-proxy/configuration/authentication).
### Connect and Test
Use the format: `username:password@proxy.mrscraper.com:10000` in your application.
## Need Help?
If you have questions or need assistance:
* Check our [Examples page](/docs/residential-proxy/examples/overview) for common configurations
* Review the [Authentication guide](/docs/residential-proxy/configuration/authentication) for username format details
* Contact our support team for personalized assistance
# Proxy Generator
import { Step, Steps } from 'fumadocs-ui/components/steps';
## Generate A Proxy
You generate residential proxy credentials for use outside the Proxy Scraper. For example, in your own scripts, third-party tools, or external applications.
Follow these steps to generate a residential proxy:
Go to the **Proxies** page by clicking the **globe icon** in the left sidebar.
Select the **Proxy Setup** tab.
### Configuration
You can configure your proxy here
#### Proxy Access
Get your `Username` and `Password` for your proxy here.
#### Proxy List
Copy, Download or Delete your proxy list here.
#### Proxy Configuration
Main proxy configuration:
* `Connection Settings` : `Static` or `Rotating`
* `Protocol` : `HTTP` or `SOCKS5`
* `Country` : Pick the country you want your request to appear from. Uses ISO 3166-1 alpha-2 codes (e.g. United States → `us`).
Click **Generate** to create a new proxy credential.
Copy the generated proxy URL and use it in your application or tool. Or use generated code from **Integration Code** panel.
supported framework/library :
* Puppeteer (JavaScript)
* Playwright (JavaScript & Python)
* CloakBrowser (JavaScript & Python)
* Selenium (Python)
# Proxy Scraper
import { Step, Steps } from 'fumadocs-ui/components/steps';
The **Proxy Scraper** is a standalone scraping service available on the [Proxies page](https://app.mrscraper.com/proxies). It routes requests through residential proxies, allowing you to specify a target URL, select a proxy country, and retrieve the scraped content directly from a single interface.
## Proxies Page Tabs
The [**Proxies page**](https://app.mrscraper.com/proxies) is organized into four tabs:
| Tab | Description |
| ----------------- | -------------------------------------------------------------------------- |
| **Proxy Scraper** | Scrape any URL through a proxy using MrScraper's built-in scraping engine. |
| **Proxy Setup** | Generate and configure residential proxy credentials for external use. |
| **Analytics** | Monitor proxy bandwidth consumption and request statistics. |
| **Proxy Users** | Create sub-user accounts and allocate proxy bandwidth. |
* When you switch between tabs, your scrape results are preserved. You can navigate away and return to find your results intact.
* If a scrape is in progress, you receive a warning before switching tabs to prevent losing an active request.
* Completed proxy scrape results are also available on the Result section. If you navigate away during a long-running scrape, you can find the results there.
* Your active tab is saved in the URL parameters. You can bookmark or share a direct link to any tab, and it will open in the same state when revisited.
## Proxy Scraper
The **Proxy Scraper** tab is an interactive playground for running on-demand, proxy-powered scraping requests. It shares the same interface layout as the [Playground](/docs/getting-started/playground) but adds a proxy country selector so every request is routed through a residential proxy.
Enter a **Target URL**, select a **proxy country** from the dropdown, and click **Run**. MrScraper's scraping engine fetches the page through a residential proxy in the selected region and returns the extracted content.
When a proxy scrape finishes, you receive an in-app notification confirming the result is ready. This lets you queue a request and continue working without watching the screen.
### Target URL
In the **Target URL** panel, you configure and run the request:
* Enter the target URL.
* Select **Run** to send the request, or **Reset** to clear the current configuration.
* Select a country to load the page from.
### API Token
You can copy your secret API token for authenticating requests to the MrScraper API. Keep this value private.
### Request Options
The request options panel controls how the proxy scraper handles each request. Adjust these settings to improve reliability and performance.
| Setting | Default | Description |
| --------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------- |
| **Timeout (seconds)** | `90` | Maximum time in seconds to wait for the page to load. |
| **Max retries** | `3` | Maximum number of retry attempts if the scrape fails. Failed requests are automatically retried up to this limit. |
| **Wait for selector** | None | Pause until a specific CSS selector appears in the DOM. Useful for content that loads asynchronously after the initial page load. |
| **Super** | Off | Uses additional resources to improve extraction accuracy on complex or protected websites. |
| **From Homepage** | Off | Redirect to the target homepage first before going to the target URL. |
| **Browser rendering** | Off | Renders the page in a headless browser, executing JavaScript before extracting content. Required for SPAs and dynamic websites. |
| **Block resources** | Off | Skips non-essential assets (images, fonts, CSS) to reduce bandwidth and improve speed. |
Our bandwidth is not 1:1 with the bandwidth you see in your browser when opening the target page. This is due to our retry mechanism and techniques used to avoid blocking from the page.
## Proxy Setup
The **Proxy Setup** tab lets you generate residential proxy credentials for use outside the Proxy Scraper. For example, in your own scripts, third-party tools, or external applications.
Follow these steps to generate a residential proxy:
Go to the **Proxies** page by clicking the **globe icon** in the left sidebar.
Select the **Proxy Setup** tab.
Scroll down to the **Proxy Configuration** section and configure your proxy settings.
Click **Generate** to create a new proxy credential.
Copy the generated proxy URL and use it in your application or tool.
## Analytics
The **Analytics** tab provides a real-time overview of your proxy bandwidth consumption and request performance. It displays the following summary cards:
| Metric | Description |
| ------------------- | --------------------------------------------------------- |
| **Total Bandwidth** | Total proxy bandwidth consumed (displayed in MB or GB). |
| **Total Requests** | Number of proxy requests made within the selected period. |
| **Success Rate** | Percentage of proxy requests that completed successfully. |
| **Success** | Count of successful proxy requests. |
| **Failed** | Count of failed proxy requests. |
### Available Filters
You can narrow the analytics view using the following filters:
| Filter | Description |
| -------------- | --------------------------------------------------------------- |
| **Time Range** | Select a time window (e.g., 1 Hour, 24 Hours, 7 Days, 30 Days). |
| **Interval** | Choose the data granularity (e.g., Hourly, Daily). |
| **Username** | Filter by a specific proxy sub-user. |
| **Country** | Filter by proxy country/region. |
| **Timezone** | View data in your preferred timezone. |
Analytics data may take up to 5 minutes to update. The dashboard refreshes automatically, or you can click the refresh icon on the top right manually to fetch the latest data.
## Proxy Users
This tab is still in `Beta` phase
The **Proxy Users** tab lets you create and manage sub-user accounts for your proxy service. Each sub-user receives their own credentials and a dedicated bandwidth allocation drawn from your main proxy bandwidth pool.
This is useful when you need to:
* Distribute proxy access across team members or clients
* Control and limit bandwidth usage per user
* Track individual proxy consumption separately
### Creating a Sub-User
Follow these steps to create a new proxy sub-user:
Navigate to the **Proxies** page and select the **Proxy Users** tab.
Click the **+ Create Sub-User** button in the top-right corner.
In the **Create Sub-User** dialog, fill in the following fields:
* **Username suffix** *(optional)*: Enter a suffix to append to your account email. Only alphanumeric characters are allowed; symbols and hyphens are not permitted.
* **Bandwidth Quota**: Enter the amount of bandwidth (in MB) to allocate to this sub-user. The value is drawn from your unallocated bandwidth pool.
Click **OK** to create the sub-user.
You can create up to 80 sub-user.
### Renaming username
You can rename a username suffix in the Proxy User table by clicking the edit icon beside the username.
### Editing Bandwidth Allocation
To change a sub-user's bandwidth limit:
Locate the sub-user in the table.
Click the **edit icon** (pencil) next to the **Bandwidth Limit** value.
Enter the new bandwidth amount (in MB).
For user with `Enterprise` plan you can select `Unlimited` to pay as you go.
Confirm the change.
The updated allocation is reflected immediately. Any bandwidth freed up returns to the unallocated pool.
### Deleting a Sub-User
To remove a sub-user, click the **delete icon** (trash) next to their row in the table. The bandwidth that was allocated to the deleted sub-user is returned to your unallocated pool.
# Troubleshoot URL Access
import { Step, Steps } from 'fumadocs-ui/components/steps';
When a target website doesn't load through your proxy integration, it can be hard to tell whether the issue lies in the proxy configuration, or the target site's defenses. This guide walks you through a structured process to isolate the cause and resolve it.
## Why target websites block proxy requests
Websites use several techniques to detect and block non-human traffic. Even with residential proxy IPs, a request can still fail if:
* **Web Application Firewalls (WAF)** like Cloudflare, Akamai, or AWS WAF inspect request patterns and block suspicious traffic.
* **CAPTCHA challenges** are triggered by rate limiting or behavioral analysis.
* **Bot detection systems** flag requests that lack proper browser fingerprints (headers, cookies, JavaScript execution).
* **Geo-restrictions** block access from certain countries or regions.
* **Rate limiting** blocks IPs that send too many requests in a short period.
* **TLS fingerprinting** identifies non-browser HTTP clients by their TLS handshake characteristics.
Understanding these causes helps you pick the right fix. The fastest way to start is to use **Proxy Scraper** to test whether the issue is on your side or the proxy side.
## Test with Proxy Scraper
[Proxy Scraper](/docs/residential-proxy/getting-started/proxy-scraper) is a standalone scraping tool built into MrScraper. It sends requests through the same residential proxy network. This isolates the proxy path from your code path.
Go to [app.mrscraper.com](https://app.mrscraper.com), sign in, and select **Proxy** from the left navigation menu. Then select the [**Proxy Scraper**](https://app.mrscraper.com/proxies?tab=Proxy+Scraper) tab.
Enter a simple, reliable URL in the **Target URL** field. For example, `https://www.google.com`. Keep all advanced settings at their defaults. Click **Run**.
If Proxy Scraper returns an **HTTP 200** response with page content, the proxy connection is working. Proceed to the next step.
If it returns an error, see [When the connectivity test fails](#when-the-connectivity-test-fails) below.
Now enter the **real target URL**. Click **Run** with the same default settings.
## Interpret the results
Use the table below to determine your next action based on the Proxy Scraper results:
| google.com result | Target URL result | What it means | Next action |
| ----------------- | ----------------- | ------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| ✅ Success | ✅ Success | The proxy path works. The website target detecting the scraping script. | You can check your proxy configuration or continue using our Proxy Scraper to access your website target. |
| ✅ Success | ❌ Failure | The proxy path works, but the target website is blocking the request. | Go to [Bypass target website defenses](#bypass-target-website-defenses). |
| ❌ Failure | ❌ Failure | The proxy path itself has an issue. | Go to [When the connectivity test fails](#when-the-connectivity-test-fails). |
| ❌ Failure | ✅ Success | Unlikely, but possible if google.com is blocked in the selected proxy country. Try a different proxy country. | Change the proxy country and retest. |
## Check your configuration
If Proxy Scraper succeeds but your own code or tool fails, the issue is in how your integration sends requests. Check the following:
### Proxy credentials
* Verify your **username** and **password** are correct and match the format described in the [Authentication guide](/docs/residential-proxy/configuration/authentication).
* Check for typos, extra spaces, or missing segments (e.g., `-country-`, `-sessid-`).
### Request format
* Ensure you're using the correct proxy endpoint: `proxy.mrscraper.com:10000`.
* Verify the proxy protocol. MrScraper supports HTTP. Make sure your client is configured to use the HTTP protocol.
* Check that the target URL includes the protocol (`http://`).
### HTTP headers
* Some websites block requests that lack a proper `User-Agent` header. Make sure your client sends a realistic browser User-Agent.
* Include standard headers like `Accept`, `Accept-Language`, and `Accept-Encoding` to reduce the chance of being flagged as a bot.
### Network and firewall
* Confirm your network allows outbound connections to `proxy.mrscraper.com` on port `10000`.
* If you're behind a corporate firewall or VPN, check whether proxy traffic is being intercepted or blocked.
## Bypass target website defenses
If Proxy Scraper can reach google.com but fails on your target URL, the target website is actively blocking the request. Try the following escalation steps **in order**:
### Try a different proxy country
Some websites only serve traffic from specific regions. Change the proxy country in Proxy Scraper to one that matches the target website's expected audience (e.g., `us` for a US-based website).
### Enable Browser rendering
Toggle **Browser rendering** to **On** in the Proxy Scraper request options. This renders the page in a headless browser, executing JavaScript before extracting content. This is required for:
* Single-page applications (SPAs)
* Websites that load content dynamically via JavaScript
* Pages behind JavaScript-based challenges
### Adjust timeout and retries
Increase the **Timeout** beyond the default 90 seconds, and set **Max retries** to 5 or higher. Some heavily protected websites are slow to respond or require multiple attempts.
### Verify the block manually in a browser
Before assuming the proxy IPs are at fault, browse the target website through the same proxy in a real browser, arriving from a Google search and navigating to the page like a human would. If the page loads that way, the IPs are fine and the website is detecting your scraper, not your proxy. See [Verify a Block Manually](/docs/residential-proxy/getting-started/verify-block-manually).
### Contact support
If none of the above steps resolve the issue, the target website may require custom handling. Contact [us](mailto:support@mrscraper.com) with the following details:
* The target URL that fails
* The Proxy Scraper result (screenshot or response)
* The proxy country you tested with
* The settings you've tried (Super, Browser rendering, timeout)
## When the connectivity test fails
If Proxy Scraper cannot reach even a simple URL like google.com, check the following:
| Possible cause | What to check |
| --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Account or subscription issue** | Verify your account is active and has remaining proxy bandwidth in the **Analytics** tab. |
| **Service outage** | Check if MrScraper is experiencing an outage. Try again in a few minutes. |
| **Proxy country unavailable** | Some proxy countries may have limited availability. Try a different country code from the [supported countries list](/docs/residential-proxy/configuration/country-codes). |
| **Browser or network issue** | Try accessing [app.mrscraper.com](https://app.mrscraper.com) in an incognito/private window to rule out browser cache or extension interference. |
If the issue persists, contact support at [support@mrscraper.com](mailto:support@mrscraper.com).
# Verify a Block Manually
import { Step, Steps } from 'fumadocs-ui/components/steps';
When a scraper suddenly starts getting blocked, the proxy is the easiest thing to blame. But in most cases the target website has tightened its bot detection, and the same IPs still work fine for ordinary browsing.
This guide walks through a manual test: browse the target website through your Residential Proxy in a real browser, exactly the way a human would. The result tells you which side the block is actually coming from.
Use this test when your scraper worked before and started failing, or when a scrape is blocked but you're not sure whether the proxy IPs or the website is responsible. If you haven't run the automated check yet, start with [Troubleshoot URL Access](/docs/residential-proxy/getting-started/troubleshoot-url-access) first, it's faster.
## Why direct URL access fails
Many websites treat a request for a deep page (a product page, a listing, a search result) with no prior history as a strong bot signal. A real visitor almost never lands there cold. They arrive from a search engine, from the homepage, or from a category page, carrying cookies, a referrer, and a browsing history that the site has already seen.
That's why a scraper hitting a product URL directly can be blocked while the exact same IP loads the site normally in a browser. The test below reproduces the natural path so you can compare the two.
## What you need
* Your Residential Proxy credentials from the [Proxy Setup tab](https://app.mrscraper.com/proxies?tab=Proxy+Setup). See the [Authentication guide](/docs/residential-proxy/configuration/authentication) for the username format.
* Google Chrome with the [FoxyProxy](https://chromewebstore.google.com/detail/foxyproxy/gcknhkkoolaabfmlnjonogaaifnjlfnp) extension installed.
* Optional: [CloakBrowser](/docs/residential-proxy/examples/cloakbrowser), an open source stealth browser, for the second round of testing.
## Run the test
### Route Chrome through the proxy
Open FoxyProxy, add a new proxy, and fill in the connection details:
| Field | Value |
| ----------------- | -------------------------------------------------- |
| **Proxy type** | HTTP |
| **Hostname / IP** | `proxy.mrscraper.com` |
| **Port** | `10000` |
| **Username** | Your proxy username, for example `user-country-us` |
| **Password** | Your proxy password |
Set the country in the username to match the target website's audience. For a Brazilian website, use `-country-br`.
Save the proxy, then enable it from the FoxyProxy toolbar icon. Confirm the traffic is actually routed by opening [api.ipify.org](https://api.ipify.org) and checking that the IP is not your own.
### Search for the website on Google
Go to [google.com](https://www.google.com) and search for the target website's name or homepage, for example `ifood.com.br`.
Don't paste the target page URL into the address bar. The point of this test is to arrive at the site the way a visitor does.
### Click through from the search results
Click the organic search result that leads to the website's homepage. This gives the session a search engine referrer and lets the site set its cookies on a page it expects first-time visitors to land on.
### Navigate to the target page like a human
From the homepage, reach the page you want to scrape using the site's own navigation: menus, category links, the on-site search box, pagination. Take a moment between clicks instead of firing them back to back.
If you reach the page and it loads normally, the website is serving your proxy IP without complaint.
### If regular Chrome is blocked, retry with CloakBrowser
Regular Chrome still exposes automation and environment signals that stricter sites fingerprint. [CloakBrowser](/docs/residential-proxy/examples/cloakbrowser) is an open source stealth browser built on a patched Chromium that hides far more of them.
Launch it in headed mode with the same proxy credentials, then repeat steps 2 to 4 inside it:
```javascript
import { launch } from 'cloakbrowser';
const browser = await launch({
headless: false,
proxy: {
server: 'http://proxy.mrscraper.com:10000',
username: 'user-country-br',
password: 'pass123'
}
});
const page = await browser.newPage();
await page.goto('https://www.google.com');
// Now search for the site and click through by hand.
```
## Interpret the results
| Manual browser test | What it means | Next action |
| ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| ✅ Works in regular Chrome | The proxy IPs are fine. Your scraper is being detected by its request signature or by navigating directly to the target URL. | Reproduce the natural flow in your scraper: start from the homepage or a search result, keep cookies across requests, and enable browser rendering. |
| ❌ Blocked in Chrome, ✅ works in CloakBrowser | The IPs are fine. The website is fingerprinting the browser, not the IP. | Move your scraping to a stealth browser. See the [CloakBrowser examples](/docs/residential-proxy/examples/cloakbrowser). |
| ❌ Blocked in both, even with natural navigation | The website is rejecting the IP itself, or the whole country or ASN. | Try a different [proxy country](/docs/residential-proxy/configuration/country-codes) and repeat the test. If it still fails, contact support. |
| ❌ Blocked in both, and the site is also blocked without the proxy | The website is blocking your region or is down for everyone. | Verify from a different network before investigating the proxy further. |
A website that recently changed its protection can block a perfectly healthy residential IP simply because the request didn't look like a human session. Running this test before escalating saves you from swapping proxies that were never the problem.
# CloakBrowser
Cloakbrowser is an opensource stealth browser developed by CloakHQ that will increase the success rate of the web scraping process, although there still many factors affecting the success rate.
CloakBrowser code examples divided by programming language (JavaScript and Python) for stealth browser automation with Residential Proxy.
## JavaScript (Node.js)
### Prerequisites
```bash
npm install cloakbrowser proxy-chain
npx cloakbrowser install
```
* `cloakbrowser`: Node.js stealth browser library featuring custom Chromium fingerprint evasion and Playwright-like APIs.
### Proxy Format
In JavaScript, CloakBrowser accepts a `proxy` object during `launch()`:
```javascript
const proxy = {
server: 'http://proxy.mrscraper.com:10000',
username: 'user-country-us-sessid-session1',
password: 'pass123',
}
```
### SOCKS5 Proxy Setup
For SOCKS5 proxies, use `proxy-chain` to anonymize the authenticated SOCKS5 connection before passing the local proxy server to CloakBrowser:
```javascript
import { launch } from 'cloakbrowser'
import { anonymizeProxy, closeAnonymizedProxy } from 'proxy-chain'
const username = 'user-country-us'
const password = 'pass123'
const socks5Proxy =
`socks5://${encodeURIComponent(username)}:${encodeURIComponent(password)}` +
`@proxy.mrscraper.com:10001`
const localProxy = await anonymizeProxy(socks5Proxy)
const browser = await launch({
proxy: {
server: localProxy,
},
})
try {
const page = await browser.newPage()
await page.goto('https://ipinfo.io/json')
console.log(await page.textContent('body'))
} finally {
await browser.close()
await closeAnonymizedProxy(localProxy, true)
}
```
Use port `10001` for SOCKS5. Always close the browser before calling `closeAnonymizedProxy()`.
### 1. Basic Stealth Request
Demonstrates launching CloakBrowser with an authenticated residential proxy in JavaScript. It navigates to an IP lookup endpoint and prints the verified proxy IP.
```javascript
import { launch } from 'cloakbrowser'
async function testStealthProxy() {
// Launch stealth browser with proxy options
const browser = await launch({
headless: true,
proxy: {
server: 'http://proxy.mrscraper.com:10000',
username: 'user-country-us',
password: 'pass123',
},
})
const page = await browser.newPage()
await page.goto('https://api.ipify.org?format=json')
const content = await page.textContent('body')
console.log('Your Stealth Proxy IP:', content)
await browser.close()
}
testStealthProxy().catch(console.error)
```
**Use Case:** Baseline proxy connectivity check and stealth browser launch in Node.js.
### 2. Sticky Session Navigation
Maintains a static IP address across sequential page navigations by reusing a session ID (`sessid`) and extending session time (`sesstime-30`).
```javascript
import { launch } from 'cloakbrowser'
async function runStickyStealthSession() {
const browser = await launch({
headless: true,
proxy: {
server: 'http://proxy.mrscraper.com:10000',
// 30-minute Canadian static session
username: 'user-country-ca-sessid-stealth1-sesstime-30',
password: 'pass123',
},
})
const page = await browser.newPage()
const targetUrls = [
'https://example.com/step1',
'https://example.com/step2',
'https://example.com/step3',
]
for (const url of targetUrls) {
await page.goto(url)
console.log(`Visited ${url} -> Title:`, await page.title())
}
await browser.close()
}
runStickyStealthSession().catch(console.error)
```
**Use Case:** Executing sensitive multi-page JavaScript workflows (logins, checkouts) while bypassing bot detection and retaining IP consistency.
### 3. Parallel Stealth Workers
Demonstrates spawning multiple concurrent JavaScript CloakBrowser instances, each configured with a unique sticky session ID for isolated parallel operations.
```javascript
import { launch } from 'cloakbrowser'
async function runParallelWorkers() {
const workerIds = ['worker_1', 'worker_2', 'worker_3']
const workerPromises = workerIds.map(async (workerId) => {
const browser = await launch({
headless: true,
proxy: {
server: 'http://proxy.mrscraper.com:10000',
username: `user-country-us-sessid-${workerId}`,
password: 'pass123',
},
})
const page = await browser.newPage()
await page.goto('https://api.ipify.org?format=json')
const ipData = await page.textContent('body')
console.log(`Stealth Worker [${workerId}] IP:`, ipData)
await browser.close()
})
await Promise.all(workerPromises)
}
runParallelWorkers().catch(console.error)
```
**Use Case:** High-concurrency Node.js web scraping where each worker thread requires dedicated stealth fingerprinting and IP isolation.
### 4. Production Error Handling
Production-ready error handling pattern for JavaScript CloakBrowser, providing navigation timeout configurations, response status validation, and safe browser closing routines.
```javascript
import { launch } from 'cloakbrowser'
async function safeStealthScrape(targetUrl) {
let browser = null
try {
browser = await launch({
headless: true,
proxy: {
server: 'http://proxy.mrscraper.com:10000',
username: 'user-country-us-sessid-prod1',
password: 'pass123',
},
})
const page = await browser.newPage()
// Set 30s timeout
const response = await page.goto(targetUrl, { timeout: 30000 })
if (!response || !response.ok()) {
throw new Error(`HTTP Error ${response?.status()}`)
}
console.log('Successfully loaded page title:', await page.title())
} catch (error) {
console.error(`CloakBrowser execution failed:`, error.message)
} finally {
if (browser) {
await browser.close()
}
}
}
safeStealthScrape('https://example.com')
```
**Use Case:** Deploying enterprise Node.js stealth scrapers that handle timeouts and site exceptions safely.
***
## Python
### Prerequisites
```bash
pip install cloakbrowser
python -m cloakbrowser install
```
* `cloakbrowser`: Python package for stealth browser automation and anti-bot evasions.
* Install `sing-box` separately and make sure the `sing-box` command is available on your `PATH` for SOCKS5 proxy bridging.
### Proxy Format
In Python, CloakBrowser receives a dictionary with proxy parameters:
```python
proxy = {
"server": "http://proxy.mrscraper.com:10000",
"username": "user-country-us-sessid-session1",
"password": "pass123"
}
```
### SOCKS5 Proxy Setup
CloakBrowser's Python integration uses `sing-box` to expose the authenticated SOCKS5 proxy as a local HTTP proxy:
```python
import json
import os
import subprocess
import tempfile
import time
from cloakbrowser import launch
username = "user-country-us"
password = "pass123"
local_proxy = "http://127.0.0.1:8080"
singbox_config = {
"inbounds": [
{
"type": "http",
"tag": "http-in",
"listen": "127.0.0.1",
"listen_port": 8080,
}
],
"outbounds": [
{
"type": "socks",
"tag": "mrscraper",
"server": "proxy.mrscraper.com",
"server_port": 10001,
"username": username,
"password": password,
"version": "5",
}
],
"route": {
"final": "mrscraper"
},
}
with tempfile.NamedTemporaryFile(
mode="w",
suffix=".json",
delete=False,
) as config_file:
json.dump(singbox_config, config_file)
config_path = config_file.name
singbox_process = subprocess.Popen([
"sing-box",
"run",
"-c",
config_path,
])
try:
time.sleep(1)
browser = launch(
headless=True,
proxy={
"server": local_proxy,
},
)
try:
page = browser.new_page()
page.goto("https://ipinfo.io/json")
print(page.text_content("body"))
finally:
browser.close()
finally:
singbox_process.terminate()
singbox_process.wait()
os.remove(config_path)
```
Use port `10001` for SOCKS5 and always terminate `sing-box` after closing the browser.
### 1. Basic Stealth Request
Demonstrates launching CloakBrowser using its Python API to route automated browser requests through a residential proxy.
```python
from cloakbrowser import launch
def test_stealth_proxy():
# Launch browser with proxy server and credentials
browser = launch(
headless=True,
proxy={
"server": "http://proxy.mrscraper.com:10000",
"username": "user-country-us",
"password": "pass123"
}
)
page = browser.new_page()
page.goto("https://api.ipify.org?format=json")
print("Your Stealth Proxy IP:", page.text_content("body"))
browser.close()
if __name__ == "__main__":
test_stealth_proxy()
```
**Use Case:** Quick stealth proxy verification script in Python for anti-bot testing and scraping.
### 2. Sticky Session Navigation
Maintains a static Python stealth browser session across multiple page navigations using a session ID (`sessid`).
```python
from cloakbrowser import launch
def run_sticky_session():
browser = launch(
headless=True,
proxy={
"server": "http://proxy.mrscraper.com:10000",
"username": "user-country-us-sessid-python1-sesstime-20",
"password": "pass123"
}
)
page = browser.new_page()
urls = [
"https://example.com/step1",
"https://example.com/step2",
"https://example.com/step3"
]
for url in urls:
page.goto(url)
print(f"Scraped {url} -> Title: {page.title()}")
browser.close()
if __name__ == "__main__":
run_sticky_session()
```
**Use Case:** Python multi-step form completion and account crawling requiring anti-bot protection and session IP continuity.
### 3. Geotargeting & Stealth Fingerprinting
Demonstrates routing Python CloakBrowser traffic through a German residential proxy while leveraging stealth browser features.
```python
from cloakbrowser import launch
def geotargeted_stealth():
browser = launch(
headless=True,
proxy={
"server": "http://proxy.mrscraper.com:10000",
"username": "user-country-de-sessid-shop1",
"password": "pass123"
}
)
page = browser.new_page()
page.goto("https://httpbin.org/headers")
print("Stealth Browser Headers:\n", page.text_content("body"))
browser.close()
if __name__ == "__main__":
geotargeted_stealth()
```
**Use Case:** Accessing heavily protected international websites that combine WAF anti-bot protections with geo-restrictions.
### 4. Production Error Handling & Lifecycle Management
Provides robust Python error handling, custom navigation timeout configuration, response validation, and guaranteed teardown.
```python
from cloakbrowser import launch
def safe_stealth_scrape(target_url):
browser = None
try:
browser = launch(
headless=True,
proxy={
"server": "http://proxy.mrscraper.com:10000",
"username": "user-country-us-sessid-prod1",
"password": "pass123"
}
)
page = browser.new_page()
page.set_default_timeout(30000)
page.goto(target_url)
print("Successfully loaded page title:", page.title())
except Exception as error:
print(f"CloakBrowser Python execution failed: {error}")
finally:
if browser:
browser.close()
if __name__ == "__main__":
safe_stealth_scrape("https://example.com")
```
**Use Case:** Production Python automation scripts requiring clean error logging and reliable browser process cleanup.
* CloakBrowser follows standard Playwright page and navigation APIs in both JavaScript and Python.
* Run `npx cloakbrowser install` or `python -m cloakbrowser install` prior to execution to download stealth binaries.
* Keep sensitive proxy credentials in environment variables (`process.env.PROXY_PASSWORD` or `os.environ.get("PROXY_PASSWORD")`).
# cURL
Command-line examples for testing Residential Proxy configurations quickly.
## SOCKS5 Proxy Setup
Every example on this page uses the HTTP endpoint on port `10000`. SOCKS5 is supported too, on port `10001` — add the scheme to `-x`:
```bash
# SOCKS5 with DNS resolved by the proxy
curl -x "socks5h://user-country-us:pass123@proxy.mrscraper.com:10001" https://api.ipify.org
# Equivalent using the dedicated flag
curl --socks5-hostname proxy.mrscraper.com:10001 \
--proxy-user "user-country-us:pass123" \
https://api.ipify.org
```
Use port `10001` for SOCKS5. Prefer `socks5h://` (or `--socks5-hostname`) so hostnames are resolved by the proxy instead of locally. Username parameters such as `-country-` and `-sessid-` behave identically on both protocols.
## 1. Basic Request
The simplest way to test Residential Proxy connectivity. This command routes your request through a US proxy and returns the proxy's IP address.
```bash
# Test proxy connection
curl -x "user-country-us:pass123@proxy.mrscraper.com:10000" https://api.ipify.org
```
**Use Case:** Quick connectivity testing and verifying your proxy credentials are working correctly.
## 2. Static Session Request
Demonstrates session-based proxying where the same session ID (`sessid-test1`) maintains the same IP address across multiple requests.
```bash
# Same IP across multiple requests
curl -x "user-country-us-sessid-test1:pass123@proxy.mrscraper.com:10000" https://example.com
# Verify same IP
curl -x "user-country-us-sessid-test1:pass123@proxy.mrscraper.com:10000" https://api.ipify.org
```
**Use Case:** Testing scenarios where you need to maintain session state, like logging into websites or simulating a single user's browsing session.
## 3. Rotating Proxy Test
This loop demonstrates IP rotation by making multiple requests without a session ID. Each request will come from a different IP address.
```bash
# Test IP rotation - each request gets different IP
for i in {1..5}; do
echo "Request $i:"
curl -x "user-country-gb:pass123@proxy.mrscraper.com:10000" https://api.ipify.org
echo ""
done
```
**Use Case:** Verifying that IP rotation is working correctly and understanding the different IPs available in your proxy pool.
## 4. Custom Headers
Shows how to combine proxy usage with custom HTTP headers to appear more like a real browser from a specific region.
```bash
# Add custom user agent and headers
curl -x "user-country-de:pass123@proxy.mrscraper.com:10000" \
-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)" \
-H "Accept-Language: de-DE" \
https://example.com
```
**Use Case:** Scraping geo-specific content or avoiding detection by matching your headers to your proxy's location.
## 5. Save Response
Captures the complete HTTP response body and saves it to a local file for later analysis or processing.
```bash
# Save scraped content to file
curl -x "user-country-jp-sessid-save1:pass123@proxy.mrscraper.com:10000" \
-o output.html \
https://example.com
```
**Use Case:** Batch downloading of pages, creating local copies of websites, or saving responses for offline analysis.
## 6. Verbose Output
Enables detailed logging to troubleshoot connection issues, see SSL handshakes, and understand the complete request/response flow.
```bash
# Debug proxy connection with verbose output
curl -v -x "user-country-fr:pass123@proxy.mrscraper.com:10000" \
https://api.ipify.org
```
**Use Case:** Debugging proxy connection problems, understanding SSL certificate issues, or verifying that requests are properly routed through the proxy.
## 7. POST Request
Demonstrates sending POST requests with JSON data through a proxy, useful for API interactions and form submissions.
```bash
# POST request through proxy
curl -x "user-country-ca-sessid-post1:pass123@proxy.mrscraper.com:10000" \
-X POST \
-H "Content-Type: application/json" \
-d '{"key":"value"}' \
https://api.example.com/endpoint
```
**Use Case:** Testing APIs through proxies, submitting forms, or sending data to web services while maintaining anonymity or bypassing geo-restrictions.
## 8. Custom Session Duration
Controls how long your proxy session remains active using the `sesstime` parameter, extending beyond the default 10-minute session time.
```bash
# 30-minute session
curl -x "user-country-au-sessid-long1-sesstime-30:pass123@proxy.mrscraper.com:10000" \
https://example.com
```
**Use Case:** Long-running scripts that need to maintain the same IP for extended periods, such as multi-step authentication flows or comprehensive site crawling.
## 9. Multiple Requests Script
A practical bash script that demonstrates bulk scraping with status monitoring and rate limiting. Each URL gets a different IP due to proxy rotation.
```bash
#!/bin/bash
# Script to scrape multiple URLs with rotating proxy
PROXY="user-country-us:pass123@proxy.mrscraper.com:10000"
urls=(
"https://example.com/page1"
"https://example.com/page2"
"https://example.com/page3"
"https://example.com/page4"
"https://example.com/page5"
)
for url in "${urls[@]}"; do
echo "Scraping: $url"
curl -x "$PROXY" -s "$url" -o /dev/null -w "Status: %{http_code}\n"
sleep 1 # Delay between requests
done
```
**Use Case:** Batch processing multiple URLs with different IPs, monitoring success rates, and implementing respectful scraping practices with delays.
## 10. Error Handling
Production-ready error handling with timeouts and status code checking. Essential for reliable automated scraping operations.
```bash
# Check connection and handle errors
if curl -x "user-country-nl:pass123@proxy.mrscraper.com:10000" \
--connect-timeout 30 \
--max-time 60 \
-f -s -o /dev/null https://example.com; then
echo "Success"
else
echo "Failed with exit code: $?"
fi
```
**Use Case:** Building robust automation scripts that can detect and handle network failures, timeouts, and HTTP errors gracefully.
## Useful cURL Options
| Option | Description |
| ------------------- | --------------------------------- |
| `-x, --proxy` | Specify proxy server |
| `-H, --header` | Add custom header |
| `-o, --output` | Save output to file |
| `-v, --verbose` | Show detailed connection info |
| `-s, --silent` | Silent mode (no progress bar) |
| `-f, --fail` | Fail silently on HTTP errors |
| `--connect-timeout` | Maximum time for connection |
| `--max-time` | Maximum time for entire operation |
| `-L, --location` | Follow redirects |
| `-A, --user-agent` | Set user agent string |
# Go
Practical Go examples for integrating Residential Proxy into your scraping applications.
## SOCKS5 Proxy Setup
Every example on this page uses the HTTP endpoint on port `10000`. SOCKS5 is supported too, on port `10001`. `net/http` handles it natively — only the scheme and port change:
```go
package main
import (
"fmt"
"io"
"net/http"
"net/url"
)
func main() {
// Same credentials, SOCKS5 scheme and port
proxyURL, _ := url.Parse("socks5://user-country-us:pass123@proxy.mrscraper.com:10001")
client := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(proxyURL),
},
}
resp, err := client.Get("https://api.ipify.org")
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println("Your IP:", string(body))
}
```
Use port `10001` for SOCKS5. `http.Transport` recognises the `socks5` scheme and passes the username and password from the URL as SOCKS authentication. Username parameters such as `-country-` and `-sessid-` behave identically on both protocols.
## 1. Basic HTTP Request
This example demonstrates the fundamental setup for using Residential Proxy with Go's `net/http` package. It configures a static proxy session and makes a simple GET request.
```go
package main
import (
"fmt"
"io"
"net/http"
"net/url"
)
func main() {
// Static proxy
proxyURL, _ := url.Parse("http://user-country-us-sessid-go1:pass123@proxy.mrscraper.com:10000")
client := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(proxyURL),
},
}
resp, err := client.Get("https://api.ipify.org")
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println("Your IP:", string(body))
}
```
**Use Case:** Perfect for simple proxy testing, IP verification, and single-request scenarios where you need a consistent IP address through a static session.
## 2. Rotating Proxy for Scraping
Shows how to create a reusable scraping function that uses rotating proxies (no session ID). Each call gets a fresh IP address, ideal for avoiding rate limits.
```go
package main
import (
"fmt"
"io"
"net/http"
"net/url"
)
func scrapeWithProxy(targetURL string) error {
// Rotating proxy - new IP per request
proxyURL, _ := url.Parse("http://user-country-gb:pass123@proxy.mrscraper.com:10000")
client := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(proxyURL),
},
}
resp, err := client.Get(targetURL)
if err != nil {
return fmt.Errorf("failed to fetch %s: %w", targetURL, err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Printf("Scraped %s: %d bytes (status: %d)\n", targetURL, len(body), resp.StatusCode)
return nil
}
func main() {
urls := []string{
"https://example.com/page1",
"https://example.com/page2",
"https://example.com/page3",
}
for _, url := range urls {
if err := scrapeWithProxy(url); err != nil {
fmt.Println("Error:", err)
}
}
}
```
**Use Case:** High-volume scraping where IP diversity is crucial for avoiding detection and rate limiting. Each page request appears to come from a different visitor.
## 3. Concurrent Scraping
Demonstrates parallel scraping using goroutines with different static proxy sessions. Each goroutine maintains its own consistent IP address for the duration of its work.
```go
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"sync"
)
func scrapeWithProxy(targetURL string, proxyAuth string, wg *sync.WaitGroup) {
defer wg.Done()
proxyURL, _ := url.Parse(fmt.Sprintf("http://%s@proxy.mrscraper.com:10000", proxyAuth))
client := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(proxyURL),
},
}
resp, err := client.Get(targetURL)
if err != nil {
fmt.Printf("Error scraping %s: %v\n", targetURL, err)
return
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Printf("Scraped %s: %d bytes\n", targetURL, len(body))
}
func main() {
urls := []string{
"https://example.com/page1",
"https://example.com/page2",
"https://example.com/page3",
}
var wg sync.WaitGroup
for i, targetURL := range urls {
wg.Add(1)
proxyAuth := fmt.Sprintf("user-country-fr-sessid-worker%d:pass123", i+1)
go scrapeWithProxy(targetURL, proxyAuth, &wg)
}
wg.Wait()
fmt.Println("All scraping completed")
}
```
**Use Case:** High-performance scraping that needs to process multiple URLs quickly while maintaining separate identities. Great for scraping sites with per-IP rate limits.**Use Case:** High-performance scraping that needs to process multiple URLs quickly while maintaining separate identities. Great for scraping sites with per-IP rate limits.
## 4. Error Handling & Retries
Implements robust error handling with exponential backoff retry logic. Essential for production scraping applications that need to handle network failures gracefully.
```go
package main
import (
"fmt"
"io"
"math"
"net/http"
"net/url"
"time"
)
func scrapeWithRetry(targetURL string, maxRetries int) ([]byte, error) {
proxyURL, _ := url.Parse("http://user-country-de:pass123@proxy.mrscraper.com:10000")
client := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(proxyURL),
},
Timeout: 30 * time.Second,
}
var lastErr error
for attempt := 0; attempt < maxRetries; attempt++ {
resp, err := client.Get(targetURL)
if err != nil {
lastErr = err
backoff := time.Duration(math.Pow(2, float64(attempt))) * time.Second
fmt.Printf("Attempt %d failed: %v. Retrying in %v...\n", attempt+1, err, backoff)
time.Sleep(backoff)
continue
}
defer resp.Body.Close()
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
body, _ := io.ReadAll(resp.Body)
return body, nil
}
lastErr = fmt.Errorf("HTTP %d", resp.StatusCode)
backoff := time.Duration(math.Pow(2, float64(attempt))) * time.Second
fmt.Printf("Attempt %d returned %d. Retrying in %v...\n", attempt+1, resp.StatusCode, backoff)
time.Sleep(backoff)
}
return nil, fmt.Errorf("failed after %d attempts: %w", maxRetries, lastErr)
}
func main() {
body, err := scrapeWithRetry("https://example.com", 3)
if err != nil {
fmt.Println("Failed:", err)
} else {
fmt.Printf("Success: %d bytes\n", len(body))
}
}
```
**Use Case:** Production-ready scraping that must handle temporary network issues, server errors, and proxy failures without crashing or losing data.
## 5. Custom Headers
Shows how to add realistic browser headers to your requests when using proxies. This helps avoid detection by making requests appear more legitimate.
```go
package main
import (
"fmt"
"io"
"net/http"
"net/url"
)
func scrapeWithHeaders(targetURL string) error {
proxyURL, _ := url.Parse("http://user-country-jp:pass123@proxy.mrscraper.com:10000")
client := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(proxyURL),
},
}
req, _ := http.NewRequest("GET", targetURL, nil)
// Add custom headers
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)")
req.Header.Set("Accept-Language", "ja-JP,ja;q=0.9")
req.Header.Set("Accept", "text/html,application/xhtml+xml")
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Printf("Scraped %d bytes with status %d\n", len(body), resp.StatusCode)
return nil
}
func main() {
if err := scrapeWithHeaders("https://example.com"); err != nil {
fmt.Println("Error:", err)
}
}
```
**Use Case:** Scraping sites that check for browser-like behavior or when you need to match your headers to your proxy's geographic location for consistency.
## 6. Context with Timeout
Demonstrates using Go's context package for proper timeout handling and request cancellation. This prevents requests from hanging indefinitely.
```go
package main
import (
"context"
"fmt"
"io"
"net/http"
"net/url"
"time"
)
func scrapeWithContext(targetURL string) error {
proxyURL, _ := url.Parse("http://user-country-ca-sessid-ctx1:pass123@proxy.mrscraper.com:10000")
client := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(proxyURL),
},
}
// Create context with 30-second timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, "GET", targetURL, nil)
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Printf("Scraped %d bytes\n", len(body))
return nil
}
func main() {
if err := scrapeWithContext("https://example.com"); err != nil {
fmt.Println("Error:", err)
}
}
```
**Use Case:** Applications that need precise control over request timeouts and graceful cancellation, especially in concurrent scenarios or when dealing with unreliable target sites.
## 7. Rate Limiting
Implements respectful scraping with controlled request rates using Go's time.Ticker. This prevents overwhelming target servers while maintaining steady throughput.
```go
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"time"
)
func scrapeWithRateLimit(urls []string, requestsPerMinute int) {
proxyURL, _ := url.Parse("http://user-country-au:pass123@proxy.mrscraper.com:10000")
client := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(proxyURL),
},
}
delay := time.Minute / time.Duration(requestsPerMinute)
ticker := time.NewTicker(delay)
defer ticker.Stop()
for _, targetURL := range urls {
<-ticker.C // Wait for next tick
resp, err := client.Get(targetURL)
if err != nil {
fmt.Printf("Error scraping %s: %v\n", targetURL, err)
continue
}
body, _ := io.ReadAll(resp.Body)
resp.Body.Close()
fmt.Printf("Scraped %s: %d bytes\n", targetURL, len(body))
}
}
func main() {
urls := []string{
"https://example.com/page1",
"https://example.com/page2",
"https://example.com/page3",
}
scrapeWithRateLimit(urls, 20) // 20 requests per minute
}
```
**Use Case:** Ethical scraping that respects server resources and terms of service. Essential for long-running scraping operations that need to avoid being blocked.
# Node.js
Practical Node.js examples for integrating Residential Proxy into your scraping and automation projects.
## Prerequisites
```bash
npm install axios cheerio puppeteer
```
* `axios`: Promise-based HTTP client for making requests with built-in proxy support and interceptors.
* `cheerio`: Server-side jQuery implementation for parsing and manipulating HTML responses.
* `puppeteer`: Headless Chrome automation library for full browser simulation with proxy support.
## SOCKS5 Proxy Setup
Every example on this page uses the HTTP endpoint on port `10000`. SOCKS5 is supported too, on port `10001`. The axios `proxy` option only speaks HTTP, so SOCKS5 goes through an agent instead:
```bash
npm install socks-proxy-agent
```
```javascript
const axios = require('axios');
const { SocksProxyAgent } = require('socks-proxy-agent');
// Same credentials, SOCKS5 scheme and port
const agent = new SocksProxyAgent(
'socks5://user-country-us-sessid-session1:pass123@proxy.mrscraper.com:10001'
);
const response = await axios.get('https://api.ipify.org', {
httpAgent: agent,
httpsAgent: agent,
proxy: false,
});
console.log('Your IP:', response.data);
```
Use port `10001` for SOCKS5. Keep `proxy: false` so axios does not layer its own HTTP proxy on top of the agent. Username parameters such as `-country-` and `-sessid-` behave identically on both protocols.
## 1. Basic Static Proxy
Demonstrates the simplest proxy setup with axios using a static session. The same IP address is maintained across requests using the session ID parameter.
```javascript
const axios = require('axios');
// Static proxy configuration
const proxy = {
host: 'proxy.mrscraper.com',
port: 10000,
auth: {
username: 'user-country-us-sessid-session1',
password: 'pass123'
}
};
// Make a request
async function testProxy() {
try {
const response = await axios.get('https://api.ipify.org', { proxy });
console.log('Your IP:', response.data);
} catch (error) {
console.error('Error:', error.message);
}
}
testProxy();
```
**Use Case:** Simple proxy testing and scenarios where you need consistent IP addresses for maintaining login sessions or avoiding duplicate detection.
## 2. Rotating Proxy with Axios
Shows how to combine rotating proxies with Cheerio for HTML parsing. Each request gets a fresh IP address, perfect for scraping multiple pages without detection.
```javascript
const axios = require('axios');
const cheerio = require('cheerio');
// Rotating proxy - new IP per request
const rotatingProxy = {
host: 'proxy.mrscraper.com',
port: 10000,
auth: {
username: 'user-country-gb',
password: 'pass123'
}
};
async function scrapePage(url) {
try {
const response = await axios.get(url, {
proxy: rotatingProxy,
timeout: 30000
});
const $ = cheerio.load(response.data);
const title = $('h1').first().text();
console.log(`Scraped: ${title}`);
return response.data;
} catch (error) {
console.error(`Error scraping ${url}:`, error.message);
return null;
}
}
// Scrape multiple pages (each with different IP)
async function scrapeMultiple() {
const urls = [
'https://example.com/page1',
'https://example.com/page2',
'https://example.com/page3'
];
for (const url of urls) {
await scrapePage(url);
}
}
scrapeMultiple();
```
**Use Case:** High-volume web scraping where IP rotation helps avoid rate limits and detection. Ideal for scraping e-commerce sites, job boards, or news sites.
## 3. Multiple Sessions (Promise.all)
Demonstrates parallel scraping using Promise.all with different static proxy sessions. Each concurrent request maintains its own consistent IP address.
```javascript
const axios = require('axios');
// Create array of proxy configs with different sessions
const proxies = Array.from({ length: 5 }, (_, i) => ({
host: 'proxy.mrscraper.com',
port: 10000,
auth: {
username: `user-country-de-sessid-worker${i + 1}`,
password: 'pass123'
}
}));
async function scrapeWithProxy(proxy, url) {
try {
const response = await axios.get(url, { proxy, timeout: 30000 });
return {
status: response.status,
length: response.data.length,
url
};
} catch (error) {
return { error: error.message, url };
}
}
async function parallelScraping() {
const urls = Array.from({ length: 10 }, (_, i) =>
`https://example.com/page${i + 1}`
);
// Scrape in parallel using different sessions
const promises = urls.map((url, index) => {
const proxy = proxies[index % proxies.length];
return scrapeWithProxy(proxy, url);
});
const results = await Promise.all(promises);
console.log('Results:', results);
}
parallelScraping();
```
**Use Case:** High-performance scraping that needs maximum throughput while maintaining multiple distinct identities. Great for scraping large datasets quickly.
## 4. Puppeteer with Proxy
Shows how to use Residential Proxy with Puppeteer for full browser automation. This enables JavaScript rendering, screenshot capture, and interaction with dynamic content.
```javascript
const puppeteer = require('puppeteer');
async function scrapeWithPuppeteer() {
// Proxy URL format for Puppeteer
const proxyUrl = 'http://user-country-jp-sessid-pup1:pass123@proxy.mrscraper.com:10000';
const browser = await puppeteer.launch({
headless: true,
args: [
`--proxy-server=${proxyUrl}`,
'--no-sandbox',
'--disable-setuid-sandbox'
]
});
try {
const page = await browser.newPage();
// Navigate to page
await page.goto('https://example.com', { waitUntil: 'networkidle2' });
// Extract data
const title = await page.title();
console.log('Page title:', title);
// Take screenshot
await page.screenshot({ path: 'screenshot.png' });
} finally {
await browser.close();
}
}
scrapeWithPuppeteer();
```
**Use Case:** Scraping Single Page Applications (SPAs), taking screenshots for monitoring, or automating complex user interactions through a proxy.
## 5. Error Handling & Retries
Implements robust error handling with exponential backoff retry logic. Essential for production applications that need to handle network failures gracefully.
```javascript
const axios = require('axios');
const proxy = {
host: 'proxy.mrscraper.com',
port: 10000,
auth: {
username: 'user-country-fr',
password: 'pass123'
}
};
async function scrapeWithRetry(url, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await axios.get(url, {
proxy,
timeout: 30000
});
return response.data;
} catch (error) {
console.log(`Attempt ${attempt + 1} failed: ${error.message}`);
if (attempt < maxRetries - 1) {
const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
console.log(`Failed after ${maxRetries} attempts`);
return null;
}
// Use with retry logic
scrapeWithRetry('https://example.com')
.then(data => console.log('Success:', data ? 'Got data' : 'Failed'));
```
**Use Case:** Production-ready scraping that must handle temporary network issues, server errors, and proxy failures without losing data or crashing.
## 6. Environment Variables
Demonstrates secure credential management using environment variables. This keeps sensitive proxy credentials out of your source code.
```javascript
const axios = require('axios');
require('dotenv').config();
// Use environment variables for credentials
const proxy = {
host: 'proxy.mrscraper.com',
port: 10000,
auth: {
username: process.env.MRPROXY_USERNAME,
password: process.env.MRPROXY_PASSWORD
}
};
async function secureScrape(url) {
try {
const response = await axios.get(url, { proxy });
return response.data;
} catch (error) {
console.error('Error:', error.message);
return null;
}
}
// .env file:
// MRPROXY_USERNAME=user-country-us-sessid-session1
// MRPROXY_PASSWORD=pass123
```
**Use Case:** Production deployments where credentials need to be kept secure and separate from code. Essential for CI/CD pipelines and team development.
# Overview
import { Code2, Terminal, FileCode, Theater, Bot, Zap, FlaskConical, ShieldCheck, Globe, LineChart, Bug } from 'lucide-react';
Ready-to-use code examples for integrating Residential Proxy into your applications. Choose your programming language to get started.
## Quick Reference
### Example Proxy Configurations
Default (US)
US Static
GB Rotating
Custom Session
SOCKS5
```bash
# No country specified, falls back to US, rotating IP
user:password@proxy.mrscraper.com:10000
```
```bash
# US proxy with 10-minute session
user-country-us-sessid-a1:password@proxy.mrscraper.com:10000
```
```bash
# GB rotating proxy
user-country-gb:password@proxy.mrscraper.com:10000
```
```bash
# 30-minute session in Japan
user-country-jp-sessid-x9-sesstime-30:password@proxy.mrscraper.com:10000
```
```bash
# Same username format, SOCKS5 scheme and port
socks5://user-country-us:password@proxy.mrscraper.com:10001
```
The snippets on this page and in most language guides use the HTTP endpoint on port `10000` because it needs no extra dependencies. SOCKS5 is fully supported on port `10001` with the `socks5://` prefix, and every username parameter works the same on both. Each language page has a **SOCKS5 Proxy Setup** section with the client-specific setup, and [Proxy Types](/docs/residential-proxy/configuration/proxy-types) compares the two protocols.
## Examples by Language & Framework
} href="/docs/residential-proxy/examples/python">
Examples with requests, BeautifulSoup, and asyncio
} href="/docs/residential-proxy/examples/nodejs">
Examples with axios, Puppeteer, and native http
} href="/docs/residential-proxy/examples/curl">
Command-line examples for quick testing
} href="/docs/residential-proxy/examples/php">
Examples with cURL and Guzzle
} href="/docs/residential-proxy/examples/ruby">
Examples with Net::HTTP and HTTParty
} href="/docs/residential-proxy/examples/go">
Examples with net/http package
} href="/docs/residential-proxy/examples/playwright">
Browser automation in JavaScript & Python
} href="/docs/residential-proxy/examples/puppeteer">
Headless Chrome automation with page authentication
} href="/docs/residential-proxy/examples/selenium">
Browser testing and scraping with selenium-wire
} href="/docs/residential-proxy/examples/cloakbrowser">
Stealth browser automation in JS & Python
## Best Practices
### 1. Error Handling
Always implement proper error handling and retry logic:
* Catch connection timeouts
* Handle proxy authentication failures
* Retry failed requests with exponential backoff
### 2. Session Management
* Use unique session IDs for parallel operations
* Set appropriate session durations (10-60 minutes)
* Reuse sessions for related requests
### 3. Rate Limiting
* Respect target website's rate limits
* Use rotating proxies for high-volume scraping
* Add delays between requests when appropriate
### 4. Security
* Never hardcode credentials in source code
* Use environment variables for sensitive data
* Rotate credentials regularly
## Common Use Cases
}>
Use rotating proxies with country targeting to scrape large amounts of data while avoiding rate limits and IP bans.
}>
Use static proxies with custom session duration to maintain consistent IPs for login flows and account operations.
}>
Use static or rotating proxies with country targeting to view localized content and pricing across different regions.
}>
Use static proxies with various country codes to test your application's behavior across different IP addresses and geographic locations.
# PHP
Practical PHP examples for integrating Residential Proxy into your web scraping projects.
## SOCKS5 Proxy Setup
Every example on this page uses the HTTP endpoint on port `10000`. SOCKS5 is supported too, on port `10001` — set the proxy type explicitly with cURL, or use the `socks5h://` scheme with Guzzle:
```php
get('https://api.ipify.org', [
'proxy' => 'socks5h://user-country-us:pass123@proxy.mrscraper.com:10001',
]);
?>
```
Use port `10001` for SOCKS5. `CURLPROXY_SOCKS5_HOSTNAME` and `socks5h://` resolve hostnames through the proxy; `CURLPROXY_SOCKS5` and `socks5://` resolve them locally. Username parameters such as `-country-` and `-sessid-` behave identically on both protocols.
## 1. Basic cURL Request
Demonstrates the fundamental cURL setup for using Residential Proxy with a static session. This example shows essential cURL options for proxy configuration and basic error handling.
```php
```
**Use Case:** Simple proxy testing and basic scraping tasks where you need a consistent IP address. Perfect for beginners learning PHP proxy integration.
## 2. Rotating Proxy for Scraping
Shows how to create a reusable scraping function with rotating proxies. Each request gets a fresh IP address, and the function returns structured data for easy processing.
```php
$httpCode,
'html' => $html
];
}
// Scrape multiple pages
$urls = [
'https://example.com/page1',
'https://example.com/page2',
'https://example.com/page3'
];
foreach ($urls as $url) {
$result = scrapeWithProxy($url);
echo "Scraped {$url}: Status {$result['status']}\n";
}
?>
```
**Use Case:** High-volume scraping where IP diversity helps avoid detection and rate limiting. Ideal for scraping product catalogs, news sites, or job boards.
## 3. Multiple Sessions
Implements an object-oriented approach with multiple static proxy sessions. The ProxyScraper class encapsulates proxy configuration and provides clean session management.
```php
username = $username;
$this->password = $password;
}
public function scrape($url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_PROXY, $this->proxy);
curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$this->username}:{$this->password}");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$response = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
return [
'status' => $info['http_code'],
'content' => $response
];
}
}
// Create multiple scrapers with different sessions
$scrapers = [];
for ($i = 1; $i <= 3; $i++) {
$scrapers[] = new ProxyScraper("user-country-gb-sessid-worker{$i}", 'pass123');
}
// Use different sessions
$urls = ['https://example.com/page1', 'https://example.com/page2', 'https://example.com/page3'];
foreach ($urls as $index => $url) {
$scraper = $scrapers[$index % count($scrapers)];
$result = $scraper->scrape($url);
echo "Scraped {$url}: {$result['status']}\n";
}
?>
```
**Use Case:** Organized scraping operations that need multiple consistent identities. Great for maintaining separate sessions for different data sources or user profiles.
## 4. Error Handling & Retries
Implements robust retry logic with exponential backoff to handle network failures gracefully. This pattern is essential for production scraping applications.
```php
= 200 && $httpCode < 300) {
return $response;
}
echo "Attempt {$attempt} returned HTTP {$httpCode}\n";
sleep(pow(2, $attempt - 1));
}
return false;
}
$result = scrapeWithRetry('https://example.com');
if ($result) {
echo "Success!\n";
} else {
echo "Failed after retries\n";
}
?>
```
**Use Case:** Production-ready scraping that must handle temporary network issues, server errors, and proxy failures without losing data or crashing the application.
## 5. Guzzle HTTP Client
Demonstrates using the popular Guzzle library for more elegant HTTP requests. Guzzle provides better error handling and a more intuitive API compared to raw cURL.
```php
'http://user-country-jp-sessid-guzzle1:pass123@proxy.mrscraper.com:10000',
'timeout' => 30
]);
try {
$response = $client->get('https://api.ipify.org');
echo 'Your IP: ' . $response->getBody();
} catch (RequestException $e) {
echo 'Error: ' . $e->getMessage();
}
?>
```
**Use Case:** Modern PHP applications that prefer object-oriented HTTP clients with better exception handling and cleaner syntax than raw cURL.
## 6. Async Requests with Guzzle
Shows how to make concurrent HTTP requests using Guzzle's promise-based async functionality. This dramatically improves performance for bulk scraping operations.
```php
'http://user-country-au:pass123@proxy.mrscraper.com:10000',
'timeout' => 30
]);
// Create array of promises
$promises = [
'page1' => $client->getAsync('https://example.com/page1'),
'page2' => $client->getAsync('https://example.com/page2'),
'page3' => $client->getAsync('https://example.com/page3'),
];
// Wait for all requests to complete
$results = Promise\Utils::settle($promises)->wait();
// Process results
foreach ($results as $key => $result) {
if ($result['state'] === 'fulfilled') {
echo "{$key}: Success\n";
} else {
echo "{$key}: Failed - {$result['reason']}\n";
}
}
?>
```
**Use Case:** High-performance scraping that needs maximum throughput. Perfect for bulk data collection where you need to process many URLs simultaneously.
## 7. Environment Variables
Demonstrates secure credential management by loading proxy credentials from environment variables instead of hardcoding them in your source code.
```php
```
**Use Case:** Production deployments where credentials must be kept secure and separate from code. Essential for team development and CI/CD pipelines.
# Playwright
Practical Playwright examples for integrating Residential Proxy into browser automation and web scraping projects, separated into JavaScript (Node.js) and Python sections.
## JavaScript (Node.js)
### Prerequisites
```bash
npm install playwright proxy-chain
npx playwright install chromium
```
* `playwright`: Node.js library for browser automation supporting Chromium, Firefox, and WebKit with native proxy authentication.
### Proxy Format
Playwright accepts proxy settings via the `proxy` launch option in JavaScript:
```javascript
const proxy = {
server: 'http://proxy.mrscraper.com:10000',
username: 'user-country-us-sessid-session1',
password: 'pass123',
}
```
### SOCKS5 Proxy Setup
For SOCKS5 proxies, use `proxy-chain` to anonymize the authenticated SOCKS5 connection before passing the local proxy server to Playwright:
```javascript
import { chromium } from 'playwright'
import { anonymizeProxy, closeAnonymizedProxy } from 'proxy-chain'
const username = 'user-country-us'
const password = 'pass123'
const socks5Proxy =
`socks5://${encodeURIComponent(username)}:${encodeURIComponent(password)}` +
`@proxy.mrscraper.com:10001`
const localProxy = await anonymizeProxy(socks5Proxy)
const browser = await chromium.launch({
proxy: {
server: localProxy,
},
})
try {
const page = await browser.newPage()
await page.goto('https://ipinfo.io/json')
console.log(await page.textContent('body'))
} finally {
await browser.close()
await closeAnonymizedProxy(localProxy, true)
}
```
Use port `10001` for SOCKS5. Do not pass SOCKS5 credentials directly to Playwright; `proxy-chain` handles the authenticated upstream connection.
### 1. Basic Proxy Setup
Demonstrates launching Headless Chromium with authenticated proxy credentials in JavaScript, inspecting the resulting external proxy IP.
```javascript
import { chromium } from 'playwright'
async function testProxy() {
// Launch browser with proxy settings
const browser = await chromium.launch({
headless: true,
proxy: {
server: 'http://proxy.mrscraper.com:10000',
username: 'user-country-us',
password: 'pass123',
},
})
const page = await browser.newPage()
// Navigate to IP inspection endpoint
await page.goto('https://api.ipify.org?format=json')
const content = await page.textContent('body')
console.log('Your Proxy IP:', content)
await browser.close()
}
testProxy().catch(console.error)
```
**Use Case:** Fundamental proxy connectivity check and baseline browser launch in Node.js.
### 2. Multi-Context Sticky Sessions
Shows how to create isolated browser contexts on a single browser instance. Each context maintains its own consistent IP address using unique session IDs (`sessid`).
```javascript
import { chromium } from 'playwright'
async function runParallelSessions() {
const browser = await chromium.launch({ headless: true })
const workerSessions = ['worker1', 'worker2', 'worker3']
// Create isolated context per session
for (const session of workerSessions) {
const context = await browser.newContext({
proxy: {
server: 'http://proxy.mrscraper.com:10000',
username: `user-country-us-sessid-${session}`,
password: 'pass123',
},
})
const page = await context.newPage()
await page.goto('https://api.ipify.org?format=json')
const ipData = await page.textContent('body')
console.log(`Session [${session}]:`, ipData)
await context.close()
}
await browser.close()
}
runParallelSessions().catch(console.error)
```
**Use Case:** Parallel web scraping where multiple workers maintain independent sticky sessions on a single browser process.
### 3. Geotargeting & Custom Session Duration
Demonstrates routing Playwright traffic through a German proxy with a 30-minute static session duration (`sesstime-30`), configuring regional locale settings.
```javascript
import { chromium } from 'playwright'
async function geotargetedSession() {
const browser = await chromium.launch({
headless: true,
proxy: {
server: 'http://proxy.mrscraper.com:10000',
// German IP with 30-minute static duration
username: 'user-country-de-sessid-shop1-sesstime-30',
password: 'pass123',
},
})
const context = await browser.newContext({
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
locale: 'de-DE',
})
const page = await context.newPage()
await page.goto('https://httpbin.org/headers')
console.log(await page.textContent('body'))
await browser.close()
}
geotargetedSession().catch(console.error)
```
**Use Case:** Testing localized e-commerce pricing, geo-restricted page content, and multi-step checkouts requiring static IPs.
### 4. Production Error Handling
Production-ready error handling pattern for JavaScript Playwright operations, featuring timeout settings, response checks, and guaranteed resource cleanup.
```javascript
import { chromium } from 'playwright'
async function robustScraping(targetUrl) {
let browser = null
try {
browser = await chromium.launch({
headless: true,
proxy: {
server: 'http://proxy.mrscraper.com:10000',
username: 'user-country-us-sessid-task1',
password: 'pass123',
},
})
const page = await browser.newPage()
page.setDefaultTimeout(30000) // 30s timeout
const response = await page.goto(targetUrl, { waitUntil: 'networkidle' })
if (!response || !response.ok()) {
throw new Error(`Failed to load page: ${response?.status()}`)
}
console.log('Page loaded successfully:', await page.title())
} catch (error) {
console.error(`Scraping failed for ${targetUrl}:`, error.message)
} finally {
if (browser) {
await browser.close()
}
}
}
robustScraping('https://example.com')
```
**Use Case:** Deploying enterprise JavaScript Playwright scrapers that handle timeouts and failures gracefully.
***
## Python
### Prerequisites
```bash
pip install playwright
playwright install chromium
```
* `playwright`: Python package offering synchronous and asynchronous browser automation bindings.
* Install `sing-box` separately and make sure the `sing-box` command is available on your `PATH` for SOCKS5 proxy bridging.
### Proxy Format
Playwright for Python passes proxy options via a dictionary to `chromium.launch()`:
```python
proxy = {
"server": "http://proxy.mrscraper.com:10000",
"username": "user-country-us-sessid-session1",
"password": "pass123"
}
```
### SOCKS5 Proxy Setup
Playwright's Python integration uses `sing-box` to expose the authenticated SOCKS5 proxy as a local HTTP proxy:
```python
import json
import os
import subprocess
import tempfile
import time
from playwright.sync_api import sync_playwright
username = "user-country-us"
password = "pass123"
local_proxy = "http://127.0.0.1:8080"
singbox_config = {
"inbounds": [
{
"type": "http",
"tag": "http-in",
"listen": "127.0.0.1",
"listen_port": 8080,
}
],
"outbounds": [
{
"type": "socks",
"tag": "mrscraper",
"server": "proxy.mrscraper.com",
"server_port": 10001,
"username": username,
"password": password,
"version": "5",
}
],
"route": {
"rules": [
{
"action": "route",
"outbound": "mrscraper",
}
]
},
}
with tempfile.NamedTemporaryFile(
mode="w",
suffix=".json",
delete=False,
) as config_file:
json.dump(singbox_config, config_file)
config_path = config_file.name
print("Starting sing-box...")
singbox_process = subprocess.Popen([
"sing-box",
"run",
"-c",
config_path,
])
try:
time.sleep(1)
with sync_playwright() as playwright:
browser = playwright.chromium.launch(
proxy={
"server": local_proxy,
}
)
try:
page = browser.new_page()
page.goto(
"https://ipinfo.io/json",
wait_until="domcontentloaded",
timeout=30000,
)
print(page.text_content("body"))
finally:
browser.close()
finally:
singbox_process.terminate()
singbox_process.wait()
os.remove(config_path)
```
Use port `10001` for SOCKS5. The browser connects to the local HTTP proxy at `127.0.0.1:8080`; `sing-box` handles the authenticated SOCKS5 upstream.
### 1. Basic Proxy Setup (Sync API)
Demonstrates the Python synchronous Playwright API for initializing an authenticated proxy connection and inspecting page output.
```python
from playwright.sync_api import sync_playwright
def test_proxy():
with sync_playwright() as p:
# Launch browser with proxy server and credentials
browser = p.chromium.launch(
headless=True,
proxy={
"server": "http://proxy.mrscraper.com:10000",
"username": "user-country-us",
"password": "pass123"
}
)
page = browser.new_page()
page.goto("https://api.ipify.org?format=json")
print("Your Proxy IP:", page.text_content("body"))
browser.close()
if __name__ == "__main__":
test_proxy()
```
**Use Case:** Quick proxy integration for Python automation scripts, test suites, and data collection utilities.
### 2. Sticky Session Management (Sync API)
Maintains a static Python Playwright browser session with a stable IP address across multi-step page navigations.
```python
from playwright.sync_api import sync_playwright
def run_sticky_session():
with sync_playwright() as p:
# Static session IP in Canada
browser = p.chromium.launch(
headless=True,
proxy={
"server": "http://proxy.mrscraper.com:10000",
"username": "user-country-ca-sessid-auth1-sesstime-20",
"password": "pass123"
}
)
context = browser.new_context()
page = context.new_page()
for url in ["https://example.com/step1", "https://example.com/step2"]:
page.goto(url)
print(f"Visited {url} -> Title: {page.title()}")
browser.close()
if __name__ == "__main__":
run_sticky_session()
```
**Use Case:** Simulating multi-step user interactions and login sequences in Python requiring a consistent residential IP.
### 3. Rotating Proxy Scraping (Async API)
Uses an asynchronous Python Playwright setup with rotating proxies to visit multiple target URLs, ensuring each request receives a fresh IP address.
```python
import asyncio
from playwright.async_api import async_playwright
async def scrape_target(url, proxy_config):
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True, proxy=proxy_config)
page = await browser.new_page()
try:
await page.goto(url, wait_until="domcontentloaded", timeout=30000)
title = await page.title()
print(f"Scraped '{url}' -> Title: {title}")
except Exception as e:
print(f"Error scraping {url}: {e}")
finally:
await browser.close()
async def main():
# Rotating proxy (no sessid parameter)
proxy_config = {
"server": "http://proxy.mrscraper.com:10000",
"username": "user-country-gb",
"password": "pass123"
}
urls = [
"https://example.com/page1",
"https://example.com/page2",
"https://example.com/page3",
]
for url in urls:
await scrape_target(url, proxy_config)
if __name__ == "__main__":
asyncio.run(main())
```
**Use Case:** High-volume automated Python browser scraping where rotating IPs prevent target site rate limits.
### 4. Production Error Handling & Async Teardown
Implements defensive Python async error trapping, default page timeout limits, and safe browser closing routines.
```python
import asyncio
from playwright.async_api import async_playwright
async def safe_scrape(url):
proxy_config = {
"server": "http://proxy.mrscraper.com:10000",
"username": "user-country-us-sessid-prod1",
"password": "pass123"
}
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True, proxy=proxy_config)
try:
page = await browser.new_page()
page.set_default_timeout(30000)
response = await page.goto(url, wait_until="networkidle")
if not response or not response.ok:
raise RuntimeError(f"HTTP error {response.status if response else 'No response'}")
print(f"Successfully scraped {url} - Length: {len(await page.content())}")
except Exception as err:
print(f"Failed to scrape {url}: {err}")
finally:
await browser.close()
if __name__ == "__main__":
asyncio.run(safe_scrape("https://example.com"))
```
**Use Case:** Enterprise Python async web scrapers operating in production environments with strict reliability requirements.
* Define proxy credentials when calling `chromium.launch()` or `browser.newContext()` / `browser.new_context()`.
* Use browser contexts to handle multiple proxy configurations within a single browser process.
* Keep sensitive proxy credentials in environment variables (`process.env.PROXY_PASSWORD` or `os.environ.get("PROXY_PASSWORD")`).
# Puppeteer
Practical Puppeteer code examples for routing browser automation traffic through Residential Proxies using `page.authenticate()`.
## Prerequisites
```bash
npm install puppeteer proxy-chain
```
* `puppeteer`: Node.js library providing a high-level API to control Headless Chrome or Chromium over the DevTools Protocol.
## Proxy Format
Puppeteer passes the proxy server address via Chromium launch flags (`--proxy-server`), then authenticates using `page.authenticate()`.
```text
username:password@proxy.mrscraper.com:10000
```
For sticky sessions or targeted countries, format the username with parameters:
```text
user-country-us-sessid-session1:password@proxy.mrscraper.com:10000
```
### SOCKS5 Proxy Setup
For SOCKS5 proxies, use `proxy-chain` to anonymize the authenticated SOCKS5 connection before passing the local proxy server to Puppeteer:
```javascript
import puppeteer from 'puppeteer'
import { anonymizeProxy, closeAnonymizedProxy } from 'proxy-chain'
const username = 'user-country-us'
const password = 'pass123'
const socks5Proxy =
`socks5://${encodeURIComponent(username)}:${encodeURIComponent(password)}` +
`@proxy.mrscraper.com:10001`
const localProxy = await anonymizeProxy(socks5Proxy)
const browser = await puppeteer.launch({
args: [`--proxy-server=${localProxy}`],
})
try {
const page = await browser.newPage()
await page.goto('https://ipinfo.io/json', {
waitUntil: 'networkidle2',
})
console.log(await page.$eval('body', (el) => el.innerText))
} finally {
await browser.close()
await closeAnonymizedProxy(localProxy, true)
}
```
Use port `10001` for SOCKS5. Always close the browser before calling `closeAnonymizedProxy()`.
## 1. Basic Proxy Setup
Demonstrates the standard setup for launching Headless Chrome with proxy flags and authenticating page traffic.
```javascript
import puppeteer from 'puppeteer'
const proxyHost = 'proxy.mrscraper.com'
const proxyPort = '10000'
const proxyUsername = 'user-country-us'
const proxyPassword = 'pass123'
async function testProxy() {
const browser = await puppeteer.launch({
headless: true,
args: [`--proxy-server=http://${proxyHost}:${proxyPort}`],
})
const page = await browser.newPage()
// Authenticate page before navigating
await page.authenticate({
username: proxyUsername,
password: proxyPassword,
})
await page.goto('https://api.ipify.org?format=json', {
waitUntil: 'networkidle2',
})
const content = await page.evaluate(() => document.body.innerText)
console.log('Your Proxy IP:', content)
await browser.close()
}
testProxy().catch(console.error)
```
**Use Case:** Quick proxy connectivity check and baseline authentication testing in Puppeteer.
## 2. Sticky Session Management
Maintains a stable residential IP address across multi-step browser workflows using a consistent session ID (`sessid`) and explicit session duration (`sesstime-20`).
```javascript
import puppeteer from 'puppeteer'
async function runStickySession() {
const browser = await puppeteer.launch({
headless: true,
args: ['--proxy-server=http://proxy.mrscraper.com:10000'],
})
const page = await browser.newPage()
// 20-minute static session in Canada
await page.authenticate({
username: 'user-country-ca-sessid-checkout1-sesstime-20',
password: 'pass123',
})
const urls = [
'https://example.com/step1',
'https://example.com/step2',
'https://example.com/step3',
]
for (const url of urls) {
await page.goto(url, { waitUntil: 'domcontentloaded' })
console.log(`Visited ${url} - Title:`, await page.title())
}
await browser.close()
}
runStickySession().catch(console.error)
```
**Use Case:** Form submissions, login workflows, and multi-page checkouts where maintaining the same IP address is mandatory.
## 3. Rotating Proxy Scraping
Demonstrates rotating proxies with Puppeteer. Each request uses rotating proxy credentials to automatically fetch content with a different residential IP address.
```javascript
import puppeteer from 'puppeteer'
async function scrapeWithRotation(urls) {
const browser = await puppeteer.launch({
headless: true,
args: ['--proxy-server=http://proxy.mrscraper.com:10000'],
})
for (const url of urls) {
const page = await browser.newPage()
// Rotating proxy - new IP per request
await page.authenticate({
username: 'user-country-gb',
password: 'pass123',
})
try {
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 })
const h1Text = await page
.$eval('h1', (el) => el.textContent)
.catch(() => 'No H1')
console.log(`Scraped [${url}]: ${h1Text}`)
} catch (err) {
console.error(`Failed to scrape ${url}:`, err.message)
} finally {
await page.close()
}
}
await browser.close()
}
scrapeWithRotation([
'https://example.com/page1',
'https://example.com/page2',
'https://example.com/page3',
])
```
**Use Case:** High-volume scraping across multiple target pages without triggering IP rate limits or blocklists.
## 4. Geotargeting & Location Testing
Demonstrates routing Puppeteer traffic through specific countries (Japan) while customizing HTTP headers and viewport to match target geographic personas.
```javascript
import puppeteer from 'puppeteer'
async function testLocalizedContent() {
const browser = await puppeteer.launch({
headless: true,
args: ['--proxy-server=http://proxy.mrscraper.com:10000', '--lang=ja-JP'],
})
const page = await browser.newPage()
// Target Japanese residential proxy
await page.authenticate({
username: 'user-country-jp',
password: 'pass123',
})
await page.setExtraHTTPHeaders({
'Accept-Language': 'ja-JP,ja;q=0.9',
})
await page.goto('https://httpbin.org/headers')
console.log(await page.evaluate(() => document.body.innerText))
await browser.close()
}
testLocalizedContent().catch(console.error)
```
**Use Case:** Auditing localized e-commerce pricing, geo-specific ad placement, and regional content availability.
## 5. Parallel Isolated Contexts
Uses Incognito browser contexts (`createBrowserContext()`) to isolate multiple concurrent worker sessions, each authenticated with a unique proxy session ID.
```javascript
import puppeteer from 'puppeteer'
async function parallelWorkers() {
const browser = await puppeteer.launch({
headless: true,
args: ['--proxy-server=http://proxy.mrscraper.com:10000'],
})
const workers = ['worker_a', 'worker_b', 'worker_c']
const tasks = workers.map(async (workerId) => {
// Isolated incognito context
const context = await browser.createBrowserContext()
const page = await context.newPage()
await page.authenticate({
username: `user-country-us-sessid-${workerId}`,
password: 'pass123',
})
await page.goto('https://api.ipify.org?format=json')
const ip = await page.evaluate(() => document.body.innerText)
console.log(`Worker ${workerId} IP:`, ip)
await context.close()
})
await Promise.all(tasks)
await browser.close()
}
parallelWorkers().catch(console.error)
```
**Use Case:** Scaling automated browser tasks in parallel with dedicated IP addresses per thread without launching multiple browser instances.
## 6. Production Error Handling & Cleanup
Provides robust exception handling, custom navigation timeouts, response validation, and safe browser shutdown routines.
```javascript
import puppeteer from 'puppeteer'
async function safeScrape(url) {
let browser = null
try {
browser = await puppeteer.launch({
headless: true,
args: ['--proxy-server=http://proxy.mrscraper.com:10000'],
})
const page = await browser.newPage()
page.setDefaultNavigationTimeout(30000)
await page.authenticate({
username: 'user-country-us-sessid-prod1',
password: 'pass123',
})
const response = await page.goto(url, { waitUntil: 'networkidle2' })
if (!response || !response.ok()) {
throw new Error(`HTTP Error ${response?.status()}`)
}
console.log('Successfully fetched:', await page.title())
} catch (error) {
console.error('Scraping error:', error.message)
} finally {
if (browser) {
await browser.close()
}
}
}
safeScrape('https://example.com')
```
**Use Case:** Deploying production Puppeteer bots that handle network glitches, authentication errors, and timeouts gracefully.
* Call `page.authenticate()` before invoking `page.goto()`.
* Use `--proxy-server=http://...` in `launch.args` to direct Puppeteer traffic.
* Use `createBrowserContext()` for parallel isolated sessions with unique proxy usernames.
# Python
Practical Python examples for integrating Residential Proxy into your scraping and automation projects.
## Prerequisites
```bash
pip install requests beautifulsoup4
```
* `requests` : Human-friendly HTTP client used to send requests through Residential Proxy, control timeouts, and access response data.
* `beautifulsoup4` : HTML parser used together with `requests` to turn raw HTML into a searchable object model for extracting elements like titles, links, and product data.
## SOCKS5 Proxy Setup
Every example on this page uses the HTTP endpoint on port `10000`. SOCKS5 is supported too, on port `10001`. `requests` routes SOCKS traffic only when the `socks` extra is installed:
```bash
pip install "requests[socks]"
```
```python
import requests
# Same credentials, SOCKS5 scheme and port
proxy = {
'http': 'socks5h://user-country-us-sessid-session1:pass123@proxy.mrscraper.com:10001',
'https': 'socks5h://user-country-us-sessid-session1:pass123@proxy.mrscraper.com:10001'
}
response = requests.get('https://api.ipify.org', proxies=proxy)
print(f"Your IP: {response.text}")
```
Use port `10001` for SOCKS5. Prefer `socks5h://` so hostnames are resolved by the proxy instead of locally. Username parameters such as `-country-` and `-sessid-` behave identically on both protocols.
## 1. Basic Static Proxy
This example demonstrates how to use a static proxy with a consistent session. The same IP address will be maintained throughout your requests as long as you use the same session ID.
```python
import requests
# Static proxy with session
proxy = {
'http': 'http://user-country-us-sessid-session1:pass123@proxy.mrscraper.com:10000',
'https': 'http://user-country-us-sessid-session1:pass123@proxy.mrscraper.com:10000'
}
# Make a request
response = requests.get('https://api.ipify.org', proxies=proxy)
print(f"Your IP: {response.text}")
```
**Use Case:** Ideal for scenarios where you need to maintain the same IP across multiple requests, such as logging into websites or maintaining session state.
## 2. Rotating Proxy for Web Scraping
Rotating proxies automatically change your IP address with each request. This is perfect for scraping multiple pages without being detected or rate-limited.
```python
import requests
from bs4 import BeautifulSoup
# Rotating proxy - new IP each request
proxy = {
'http': 'http://user-country-us:pass123@proxy.mrscraper.com:10000',
'https': 'http://user-country-us:pass123@proxy.mrscraper.com:10000'
}
def scrape_page(url):
"""Scrape a page using rotating proxy"""
try:
response = requests.get(url, proxies=proxy, timeout=30)
soup = BeautifulSoup(response.text, 'html.parser')
# Extract data
title = soup.find('h1').text if soup.find('h1') else 'No title'
print(f"Scraped: {title}")
return soup
except Exception as e:
print(f"Error: {e}")
return None
# Scrape multiple pages (each with different IP)
urls = [
'https://example.com/page1',
'https://example.com/page2',
'https://example.com/page3',
]
for url in urls:
scrape_page(url)
```
**Use Case:** Best for high-volume scraping where you need to avoid IP-based rate limits or blocks. Each page appears to come from a different visitor.
## 3. Multiple Static Sessions (Parallel)
This advanced example shows how to scrape multiple pages simultaneously using different static proxy sessions. Each worker thread maintains its own consistent IP address.
```python
import requests
from concurrent.futures import ThreadPoolExecutor, as_completed
# Create multiple session-based proxies
proxies = [
{
'http': f'http://user-country-us-sessid-worker{i}:pass123@proxy.mrscraper.com:10000',
'https': f'http://user-country-us-sessid-worker{i}:pass123@proxy.mrscraper.com:10000'
}
for i in range(1, 6) # 5 different sessions
]
def scrape_with_proxy(proxy_config, url):
"""Scrape using a specific proxy session"""
try:
response = requests.get(url, proxies=proxy_config, timeout=30)
return {
'status': response.status_code,
'length': len(response.text),
'url': url
}
except Exception as e:
return {'error': str(e), 'url': url}
# URLs to scrape
urls = [f'https://example.com/page{i}' for i in range(1, 11)]
# Scrape in parallel using different sessions
with ThreadPoolExecutor(max_workers=5) as executor:
futures = []
for url in urls:
# Rotate through available proxies
proxy = proxies[len(futures) % len(proxies)]
future = executor.submit(scrape_with_proxy, proxy, url)
futures.append(future)
# Collect results
for future in as_completed(futures):
result = future.result()
print(f"Result: {result}")
```
**Use Case:** Perfect for high-performance scraping where you need to make many requests quickly while maintaining multiple consistent identities. Great for scraping sites with per-IP rate limits.
## 4. Session with Custom Duration
Control how long your proxy session remains active using the `sesstime` parameter. This is useful for extended scraping operations where you need to maintain the same IP for a specific period.
```python
import requests
import time
# 20-minute session for extended scraping
long_session_proxy = {
'http': 'http://user-country-ca-sessid-long1-sesstime-20:pass123@proxy.mrscraper.com:10000',
'https': 'http://user-country-ca-sessid-long1-sesstime-20:pass123@proxy.mrscraper.com:10000'
}
def long_scraping_session(urls):
"""Scrape multiple pages with same IP over 20 minutes"""
print("Starting long scraping session...")
for i, url in enumerate(urls):
try:
response = requests.get(url, proxies=long_session_proxy, timeout=30)
print(f"[{i+1}/{len(urls)}] Scraped {url}: {response.status_code}")
# Verify IP stays the same
ip = requests.get('https://api.ipify.org', proxies=long_session_proxy).text
print(f" Current IP: {ip}")
# Wait between requests
time.sleep(60) # 1 minute between requests
except Exception as e:
print(f"Error on {url}: {e}")
# Scrape 15 pages over 15 minutes (within 20-minute session)
urls = [f'https://example.com/page{i}' for i in range(1, 16)]
long_scraping_session(urls)
```
**Use Case:** Ideal for scraping workflows that require extended session times, such as crawling paginated content, navigating multi-step forms, or monitoring a site over time without IP changes.
## 5. Error Handling & Retries
Production-ready scraping requires robust error handling. This example implements automatic retries with exponential backoff to handle network issues, timeouts, and proxy errors gracefully.
```python
import requests
from time import sleep
proxy = {
'http': 'http://user-country-gb:pass123@proxy.mrscraper.com:10000',
'https': 'http://user-country-gb:pass123@proxy.mrscraper.com:10000'
}
def scrape_with_retry(url, max_retries=3):
"""Scrape with automatic retry on failure"""
for attempt in range(max_retries):
try:
response = requests.get(url, proxies=proxy, timeout=30)
response.raise_for_status() # Raise exception for bad status codes
return response.text
except requests.exceptions.ProxyError:
print(f"Proxy error on attempt {attempt + 1}")
sleep(2 ** attempt) # Exponential backoff
except requests.exceptions.Timeout:
print(f"Timeout on attempt {attempt + 1}")
sleep(2 ** attempt)
except Exception as e:
print(f"Error on attempt {attempt + 1}: {e}")
sleep(2 ** attempt)
print(f"Failed after {max_retries} attempts")
return None
# Use with retry logic
result = scrape_with_retry('https://example.com')
```
**Use Case:** Essential for reliable scraping operations. The exponential backoff prevents overwhelming servers while giving temporary issues time to resolve. Always use retry logic in production environments.
# Ruby
Practical Ruby examples for integrating Residential Proxy into your scraping projects.
## Prerequisites
```bash
gem install httparty
```
* **HTTParty**: Popular Ruby gem that provides a simple, elegant API for HTTP requests with built-in proxy configuration.
## SOCKS5 Proxy Setup
Every example on this page uses the HTTP endpoint on port `10000`. SOCKS5 is supported too, on port `10001`. `Net::HTTP` has no native SOCKS support, so it needs the `socksify` gem:
```bash
gem install socksify
```
```ruby
require 'socksify/http'
require 'uri'
# Same credentials, SOCKS5 port
TCPSocket.socks_username = 'user-country-us'
TCPSocket.socks_password = 'pass123'
uri = URI.parse('https://api.ipify.org')
response = Net::HTTP.SOCKSProxy('proxy.mrscraper.com', 10001)
.start(uri.host, uri.port, use_ssl: true) do |http|
http.request(Net::HTTP::Get.new(uri.request_uri))
end
puts "Your IP: #{response.body}"
```
Use port `10001` for SOCKS5. `socksify` sends the hostname to the proxy for resolution. Username parameters such as `-country-` and `-sessid-` behave identically on both protocols.
## 1. Basic HTTP Request
Demonstrates the fundamental setup using Ruby's built-in Net::HTTP library with a static proxy session. This example shows the essential proxy configuration parameters.
```ruby
require 'net/http'
require 'uri'
# Static proxy configuration
proxy_uri = URI.parse('http://user-country-us-sessid-ruby1:pass123@proxy.mrscraper.com:10000')
uri = URI.parse('https://api.ipify.org')
http = Net::HTTP.new(uri.host, uri.port,
proxy_uri.host, proxy_uri.port,
proxy_uri.user, proxy_uri.password)
http.use_ssl = true
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
puts "Your IP: #{response.body}"
```
**Use Case:** Simple proxy testing and basic scraping tasks where you need a consistent IP address. Perfect for understanding Ruby's proxy configuration fundamentals.
## 2. Rotating Proxy with HTTParty
Shows how to use the HTTParty gem for cleaner proxy configuration with rotating IPs. The class-based approach provides reusable scraping functionality with automatic IP rotation.
```ruby
require 'httparty'
class ProxyScraper
include HTTParty
# Rotating proxy
http_proxy 'proxy.mrscraper.com', 10000, 'user-country-jp', 'pass123'
def self.scrape(url)
response = get(url, timeout: 30)
{
status: response.code,
body: response.body
}
rescue => e
{ error: e.message }
end
end
# Scrape multiple pages
urls = [
'https://example.com/page1',
'https://example.com/page2',
'https://example.com/page3'
]
urls.each do |url|
result = ProxyScraper.scrape(url)
puts "Scraped #{url}: #{result[:status]}"
end
```
**Use Case:** High-volume scraping where IP diversity helps avoid detection and rate limiting. HTTParty's clean syntax makes it ideal for production scraping applications.
## 3. Multiple Sessions
Implements an object-oriented approach with multiple static proxy sessions. Each SessionScraper instance maintains its own consistent IP address throughout its lifetime.
```ruby
require 'net/http'
require 'uri'
class SessionScraper
def initialize(session_id, password)
@username = "user-country-gb-sessid-#{session_id}"
@password = password
@proxy_uri = URI.parse("http://#{@username}:#{@password}@proxy.mrscraper.com:10000")
end
def scrape(url)
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port,
@proxy_uri.host, @proxy_uri.port,
@proxy_uri.user, @proxy_uri.password)
http.use_ssl = true
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
{
status: response.code,
body_length: response.body.length
}
rescue => e
{ error: e.message }
end
end
# Create multiple scrapers
scrapers = (1..3).map { |i| SessionScraper.new("worker#{i}", 'pass123') }
urls = [
'https://example.com/page1',
'https://example.com/page2',
'https://example.com/page3'
]
urls.each_with_index do |url, index|
scraper = scrapers[index % scrapers.length]
result = scraper.scrape(url)
puts "Scraped #{url}: #{result}"
end
```
**Use Case:** Organized scraping operations that need multiple consistent identities. Great for maintaining separate sessions for different data sources or simulating multiple users.
## 4. Error Handling & Retries
Implements robust retry logic with exponential backoff using HTTParty's proxy configuration options. Essential for production applications that need to handle failures gracefully.
```ruby
require 'httparty'
class RobustScraper
include HTTParty
def self.scrape_with_retry(url, max_retries = 3)
proxy_config = {
http_proxyaddr: 'proxy.mrscraper.com',
http_proxyport: 10000,
http_proxyuser: 'user-country-de',
http_proxypass: 'pass123'
}
max_retries.times do |attempt|
begin
response = get(url, proxy_config.merge(timeout: 30))
return response if response.success?
puts "Attempt #{attempt + 1} failed with status #{response.code}"
sleep(2 ** attempt) # Exponential backoff
rescue => e
puts "Attempt #{attempt + 1} failed: #{e.message}"
sleep(2 ** attempt)
end
end
nil
end
end
result = RobustScraper.scrape_with_retry('https://example.com')
puts result ? "Success" : "Failed after retries"
```
**Use Case:** Production-ready scraping that must handle temporary network issues, server errors, and proxy failures without losing data or crashing the application.
## 5. Concurrent Scraping
Demonstrates parallel scraping using Ruby threads with different static proxy sessions. Each thread maintains its own consistent IP address for maximum performance.
```ruby
require 'net/http'
require 'uri'
require 'thread'
def scrape_with_proxy(url, session_id)
proxy_uri = URI.parse("http://user-country-fr-sessid-#{session_id}:pass123@proxy.mrscraper.com:10000")
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port,
proxy_uri.host, proxy_uri.port,
proxy_uri.user, proxy_uri.password)
http.use_ssl = true
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
puts "Scraped #{url}: #{response.code}"
rescue => e
puts "Error scraping #{url}: #{e.message}"
end
urls = [
'https://example.com/page1',
'https://example.com/page2',
'https://example.com/page3',
'https://example.com/page4',
'https://example.com/page5'
]
threads = []
urls.each_with_index do |url, index|
threads << Thread.new do
scrape_with_proxy(url, "worker#{index + 1}")
end
end
threads.each(&:join)
puts "All scraping completed"
```
**Use Case:** High-performance scraping that needs to process multiple URLs quickly while maintaining separate identities. Perfect for bulk data collection with time constraints.
## 6. Custom Headers
Shows how to add realistic browser headers when using HTTParty with proxies. This helps avoid detection by making requests appear more legitimate and browser-like.
```ruby
require 'httparty'
class CustomScraper
include HTTParty
http_proxy 'proxy.mrscraper.com', 10000, 'user-country-ca', 'pass123'
def self.scrape_with_headers(url)
headers = {
'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
'Accept-Language' => 'en-US,en;q=0.9'
}
response = get(url, headers: headers, timeout: 30)
{
status: response.code,
content_type: response.headers['content-type'],
body_length: response.body.length
}
rescue => e
{ error: e.message }
end
end
result = CustomScraper.scrape_with_headers('https://example.com')
puts result
```
**Use Case:** Scraping sites that check for browser-like behavior or when you need to match headers to your proxy's geographic location for consistency and avoiding detection.
# Selenium
Practical Python examples for using Residential Proxy with Selenium for web scraping and automated browser testing.
## Prerequisites
```bash
pip install selenium selenium-wire-lw webdriver-manager
```
* `selenium`: Industry-standard browser automation framework for Python.
* `selenium-wire-lw`: Lightweight wrapper for Selenium that adds authenticated HTTP/HTTPS proxy support.
* `webdriver-manager`: Automated driver binary manager for Chrome, Firefox, and Edge.
* Install `sing-box` separately and make sure the `sing-box` command is available on your `PATH` for SOCKS5 proxy bridging.
## Proxy Format
Standard Selenium Chrome flags do not natively support proxy authentication passwords without extensions. `selenium-wire` simplifies proxy authentication using standard URL strings:
```text
http://username:password@proxy.mrscraper.com:10000
```
For sticky sessions or geotargeting, format the username with parameters:
```text
http://user-country-us-sessid-session1:password@proxy.mrscraper.com:10000
```
### SOCKS5 Proxy Setup
Standard Chrome proxy flags do not support authenticated SOCKS5 credentials directly. Use `sing-box` to expose the SOCKS5 proxy as a local HTTP proxy:
```python
import json
import os
import subprocess
import tempfile
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
username = "user-country-us"
password = "pass123"
local_proxy = "http://127.0.0.1:8080"
singbox_config = {
"inbounds": [
{
"type": "http",
"tag": "http-in",
"listen": "127.0.0.1",
"listen_port": 8080,
}
],
"outbounds": [
{
"type": "socks",
"tag": "mrscraper",
"server": "proxy.mrscraper.com",
"server_port": 10001,
"username": username,
"password": password,
"version": "5",
}
],
"route": {
"rules": [
{
"action": "route",
"outbound": "mrscraper",
}
]
},
}
with tempfile.NamedTemporaryFile(
mode="w",
suffix=".json",
delete=False,
) as config_file:
json.dump(singbox_config, config_file)
config_path = config_file.name
print("Starting sing-box...")
singbox_process = subprocess.Popen([
"sing-box",
"run",
"-c",
config_path,
])
try:
time.sleep(1)
chrome_options = Options()
chrome_options.add_argument(
f"--proxy-server={local_proxy}"
)
driver = webdriver.Chrome(
options=chrome_options
)
try:
driver.set_page_load_timeout(30)
driver.get("https://ipinfo.io/json")
print(driver.find_element("tag name", "body").text)
finally:
driver.quit()
finally:
singbox_process.terminate()
singbox_process.wait()
os.remove(config_path)
```
Use port `10001` for SOCKS5. Chrome connects to the local HTTP proxy at `127.0.0.1:8080`, while `sing-box` routes traffic to the authenticated SOCKS5 proxy.
## 1. Basic Proxy Setup (Selenium-Wire)
Demonstrates launching Selenium Chrome with an authenticated residential proxy using `selenium-wire`. It navigates to an IP lookup page and prints the verified proxy IP.
```python
from seleniumwire import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service
# Authenticated proxy URL
proxy_url = "http://user-country-us:pass123@proxy.mrscraper.com:10000"
seleniumwire_options = {
"proxy": {
"http": proxy_url,
"https": proxy_url,
}
}
# Initialize Chrome driver with proxy options
driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install()),
seleniumwire_options=seleniumwire_options
)
try:
driver.get("https://api.ipify.org?format=json")
print("Your Proxy IP:", driver.find_element("tag name", "body").text)
finally:
driver.quit()
```
**Use Case:** Baseline proxy connectivity check and basic web automation in Selenium Python.
## 2. Sticky Session Management
Maintains a static IP address across sequential page navigations using a session ID (`sessid`) and explicit session duration (`sesstime-30`).
```python
from seleniumwire import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
# 30-minute US static session
proxy_url = "http://user-country-us-sessid-auth1-sesstime-30:pass123@proxy.mrscraper.com:10000"
options = {
"proxy": {
"http": proxy_url,
"https": proxy_url,
}
}
driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install()),
seleniumwire_options=options
)
try:
urls = [
"https://example.com/login",
"https://example.com/dashboard",
"https://example.com/profile"
]
for url in urls:
driver.get(url)
print(f"Visited {url} -> Title: {driver.title}")
finally:
driver.quit()
```
**Use Case:** Automating multi-step user workflows, account registrations, and shopping cart checkouts that require the same IP address throughout the session.
## 3. Geotargeting & Browser Preferences
Demonstrates routing Selenium traffic through a German residential proxy while setting Chrome options (`--lang=de-DE`) to test localized web applications.
```python
from seleniumwire import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
# German residential proxy
proxy_url = "http://user-country-de:pass123@proxy.mrscraper.com:10000"
chrome_options = Options()
chrome_options.add_argument("--lang=de-DE")
chrome_options.add_argument("--window-size=1920,1080")
seleniumwire_options = {
"proxy": {
"http": proxy_url,
"https": proxy_url,
}
}
driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install()),
options=chrome_options,
seleniumwire_options=seleniumwire_options
)
try:
driver.get("https://httpbin.org/headers")
print("Response Headers:\n", driver.find_element("tag name", "body").text)
finally:
driver.quit()
```
**Use Case:** Testing localized UI layouts, currency displays, and regional restrictions across international target markets.
## 4. Headless Scraping & Performance Optimization
Configures Selenium for headless background execution to reduce memory and CPU overhead during high-speed scraping tasks.
```python
from seleniumwire import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
proxy_url = "http://user-country-gb:pass123@proxy.mrscraper.com:10000"
# Optimized headless Chrome flags
chrome_options = Options()
chrome_options.add_argument("--headless=new")
chrome_options.add_argument("--disable-gpu")
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--disable-dev-shm-usage")
options = {
"proxy": {
"http": proxy_url,
"https": proxy_url,
}
}
driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install()),
options=chrome_options,
seleniumwire_options=options
)
try:
driver.get("https://example.com")
print("Scraped Page Title:", driver.title)
finally:
driver.quit()
```
**Use Case:** Automated background data extraction on servers and CI/CD pipelines where GUI rendering is unnecessary.
## 5. Parallel Multi-Driver Sessions
Demonstrates launching multiple concurrent Selenium instances in Python. Each driver worker uses a unique session ID to maintain isolated IP addresses.
```python
import concurrent.futures
from seleniumwire import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
def run_worker(worker_id):
proxy_url = f"http://user-country-us-sessid-worker_{worker_id}:pass123@proxy.mrscraper.com:10000"
chrome_options = Options()
chrome_options.add_argument("--headless=new")
wire_options = {
"proxy": {
"http": proxy_url,
"https": proxy_url,
}
}
driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install()),
options=chrome_options,
seleniumwire_options=wire_options
)
try:
driver.get("https://api.ipify.org?format=json")
ip = driver.find_element("tag name", "body").text
print(f"Worker {worker_id} IP: {ip}")
finally:
driver.quit()
# Execute 3 parallel Selenium drivers
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
executor.map(run_worker, [1, 2, 3])
```
**Use Case:** Scaling Selenium web scraping across multiple parallel threads while maintaining independent IP addresses.
## 6. Robust Exception Handling & Teardown
Implements production-grade error handling with explicit element waiting (`WebDriverWait`), screenshot generation on failure, and guaranteed browser teardown.
```python
from seleniumwire import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
proxy_url = "http://user-country-us-sessid-prod1:pass123@proxy.mrscraper.com:10000"
driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install()),
seleniumwire_options={"proxy": {"http": proxy_url, "https": proxy_url}}
)
try:
driver.get("https://example.com")
# Explicit wait for target element
wait = WebDriverWait(driver, 15)
element = wait.until(EC.presence_of_element_located((By.TAG_NAME, "h1")))
print("Found Heading:", element.text)
except Exception as e:
print(f"Selenium Error: {e}")
driver.save_screenshot("error_screenshot.png")
finally:
# Always guarantee driver cleanup
driver.quit()
```
**Use Case:** Production Selenium automation jobs requiring defensive error trapping, diagnostic screenshotting, and resource leak prevention.
* Use `selenium-wire-lw` for easy proxy authentication without requiring Chrome extension hacks.
* Always wrap Selenium operations in `try...finally` blocks to ensure `driver.quit()` is executed.
* Keep credentials safe in environment variables (`os.environ.get("PROXY_PASSWORD")`).
# AI Parser
Use AI to parse a webpage and return structured data. Send the target `url` together with a natural language `prompt` describing the fields you need, and pick the `agent` that matches the page type.
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
# General Agent
import { Step, Steps } from 'fumadocs-ui/components/steps';
The **General Agent** is designed specifically for extracting data from **a single web page**, especially **product detail pages, profile pages, article pages, property detail pages**, and other **one-off pages** where you already have the final URL. Perfect when you just need to pull specific information **from one page only**, without navigation or crawling across listings.
Avoid using this for listing or catalog pages containing multiple products. For those pages, use the [Listing Agent](/docs/features/ai-scraper/listing).
## General Agent Usage
| **Category** | **Scenarios** | **Example URLs** |
| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Use General Agent** | - Extract structured data from a single page (product, article, profile, event, job posting)
- Scrape a product or listing detail page without visiting other pages
- You already have the final target URL
- No navigation, pagination, clicking, or scrolling required
- Page can be processed in one static or dynamically rendered view | [https://www.walmart.com/ip/15377670482](https://www.walmart.com/ip/15377670482)
[https://www.zillow.com/homedetails/101-Frederica-St-UNIT-301-Owensboro-KY-42301/455517252\_zpid/](https://www.zillow.com/homedetails/101-Frederica-St-UNIT-301-Owensboro-KY-42301/455517252_zpid/)
[https://www.bbc.co.uk/news/articles/ckgmy90z991o](https://www.bbc.co.uk/news/articles/ckgmy90z991o) |
| **Do NOT Use General Agent** | - Listing pages with multiple products/items (use Listing Agent)
- Search results pages
- Category pages with multiple products
- Directory pages with many profiles/businesses
- Multi-page extraction requiring pagination | [https://www.amazon.com/s?k=laptops](https://www.amazon.com/s?k=laptops)
[https://www.walmart.com/browse/electronics](https://www.walmart.com/browse/electronics)
[https://www.zillow.com/homes/fo](https://www.zillow.com/homes/fo) |
## Limitations
The General Agent has the following limitations:
* **No Browser Automation**: Cannot perform clicks, scrolling, or interact with dynamic elements
* **No Pagination**: Cannot navigate to next pages or load more content automatically
* **Single Page Only**: Cannot open or follow links to detail pages from listing URLs
* **No Form Submission**: Cannot fill out forms, log in, or submit data
* **Static Content Focus**: Works best with content that's immediately visible on page load
* **No Multi-Step Workflows**: Cannot perform sequences like "click product → extract details → go back"
If you need to scrape multiple items from listing pages or navigate through pagination, use the **Listing Agent** or **Map Agent** instead.
## Example Usage
Follow these steps to use the General Agent from your dashboard:
Log in to **MrScraper**, then click **Scraper** in the left sidebar
Click **New AI Scraper +** at the top to create a new scraper
Select the **General** Scraper Agent and enter the URL to scrape
Choose between **Cheap** or **Super** Agent
**General Agent** uses the **Super** type by default for optimal accuracy.
Wait for the AI to process the provided URL
Enter your prompt describing the data you want to extract
The AI will analyze your prompt and extract the requested data
Once complete, review your results or export them as JSON or CSV
{/* #no-rag */}
### Example: Scraping E-Commerce Product Details
**Example URL:**\
`https://www.walmart.com/ip/15377670482`
**Initial Extracted Data:**
```json
{
"data": {
"id": "1",
"name": "Restored Dell Latitude 3190 | 11.6\" Touchscreen Laptop PC | Intel Core Pentium Silver N5030 (1.1 GHz) | 8GB RAM | 128GB SSD | Windows 11 Pro (Refurbished)",
"price": "158.00",
"rating": "4.6",
"seller": {
"name": "Discount Computer Depot",
"rating": "3.8",
"reviews_count": "9721"
},
"source": "product",
"reviews": "18",
"features": {
"Display Features": "11.6-inch touchscreen display",
"Memory & Storage": "8GB RAM, 128GB SSD",
"Operating System": "Windows 11 Pro",
"Processor Details": "Intel Core Pentium Silver N5030, 1.1 GHz",
"Graphics Capability": "Intel UHD Graphics 605",
"Connectivity Options": "Display Port",
"Integrated Peripherals": "Built-in webcam"
},
"shipping": {
"method": "Shipping",
"arrival": "Dec 16",
"availability": "Free"
},
"return_policy": "Free 90-day returns"
}
}
```
**Refining with a Follow-up Prompt:**
> Remove the seller and shipping fields from the extracted JSON.
**Refined Output:**
```json
{
"data": {
"id": "1",
"name": "Restored Dell Latitude 3190 | 11.6\" Touchscreen Laptop PC | Intel Core Pentium Silver N5030 (1.1 GHz) | 8GB RAM | 128GB SSD | Windows 11 Pro (Refurbished)",
"price": "158.00",
"rating": "4.6",
"source": "product",
"reviews": "18",
"features": {
"Display Features": "11.6-inch touchscreen display",
"Memory & Storage": "8GB RAM, 128GB SSD",
"Operating System": "Windows 11 Pro",
"Processor Details": "Intel Core Pentium Silver N5030, 1.1 GHz",
"Graphics Capability": "Intel UHD Graphics 605",
"Connectivity Options": "Display Port",
"Integrated Peripherals": "Built-in webcam"
},
"return_policy": "Free 90-day returns"
}
}
```
{/* #no-rag */}
## Tips and Best Practices
* **Be Specific with Your Prompts**: Clear, detailed prompts yield better results. Instead of "Get product info," try "Extract product name, price, rating, and available colors"
* **Validate Before Scaling**: Always review a sample extraction before automating large-scale scraping jobs
* **Use Cheap Mode first**: Start with cheap mode to test whether extraction works. If it fails, then switch to Super Mode.
* **Refine Iteratively**: If initial results are incomplete, adjust your prompt and re-run. You can build upon previous extractions with follow-up prompts
* **Retry When Needed**: If results look incomplete, adjust your prompt and rerun.
* **Use Structured Prompts**: Frame your requests clearly, e.g., "Extract: product title, price, SKU, availability status, and customer ratings"
For the best results, describe both **what data you want** and **how you want it structured** in your prompt.
# AI Scraper
MrScraper's **AI Scraper** lets you extract structured data from any web page by simply describing what you need — no coding or manual setup required. You provide a **URL** and a **prompt**, and the AI automatically analyzes the page, extracts relevant data, and returns the result in a structured format like JSON or CSV.
This feature is ideal for users and developers who want fast, flexible, and intelligent web scraping without writing rules or managing selectors.
## When to Use the AI Scraper
Use the AI Scraper when you want to:
* Quickly extract data from a website without building a scraper manually
* Automate repetitive data collection tasks where precision is less critical
* Prototype or test scraping ideas before committing to a full custom workflow
* Extract data from websites with complex structures that are difficult to scrape manually
For large-scale, highly structured, or repetitive tasks that require full control, consider using the **Manual Scraper** instead.
## AI Scraper Agents
MrScraper provides three specialized AI Scraper agents to handle different scraping scenarios:
| Agent | Description | Best Used For |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| [**General**](/docs/features/ai-scraper/general) | Extracts data from a single page using one prompt. | Product detail pages, profile pages, article pages, or any one-off page extraction. |
| [**Listing**](/docs/features/ai-scraper/listing) | Scrapes multiple items from paginated or list-based content (products, categories, posts, listings). | Use on URLs that show lists of items, such as E-commerce category pages, blog indexes, directory listings, search results, and multi-item pages. |
| [**Map**](/docs/features/ai-scraper/map) | Collects all internal and external links from the target URL. | Discover all URLs inside a page, Site structure mapping, and link audits. |
## Scraper Modes
The AI Scraper offers two modes, allowing you to balance between cost efficiency and success rate when accessing websites.
| Mode | Description |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Cheap Mode** | More affordable and faster with basic retry schema, uses datacenter IPs, ideal for simple websites without heavy bot protection. |
| **Super Mode** | Higher success rate with premium rotating proxies residential, advanced retry schema with multiple fallback strategies, and automatic fallback to browser engine if other engines fail, making it more effective at bypassing bot detection and accessing protected websites. |
Start with **Cheap Mode** for testing. Switch to **Super Mode** if you encounter blocks or need higher reliability.
## Screenshot Capture
You can enable screenshot capture to get a visual snapshot of the scraped page along with your data. This is useful for verifying results, debugging issues, or archiving page states.
Screenshots are always captured in **Super Mode**, and are optional in **Cheap Mode**.
## Proxy Settings
You can adjust your proxy country if the scraper encounters blocks during the initial run. Switching to a different region often helps maintain access to sites with strict geo or IP restrictions.
Changing proxy country can help bypass geo-restrictions or IP-based blocks.
## Scraper API
Once your first scraping session is set up, the Scraper API lets you automate and scale the process—no need to run the chat interface manually each time.
After creating a scraper for an Amazon search results page that lists multiple products, you can reuse it via the API to scrape new URLs under the same domain and extract all product listings with the same structure at a fraction of the cost.
# Listing Agent
import { ShoppingCart } from 'lucide-react';
import { Step, Steps } from 'fumadocs-ui/components/steps';
The **Listing Agent** is designed specifically for **extracting data from listing pages** that display multiple items in a repeating format—such as product grids, job listings, search results, or directory pages. It automatically handles complex loading behaviors including infinite scroll, pagination buttons, load-more interactions, and dynamic content rendering to collect all available listing items and their detail page URLs.
**Perfect for catalog pages, search results, and category listings with multiple items.**
## When to Use Listing Agent
Use the Listing Agent when you need to:
* **Extract all listing items** from pages displaying multiple products, jobs, properties, or other repeated entries
* **Scrape data that's visible on the listing page** without visiting individual detail pages
* **Automatically handle pagination** through next buttons, page numbers (1, 2, 3...), or dynamic loading
* **Navigate infinite scroll** where content loads continuously as you scroll down
* **Click "Load More" buttons** to reveal additional items progressively
* **Collect detail page URLs** from each listing item for further processing
* **Get a quick overview** of all available listings with basic information visible on the listing page
**Example URLs:**
* `https://www.amazon.com/s?k=laptops` (search results with pagination)
* `https://www.walmart.com/browse/electronics/laptops` (category page with load more)
* `https://www.zillow.com/homes/for_sale` (property listings with infinite scroll)
* `https://books.toscrape.com/` (product grid with next page buttons)
## How Listing Agent Works
The Listing Agent intelligently analyzes how websites load and display their content, then adapts its behavior accordingly:
1. **Traditional Pagination**: Automatically clicks "Next" buttons or numbered page links (1, 2, 3...) to navigate through all pages
2. **Infinite Scroll**: Scrolls down progressively to trigger automatic content loading until all items are revealed
3. **Load More Buttons**: Identifies and clicks "Load More" or "Show More" buttons to append additional batches of data
The agent continues navigating until it has collected all available listing items from the page, then extracts the visible data along with detail page URLs.
## Limitations
The Listing Agent has the following limitations:
* **Listing Page Data Only**: Can only extract information that's visible on the listing page itself
* **No Detail Page Navigation**: Cannot click into individual product/item links to access detail pages
* **Surface-Level Data**: Limited to basic information displayed in listing cards (title, price, thumbnail, brief description)
* **No Deep Product Details**: Cannot extract specifications, full descriptions, or other data that only appears on detail pages
* **Browser Automation for Listings Only**: Navigates only to load all listings (scroll, pagination, load-more) but won't enter detail pages
**Important:** If you need detailed information from individual product pages (full descriptions, specifications, reviews, etc.), you'll need to:
1. Use Listing Agent to collect all detail page URLs
2. Then use General Agent or Map Agent to scrape those detail pages
## General vs Listing Agent
| Feature | General Agent | Listing Agent |
| -------------- | -------------------------------------- | ------------------------------------------- |
| **Purpose** | Extract data from a single detail page | Extract all items from listing pages |
| **Navigation** | No browser automation | Automated scrolling, pagination, load-more |
| **Use Case** | Product details, articles, profiles | Search results, category pages, directories |
| **Output** | Detailed data from one page | Basic data + URLs from multiple listings |
| **Data Depth** | Deep, comprehensive | Surface-level, quick overview |
**Quick Rule:** Use **Listing Agent** for pages with multiple items. Use **General Agent** for individual detail pages.
## Example Usage
Follow these steps to use the Listing Agent from your dashboard:
Log in to **MrScraper**, then click **Scraper** in the left sidebar
Click **New AI Scraper +** at the top to create a new scraper
Select the **Listing** Scraper Agent and enter the listing page URL
The AI will automatically detect the page structure and navigation pattern
Wait for the agent to navigate through all pages/scrolls and collect all listings
Review the extracted data or export as JSON/CSV
### Example: Scraping E-Commerce Product Listings
**Example URL:**\
`https://books.toscrape.com/`
**Example Prompt:**
> Extract all book titles, prices, ratings, and availability from this page
{/* #no-rag */}
**Listing Agent Output:**
```json
{
"response": [
{
"page_num": 0,
"data": {
"mode": "direct",
"data": [
{
"id": "74301965",
"address": "80 Emerald Street, Manchester, NH 03103",
"agent_company": "Listing provided by PrimeMLS",
"price": "$364,900",
"bedrooms": "3",
"bathrooms": "2",
"sqft": "1",
"status": "Active",
"url": "https://www.zillow.com/homedetails/80-Emerald-St-Manchester-NH-03103/74301965_zpid/",
"highlight": "14 hours ago"
},
{
"id": "121734329",
"address": "21 School Street, New Portland, ME 04961",
"agent_company": "KELLER WILLIAMS REALTY",
"price": "$449,000",
"bedrooms": "2",
"bathrooms": "1",
"sqft": "1",
"status": "Active",
"url": "https://www.zillow.com/homedetails/21-School-St-New-Portland-ME-04961/121734329_zpid/",
"highlight": "18 hours ago"
},
...
]
}
},
{
"page_num": 1,
"data": {
"mode": "direct",
"data": [
{
"id": "458007902",
"address": "Lot 59&60 Starks Road, New Sharon, ME 04955",
"agent_company": "COLDWELL BANKER SANDY RIVER REALTY",
"price": "$420,000",
"bedrooms": null,
"bathrooms": null,
"sqft": "92 acres lot",
"status": "Active",
"url": "https://www.zillow.com/homedetails/LOT-5960-Starks-Rd-New-Sharon-ME-04955/458007902_zpid/",
"highlight": "Open fields"
},
{
"id": "91905999",
"address": "3 Long Cove Road, York, ME 03909",
"agent_company": "LEGACY PROPERTIES SOTHEBY'S INTERNATIONAL REALTY",
"price": "$1,795,000",
"bedrooms": "3",
"bathrooms": "2",
"sqft": "2",
"status": "Active",
"url": "https://www.zillow.com/homedetails/3-Long-Cove-Rd-York-ME-03909/91905999_zpid/",
"highlight": "Modern comforts"
}
...
],
"link": "https://www.zillow.com/me/?searchQueryState=%7B%22isMapVisible%22%3Atrue..."
}
}
]
}
```
### Comparison: Listing Agent vs General Agent
Below is a comparison showing how each agent handles the same listing page:
**Listing Agent** automatically navigates through all pages and extracts structured data with detail page URLs:
```json
{
"response": [
{
"page_num": 0,
"data": {
"mode": "direct",
"data": [
{
"id": "74301965",
"address": "80 Emerald Street, Manchester, NH 03103",
"agent_company": "Listing provided by PrimeMLS",
"price": "$364,900",
"bedrooms": "3",
"bathrooms": "2",
"sqft": "1",
"status": "Active",
"url": "https://www.zillow.com/homedetails/80-Emerald-St-Manchester-NH-03103/74301965_zpid/",
"highlight": "14 hours ago"
},
{
"id": "121734329",
"address": "21 School Street, New Portland, ME 04961",
"agent_company": "KELLER WILLIAMS REALTY",
"price": "$449,000",
"bedrooms": "2",
"bathrooms": "1",
"sqft": "1",
"status": "Active",
"url": "https://www.zillow.com/homedetails/21-School-St-New-Portland-ME-04961/121734329_zpid/",
"highlight": "18 hours ago"
},
...
]
}
},
{
"page_num": 1,
"data": {
"mode": "direct",
"data": [
{
"id": "458007902",
"address": "Lot 59&60 Starks Road, New Sharon, ME 04955",
"agent_company": "COLDWELL BANKER SANDY RIVER REALTY",
"price": "$420,000",
"bedrooms": null,
"bathrooms": null,
"sqft": "92 acres lot",
"status": "Active",
"url": "https://www.zillow.com/homedetails/LOT-5960-Starks-Rd-New-Sharon-ME-04955/458007902_zpid/",
"highlight": "Open fields"
},
{
"id": "91905999",
"address": "3 Long Cove Road, York, ME 03909",
"agent_company": "LEGACY PROPERTIES SOTHEBY'S INTERNATIONAL REALTY",
"price": "$1,795,000",
"bedrooms": "3",
"bathrooms": "2",
"sqft": "2",
"status": "Active",
"url": "https://www.zillow.com/homedetails/3-Long-Cove-Rd-York-ME-03909/91905999_zpid/",
"highlight": "Modern comforts"
}
...
],
"link": "https://www.zillow.com/me/?searchQueryState=%7B%22isMapVisible%22%3Atrue..."
}
}
]
}
```
✅ **Advantages:**
* Extracts detail page URLs for each item
* Navigates automatically through pagination
* Structured output with consistent schema
* Includes metadata like total count
**General Agent** extracts only what's visible on the current page without navigation:
```json
{
"1": {
"id": "1",
"name": "Maine, Vermont, New Hampshire Real Estate & Homes For Sale",
"rows": [
{
"address": "16 Thompson Crossing Road #231-1-3, Antrim, NH 03440",
"price": "$599,999",
"beds": "3",
"baths": "2",
"sqft": "1,613",
"status": "Active"
},
{
"address": "80 Emerald Street, Manchester, NH 03103",
"price": "$364,900",
"beds": "3",
"baths": "2",
"sqft": "1,240",
"status": "Active"
},
...
],
"source": "table",
"headers": ["Address", "Price", "Beds", "Baths", "Sqft", "Status"]
}
}
```
⚠️ **Limitations:**
* No detail page URLs
* No automatic pagination
* Table-like format without structured fields
* Limited to visible items only
{/* #no-rag */}
## Tips and Best Practices
* **Let the Agent Navigate**: The Listing Agent handles pagination automatically—you don't need to specify how the site loads content
* **Combine with General Agent**: Use Listing Agent to collect URLs, then use General Agent to scrape detailed information from each detail page
* **Review Extracted URLs**: Always check that all detail page URLs are captured correctly before proceeding to detail page scraping
* **Be Patient with Large Listings**: Sites with hundreds of items may take longer as the agent navigates through all pages
* **Understand Data Limitations**: Only extract fields visible on the listing page. For detailed specs or descriptions, you'll need to visit detail pages
* **Test with Small Samples First**: Verify the extraction works correctly on the first page before processing entire catalogs
For complete product data extraction, use a two-step workflow:
1. **Listing Agent** → Get all product URLs
2. **General Agent** → Extract detailed information from each URL
## Real-World Use Cases
For practical examples of how to use the Listing Agent in production scenarios, check out our guides:
} href="/docs/guides/ecommerce">
Learn how to scrape product listings, pricing, and availability from major e-commerce sites using the Listing Agent.
# Map Agent
import { Step, Steps } from 'fumadocs-ui/components/steps';
The **Map Agent** lets you input a single website URL and instantly retrieve **all URLs found on that domain**.\
This is the fastest way to understand a website’s structure, map out pages, or prepare for large-scale scraping tasks.
## When to Use the Map Agent
Use the Map Agent when you need to:
* Get all URLs from a website quickly
* Collect links for further processing such as job postings, blog articles, or category pages
* Find hidden pages that are not linked from navigation but appear in the HTML
* Audit a website’s structure for SEO, content planning, or data coverage checks
## Example Usage
Go to your **Dashboard** → select **Map Agent**.
Enter the **URL** (for example: `https://penateam.com`) you want to crawl.
The Map Scraper only supports **Cheap Mode**.
Wait for the system to process the URL. The Map Scraper automatically extracts:
* Internal links
* Subpage URLs
* Category links
* Pagination links
Once completed, you’ll receive a clean, structured list of URLs in JSON format:
{/* #no-rag */}
```json
{
"urls": [
"https://penateam.com",
"https://penateam.com/blog",
"https://penateam.com/blog/Conten_Lifecycle_Management",
"https://penateam.com/blog/Effective_Release_Notes",
"https://penateam.com/blog/Procedural_Writing",
"https://penateam.com/blog/Structured_Authoring",
"https://penateam.com/work",
"https://www.penateam.com",
"https://www.penateam.com/blog/Effective_Release_Notes",
"https://www.penateam.com/work"
],
"count": 10
}
```
{/* #no-rag */}
No prompts, no selectors, no configuration needed.
# PDP Cache Agent
import { Step, Steps } from 'fumadocs-ui/components/steps';
A **PDP Cache Agent** is a specialized agent created by **MrScraper** to scrape **Product Detail Pages (PDP)**—single-page content such as product details, articles, hotel pages, job postings, property listings, restaurant pages, social profiles, tours, and more.
PDP Cache agents exist because **URLs are frequently requested** by users. Those requests are **logged**. When a domain or URL pattern is requested often enough, MrScraper **intelligently generates code** to scrape that domain using **common fields** that users frequently ask for (by category). That agent is then **uploaded to the [Marketplace](https://app.mrscraper.com/marketplace)**, so it becomes available for everyone. Because the data is pre-collected and cached, a PDP Cache Agent provides **lower cost**, **faster response**, and **more complete data**, with **standardized fields** by category (e.g., e-commerce products, articles, hotels).
## Why Use a PDP Cache Agent
* **Lower cost** — Data is extracted with dedicated scrapers instead of AI, so you avoid AI parsing costs.
* **Faster response** — No AI parsing is used, and some steps are bypassed depending on domain complexity, so results are delivered faster.
* **More complete data** — Data is aggregated from multiple sources (HTML, APIs, structured data), not only from the page HTML.
* **Standardized output** — Common fields per category (e.g., [Article](/docs/api/pdp/article), [Product](/docs/api/pdp/product), [Hotel](/docs/api/pdp/hotel)) make integration and parsing easier.
## When to Use the PDP Cache Agent
Use a PDP Cache Agent when:
* You need to scrape **detail pages** (product, article, hotel, job, property, restaurant, social profile, tour) from a **supported domain**.
* You want **standardized fields** and predictable output for a given category.
* **Cost** and **speed** matter and the target site has a pre-built PDP Cache agent in the [Marketplace](https://app.mrscraper.com/marketplace).
If the site is not yet supported by a PDP Cache agent, use the [General Agent](/docs/features/ai-scraper/general) for single-page extraction or the [Listing Agent](/docs/features/ai-scraper/listing) for listing pages.
## How It Works
1. **Frequent requests are logged** — When users request certain URLs or domains (e.g., via the General Agent), those requests are logged.
2. **Intelligent agent creation** — When a domain is requested frequently enough, MrScraper intelligently creates code to scrape that domain, using **common fields** that users in that category typically request (e.g., product name, price, description; or hotel name, rating, reviews).
3. **Upload to Marketplace** — The new PDP Cache agent is uploaded to the [Marketplace](https://app.mrscraper.com/marketplace), where it becomes available for all users.
4. **Multiple data sources** — PDP Cache retrieves data not only from HTML but also from other available sources (e.g., APIs, structured data), which improves completeness and consistency.
5. **Category-based schemas** — Each PDP type (article, hotel, job posting, product, property, restaurant, tour) follows common fields. See the API reference for each:
* [Article](/docs/api/pdp/article)
* [Hotel](/docs/api/pdp/hotel)
* [Job Posting](/docs/api/pdp/job-posting)
* [Product](/docs/api/pdp/product)
* [Property](/docs/api/pdp/property)
* [Restaurant](/docs/api/pdp/restaurant)
* [Tour](/docs/api/pdp/tour)
## General Agent vs. PDP Cache Agent
| Aspect | General Agent | PDP Cache Agent |
| ---------------- | ------------------------------------- | ---------------------------------------------------------------------------------- |
| **Cost** | Higher (AI parsing per request) | Lower (no AI; dedicated scrapers + cache) |
| **Speed** | Slower (fetch + AI parse per request) | Faster (no AI; bypass steps by domain; cache lookup) |
| **Completeness** | Depends on current HTML | Often higher (multiple sources) |
| **Availability** | Any URL | Only supported domains in the [Marketplace](https://app.mrscraper.com/marketplace) |
| **Output** | Prompt-dependent | Common fields by category |
PDP Cache agents are only available for **commonly used websites** that have been added to the marketplace. For other domains, use the General Agent.
## Example Usage
Go to the [Marketplace](https://app.mrscraper.com/marketplace).
Browse or search for the **dataset** or **website** you want (e.g., product, article, hotel, restaurant).
Choose the PDP Cache agent that matches your target site and category.
Use it from your dashboard or via the API as you would other MrScraper agents.
For field-level details and example domains per category, see the [PDP API reference](/docs/api/pdp/article) (e.g., [Article](/docs/api/pdp/article), [Hotel](/docs/api/pdp/hotel), [Product](/docs/api/pdp/product), [Property](/docs/api/pdp/property), [Restaurant](/docs/api/pdp/restaurant), [Job Posting](/docs/api/pdp/job-posting), [Tour](/docs/api/pdp/tour)).
# Manual Scraper
import { Step, Steps } from 'fumadocs-ui/components/steps';
import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';
The **Manual Scraper** in MrScraper allows you to create custom scraping workflows by defining a series of steps to extract data from web pages.
This agent is ideal for users who need full control over the scraping process and want to handle complex scenarios.
## When to Use Manual Workflow
Use the Manual Scraper when you need to:
* Extract data from complex or dynamic websites that require specific interactions.
* Implement custom workflows that involve multiple steps, such as navigation, data extraction, and pagination.
* Handle situations where our markdown converter cleans or alters the HTML, causing the AI to fail when parsing it into JSON.
## Manual Scraper Features
### Step Types
Below are the available step types you can add when building a manual scraper:
| Step Type | Description |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Extract** | Scrape data from the webpage by setting an **Extraction Name**, choosing an **Extraction Type** (`Text`, `Inner HTML`, `Outer HTML`, or `Attribute`), and defining CSS selectors to target elements. |
| **Click** | Simulates a click action on a specified element. |
| **Delay** | Pauses the scraper for a set duration (in milliseconds) before moving to the next step. |
| **Wait for Selector** | Pauses until a specific element appears on the page, or until the timeout is reached. |
| **Input** | Enters text into input fields on the webpage. |
| **Scroll** | Scrolls to the end of the page, scrolls until a specific text is found, or scrolls to a specific element (or until a certain number of elements). |
| **Inject JavaScript** | Runs custom JavaScript code on the webpage. |
| **Listen Network** | Captures and extracts data from an endpoint. |
| **Follow URLs** | Collects links from the page and runs all subsequent steps on each followed URL. |
| **Paginate** | Automatically navigates through multiple pages. |
Use **Delay** when you simply need to pause for a fixed amount of time. Use **Wait for Selector** when you are waiting for content to load, it is faster and more reliable because it resumes as soon as the element is available.
### Pagination Types
| Pagination Type | Required Parameter |
| ------------------------ | --------------------------------- |
| **Query Pagination** | Query parameter (e.g., `?page=2`) |
| **Directory Pagination** | None (e.g., `/list/page/2`) |
| **Next Page Link** | Next page selector |
### Get Cookies
This feature allows you to capture cookies from the webpage, which can be useful for maintaining sessions or accessing data that requires authentication. You can enable this feature by toggling the **Get Cookies** option in the scraper settings. When enabled, the scraper will return a `cookies` field in the output, containing all cookies set during the scraping process.
```json title="Example output with cookies"
{
"books_data": [
{
"title": "A Light in the Attic",
"rating": "Three"
}
],
"cookies": []
}
```
### Self-Healing
Self-Healing allows you to automatically generate or repair Manual Scraper workflows using AI, both directly inside the dashboard builder and programmatically via the API:
* **Full Workflow Generation**: Automatically generate an entire multi-step workflow for a target URL or replace an existing workflow using the main **+ AI** button.
* **Single Step Repair / Generation**: Use the dedicated **+ AI** button on any step block to either **Extend Step** (broaden the step to cover additional URLs or layout variations) or **Replace Step** (overwrite the step configuration with a newly generated one).
* **Self-Heal API Access**: Access the repair endpoint (`POST /api/v1/scrapers-manual/{scraperId}/heal`) directly from your own applications or automated monitoring. Retrieve your endpoint, scraper ID, and API token from the **⋮ → Self-Heal API Access** menu in the scraper builder dashboard.
For complete setup guides and API examples, see [Self-Healing](/docs/features/manual-scraper/self-healing).
### JavaScript Templates
For custom DOM parsing, calling internal page APIs, or capturing JSON responses on infinite-scroll pages, you can use pre-built IIFE JavaScript snippets with the **Inject JavaScript** step:
* **Parse Page Data**: Extract data from dynamic DOM elements using `querySelectorAll`.
* **Fetch API Data**: Directly query internal page APIs using browser credentials and headers.
* **Scroll & Capture Fetch Responses**: Automatically scroll infinite-loading pages while intercepting matching API responses.
For ready-to-use scripts and setup steps, see [Templates](/docs/features/manual-scraper/templates).
## Usage Example
### Example 1 : Simple Website
Suppose you want to scrape data from this product page:
`https://www.target.com/p/beats-studio-pro-bluetooth-wireless-headphones/-/A-89459966`
On this site, the price is loaded dynamically through an internal API, so the AI Scraper won’t be able to extract it automatically. To capture this data, you’ll need to switch to the Manual Workflow and inject a small custom JavaScript snippet.
Follow the steps below:
Log in to **MrScraper**, then click **Scraper** in the left sidebar.
Click **New Manual Scraper +** at the top to create a new scraper.
Input the product URL above.
Add `Inject JavaScript` step.
Fill the **Name** field with `data`, and **Script timeout** with `50`.
Use this script:
```js title="Script"
(() => { return window.__TGT_DATA__.__PRELOADED_QUERIES__.queries})();
```
You can locate the price by inspecting the page’s source code.\
For this specific page, the price is available under the `__TGT_DATA__` object in the window.
**Note**: The data structure varies by website, so the location of price information may differ on other pages.
Save configuration > Run scraper.
The scraper returns the following output:
**Result :**
```json title="Manual workflow result"
{
"data": {
"...",
"product": {
"...",
"price": {
"formatted_comparison_price": "$349.99",
"formatted_comparison_price_type": "reg",
"formatted_current_price": "$165.99 - $169.99",
"formatted_current_price_type": "sale",
"location_id": 3991,
"current_retail_min": 165.99,
"reg_retail_max": 349.99
}
"...",
}
"...",
}
}
```
### Example 2 : Complex Website
Some websites cannot be scraped with the AI Scraper alone, especially when you need to fill in a form before data appears.
One example is:
`https://www.handelsregister.de/rp_web/normalesuche/welcome.xhtml`
Since the site requires entering search details before showing company information, you’ll need to use a Manual Workflow to automate the steps.
Follow the steps below:
Log in to **MrScraper**, then click **Scraper** in the left sidebar.
Click **New Manual Scraper +** at the top to create a new scraper.
Input the product URL above.
Add `Input` Step, fill **Input Field Selector** with `textarea[title="Company or keywords:"]` and **Text Input** for the company you want to search, for this example we'll use `Volkswagen & Audi Club`.
Add `Delay` Step with `1000` ms duration.
Add `Click` Step and select the `button[name="form:btnSuche"]` as the **Element to Click**.
Add another `Delay` Step with`10000` ms duration.
Add `Inject JavaScript` Step, Fill the **Name** field with `data`, and **Script timeout** with `900`, then use this script :
Need help writing a custom script for your manual workflow? [Contact Us](https://help.mrscraper.com/).
```js title="Script"
(async () => {
// Wait for correct URL with timeout
const targetUrl = "https://www.handelsregister.de/rp_web/sucheErgebnisse/welcome.xhtml?cid=1";
const maxAttempts = 15;
const checkInterval = 2000; // 2 seconds
let attempts = 0;
let urlMatches = false;
console.log('Waiting for correct URL...');
while (attempts < maxAttempts) {
if (window.location.href === targetUrl) {
urlMatches = true;
console.log('URL matched! Starting to parse...');
break;
}
attempts++;
console.log(`Attempt ${attempts}/${maxAttempts}: Current URL does not match. Waiting...`);
await new Promise(resolve => setTimeout(resolve, checkInterval));
}
if (!urlMatches) {
console.log('Timeout: URL never matched the target URL');
return null;
}
// Helper function to create unique key for an entry
function getEntryKey(entry) {
return `${entry.region}|${entry.court}|${entry.companyName}|${entry.location}`;
}
// Helper function to check if page has changed
function hasPageChanged(currentResults, lastPageKeys) {
if (currentResults.length === 0) return false;
const currentKeys = currentResults.map(getEntryKey);
// Check if at least one entry is different
return currentKeys.some(key => !lastPageKeys.has(key));
}
// Parsing functions
function parseCurrentPage() {
const table = document.getElementById('ergebnissForm:selectedSuchErgebnisFormTable_data');
if (!table) {
console.log('Table not found on page');
return [];
}
const rows = table.querySelectorAll('tr[data-ri]');
const results = [];
rows.forEach(row => {
const entry = {};
// Extract region and court info
const headerCell = row.querySelector('.fontTableNameSize');
if (headerCell) {
const headerText = headerCell.textContent.trim();
const parts = headerText.split(/\s{2,}/);
entry.region = parts[0]?.trim() || '';
entry.court = parts[1]?.trim() || '';
}
// Extract company name
const nameCell = row.querySelector('.marginLeft20');
if (nameCell) {
entry.companyName = nameCell.textContent.trim();
}
// Extract location (Sitz)
const locationCell = row.querySelector('.sitzSuchErgebnisse .verticalText');
if (locationCell) {
entry.location = locationCell.textContent.trim();
}
// Extract registration status
const statusCells = row.querySelectorAll('.verticalText');
if (statusCells.length > 1) {
entry.status = statusCells[1].textContent.trim();
}
// Extract document types (AD, CD, HD, etc.)
const docLinks = row.querySelectorAll('.dokumentList .underlinedText');
entry.documentTypes = Array.from(docLinks).map(link => link.textContent.trim());
// Extract history entries
const historyRows = row.querySelectorAll('.RegPortErg_HistorieZn');
if (historyRows.length > 0) {
entry.history = [];
historyRows.forEach(histRow => {
const histText = histRow.querySelector('.fontSize85')?.textContent.trim();
const histLocation = histRow.closest('tr')?.querySelector('.RegPortErg_SitzStatus .fontSize85')?.textContent.trim();
if (histText) {
entry.history.push({
name: histText,
location: histLocation || ''
});
}
});
}
results.push(entry);
});
return results;
}
function isNextButtonDisabled() {
const nextButton = document.querySelector('a.ui-paginator-next');
return nextButton && nextButton.classList.contains('ui-state-disabled');
}
const allResults = [];
const seenKeys = new Set();
let pageNumber = 1;
const delay = 1000;
const maxRetries = 3; // Max retries if page hasn't changed
console.log(`Parsing page ${pageNumber}...`);
// Parse first page
const firstPageResults = parseCurrentPage();
firstPageResults.forEach(entry => {
const key = getEntryKey(entry);
if (!seenKeys.has(key)) {
seenKeys.add(key);
allResults.push(entry);
}
});
console.log(`Page ${pageNumber}: Found ${firstPageResults.length} entries (${allResults.length} unique so far)`);
// Continue clicking next until button is disabled
while (!isNextButtonDisabled()) {
const nextButton = document.querySelector('a.ui-paginator-next');
if (!nextButton) {
console.log('Next button not found');
break;
}
// Store current page keys for comparison
const lastPageKeys = new Set(seenKeys);
// Click next button
nextButton.click();
pageNumber++;
// Wait for page to load and retry if needed
let retries = 0;
let pageChanged = false;
while (retries < maxRetries) {
await new Promise(resolve => setTimeout(resolve, delay));
const currentPageResults = parseCurrentPage();
pageChanged = hasPageChanged(currentPageResults, lastPageKeys);
if (pageChanged) {
console.log(`Parsing page ${pageNumber}...`);
// Add only unique entries
let newEntries = 0;
currentPageResults.forEach(entry => {
const key = getEntryKey(entry);
if (!seenKeys.has(key)) {
seenKeys.add(key);
allResults.push(entry);
newEntries++;
}
});
console.log(`Page ${pageNumber}: Found ${currentPageResults.length} entries (${newEntries} new, ${allResults.length} unique total)`);
break;
} else {
retries++;
if (retries < maxRetries) {
console.log(`Page ${pageNumber}: Data not updated yet, retrying (${retries}/${maxRetries})...`);
}
}
}
if (!pageChanged) {
console.log(`Page ${pageNumber}: Data still not updated after ${maxRetries} retries, skipping...`);
}
}
console.log(`\nCompleted! Total unique entries: ${allResults.length}`);
return allResults;
})()
```
Save configuration > Run the scraper.
The scraper returns the following output:
**Result :**
```json title="Manual workflow result"
{
"data": [
{
"region": "Bavaria",
"court": "District court München VR 201131",
"companyName": "1.Volkswagen & Audi Club Mittenwald e.V.",
"location": "Mittenwald",
"status": "currently registered",
"documentTypes": [
"AD",
"CD",
"DK",
"UT",
"VÖ",
"SI"
]
},
{
"region": "Baden-Württemberg",
"court": "District court Stuttgart VR 381348",
"companyName": "VW-Audi Club Härten e.V.",
"location": "Kusterdingen",
"status": "currently registered",
"documentTypes": [
"AD",
"CD",
"HD",
"DK",
"UT",
"VÖ",
"SI"
],
"history": [
{
"name": "1.) VW-Audi Club Härten",
"location": "1.) Kusterdingen"
}
]
}
]
}
```
## AI Assistant
The AI Assistant helps you build custom scraping workflows using natural language.
You do not need to know JavaScript to get started. Simply describe the data you want to extract, and the AI Assistant will generate the workflow for you.
To open the AI Assistant:
Open the **Manual Scraper**.
Click the dropdown next to the **AI** button.
Select **Create Workflow**.
The AI Assistant will generate the required workflow steps and JavaScript code based on your prompt. You can use the generated workflow as-is or modify it to fit your needs.
### Example
Suppose you want to extract book titles and ratings from the following website:
`https://books.toscrape.com/`
Enter the following prompt:
```text
Extract the book title and rating from the page.
```
The AI Assistant analyzes the page and generates a workflow automatically.
In this example, the generated workflow may:
1. Add a delay to ensure the page has fully loaded.
2. Add JavaScript injection.
The generated JavaScript injection might look similar to the following:
```js title="AI Generated Script"
(function() {
const books = [];
const articles = document.querySelectorAll('article.product_pod');
articles.forEach(article => {
const titleEl = article.querySelector('h3 a');
const title = titleEl?.getAttribute('title')?.trim() || null;
const ratingEl = article.querySelector('p.star-rating');
let rating = null;
if (ratingEl) {
const ratingClass = Array.from(ratingEl.classList).find(c => c !== 'star-rating');
rating = ratingClass || null;
}
books.push({
title: title,
rating: rating
});
});
return books;
})();
```
## Troubleshooting
The items below cover the most common Manual Scraper issues. Work through them in the order listed—most problems are resolved by the first two or three checks.
Dynamic pages may not finish rendering before the first extraction or JavaScript step runs.
1. Add or increase a **Delay** step before the extraction step. Start with `2000` ms and increase in `1000` ms increments until the target content is present.
2. If the page loads content only after a user action (for example, after clicking a tab or submitting a form), make sure the relevant **Click** or **Input** step comes before the **Delay**.
3. Run the scraper and enable **Screenshot** to confirm the page has rendered the content you need before extraction begins.
When an **Inject JavaScript** step returns `null`, `undefined`, or `[]`, the script is running but cannot find the expected data. Work through these checks in order:
1. **Test the script locally.** Open the target URL in your browser, paste the IIFE into the developer console, and confirm it returns the expected result.
2. **Check for overlays.** Open the URL in an incognito window. A modal, cookie banner, sign-up prompt, or GDPR overlay may be covering the page. If so, add a **Click** step before the script to dismiss the overlay.
3. **Verify timing.** The data you need may load after the script runs. Add or increase a **Delay** step before the **Inject JavaScript** step.
4. **Enable a proxy.** Some sites serve different content based on IP origin. Enable a proxy, select the country where the website is located, and turn on **Route entire request through proxy** to route all page resources through the same proxy.
5. **Try Super mode.** If the website still blocks the workflow, open the **Playground**, turn on **Super** mode, and add your Manual Scraper steps as Playground automation steps. Super mode uses a real browser environment that is harder for anti-bot systems to detect.
The **Extract** step uses CSS selectors to target page elements. If it returns empty results:
1. Open the target URL in your browser and run `document.querySelectorAll("your-selector")` in the developer console to verify the selector matches the elements you expect.
2. If the selector works in the console but not in MrScraper, the content may be loaded dynamically. Add a **Delay** step before the **Extract** step or switch to an **Inject JavaScript** step that waits for the element.
3. Check that the **Extraction Type** matches the data you need: use **Text** for visible text, **Attribute** for values like `href` or `src`, and **Inner HTML** or **Outer HTML** for raw markup.
If the **Get Cookies** option is enabled but the `cookies` field is empty:
1. Confirm that the website sets cookies during the scraping session. Not all websites set cookies on every page load.
2. Make sure the workflow includes at least one step that triggers cookie creation—for example, clicking an "Accept cookies" button or submitting a login form.
3. Check that the **Get Cookies** toggle is enabled in the scraper settings before running the workflow.
Selectors that worked before can break when a site redesigns its markup. Instead of rebuilding the workflow by hand, use [Self-Healing](/docs/features/manual-scraper/self-healing) to regenerate the whole workflow or repair a single step with AI, either from the dashboard or through the Self-Heal API.
# Self-Healing
import { Step, Steps } from 'fumadocs-ui/components/steps';
Websites change their markup all the time. When a selector breaks, a Manual Scraper keeps running but returns empty or partial data. **Self-Healing** uses AI to automatically generate, repair, and extend Manual Scraper workflows so you don't have to write or update selectors manually.
You can use Self-Healing in two ways:
* **UI Platform**: Generate a full workflow or generate/repair single steps directly inside the scraper builder using the AI buttons.
* **Self-Heal API Access**: Trigger automated workflow repairs programmatically using the API endpoint.
Self-Healing is also useful for a scraper you haven't built yet. Point it at a URL and let the AI generate the full workflow automatically, then fine-tune the steps yourself.
## When to Use Self-Healing
* **Website Redesign**: The scraper suddenly returns empty fields because the target website changed its markup.
* **Automated Workflow Creation**: You want to automatically generate a starting workflow for a new URL instead of writing every step manually.
* **Single Step Repair**: One specific step is broken while the rest of the workflow still functions properly.
* **Multi-URL Coverage**: You want a step or workflow to cover additional URLs or page layouts on the same website.
## Generate a Full Workflow
You can generate an entire multi-step workflow automatically using the main AI button at the top of the scraper builder:
Open a manual scraper or create a new one.
Click the **+ AI** button at the top right of the builder. Select **Create Workflow** if you are creating a new scraper, or **Replace All** to replace an existing workflow.
Enter your prompt (or let the AI inspect the page) and wait for the AI to generate the workflow steps.
Review the generated steps, fine-tune any selectors or code, then click **Save**.
Generating a full workflow overwrites the steps currently shown in the builder. Run the scraper and check the output before saving over a workflow you still rely on.
## Generate or Repair a Single Step
Instead of rebuilding the entire workflow, you can generate or repair an individual step. Every step block in the workflow builder has its own dedicated **+ AI** button in its top-right corner.
Clicking the **+ AI** button on an individual step reveals two options:
| Option | What it does | Use it when |
| ---------------- | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| **Extend Step** | Keeps the existing step configuration and extends it so the workflow can cover additional URLs or page layouts. | The step works on some pages but fails on others, and you want one step/workflow to cover multiple page variants. |
| **Replace Step** | Discards the current step configuration and generates a new one for the target page URL. | The step is broken or outdated, and you want to replace its configuration with a newly generated workflow step. |
Locate the step you want to modify in the builder, then click its **+ AI** button.
Select either **Extend Step** or **Replace Step** based on your objective.
Wait for the AI to inspect the page and generate the updated step configuration.
Review the generated selectors or JavaScript code, then click **Save** to persist the workflow.
* **Extend Step** is additive: it broadens the step so the workflow can cover additional URLs and layout variants.
* **Replace Step** replaces the existing step configuration with a brand new workflow step for the current URL.
## Self-Heal API Access
Besides using Self-Healing in the UI platform, MrScraper also provides the **Self-Heal API**. This allows you to trigger automated workflow repairs programmatically from a monitoring script, a scheduled task, or your own application whenever a scraper detects empty or invalid results.
### Accessing Self-Heal API in the Dashboard
You can retrieve the API endpoint, your scraper ID, and your API token directly from the scraper dashboard:
Open your manual scraper in the builder dashboard.
Click the **⋮** (more options) menu icon at the top right of the page.
Select **Self-Heal API Access** from the menu.
In the popup modal, enter or copy your API token (or click **Generate** to create a new one). The modal provides a ready-made cURL example pre-configured with your `scraperId` and token.
See [Authentication](/docs/api/authentication) for more details on managing API tokens.
### Request
```bash title="Self-heal a manual scraper"
curl --request POST "https://api.app.mrscraper.com/api/v1/scrapers-manual/{scraperId}/heal" \
--header "accept: application/json" \
--header "x-api-token: YOUR_API_TOKEN"
```
| Parameter | Type | Location | Required | Description |
| ------------- | ------ | -------- | -------- | ---------------------------------------------------------------------------------------------- |
| `x-api-token` | string | header | Yes | Your MrScraper API token |
| `scraperId` | string | path | Yes | The ID of the manual scraper you want to repair (found in the scraper URL or API Access modal) |
See [Self-Heal a Manual Scraper](/docs/api/v3/scraper/manual-heal) in the API reference for the complete OpenAPI schema and error handling details.
### Response
```json title="Successful response"
{
"message": "Successful operation!",
"data": {
"success": true,
"scraperId": "",
"workflowUpdated": true
}
}
```
The endpoint asks the AI engine to repair the current workflow. The scraper's saved workflow is updated **only** when a valid workflow response is returned. If the repair attempt fails, your existing workflow configuration remains unchanged.
# Super Mode
import { Step, Steps } from 'fumadocs-ui/components/steps';
## Why Use Super Mode?
Some websites enforce strong anti-bot protection. By default, Manual Scraper accesses pages through our cloud infrastructure, which these protections may block. Super mode routes your request through a real device instead, significantly improving the chance of bypassing such protection.
## How to Use Super Mode
Super mode is not a toggle inside the scraper builder. To run a Manual Scraper workflow in Super mode, follow these steps :
Open the manual scraper you want to run in Super mode.
Click the **Ellipsis** ( **⋮** ) button in the top right and click **Manual Scraper API Access**.
In the cURL example shown in the modal, copy the `workflow` array.
Paste the workflow into the `workflow` field of the request below, then fill in your API token, target URL, and the country you want to access the URL from.
### Request
```bash title="Run a manual scraper workflow in Super mode"
curl --location 'https://api.mrscraper.com?token={MRSCRAPER_API_TOKEN}&geoCode=us&html=true&super=true&proxyCountry=us' \
--header 'x-api-token: {MRSCRAPER_API_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"url": "{YOUR_TARGET_URL}",
"homePage": true,
"proxyCountry" : "us",
"workflow": [
]
}'
```
| Parameter | Location | Description |
| ----------------------- | -------------- | --------------------------------------------------------------------------------------------- |
| `super` | query | Set to `true` to route the request through a real device instead of our cloud infrastructure. |
| `token` / `x-api-token` | query / header | Your MrScraper API token. |
| `geoCode` | query | ISO 3166-1 alpha-2 country code used for proxy routing. |
| `html` | query | Set to `true` to include the raw page HTML in the response. |
| `proxyCountry` | query / body | Country you want to access the target URL from. |
| `url` | body | The target URL to scrape. |
| `homePage` | body | Set to `true` to visit the website's home page first, then navigate to the target URL. |
| `workflow` | body | The workflow steps copied from the **Manual Scraper API Access** modal. |
### Visiting the Home Page First
Some websites block requests that land directly on a deep URL. eBay, for example, expects visitors to arrive from the home page. Setting `homePage` to `true` makes the request load the home page first and then navigate to your target URL, which mimics normal browsing behavior.
| Trade-off | Detail |
| --------- | ------------------------------------------------------------------------------ |
| **Pros** | More reliable and robust against blocks on sites that check how you arrived. |
| **Cons** | Higher bandwidth usage and higher latency, since each run loads an extra page. |
Leave `homePage` off by default. Enable it when a target URL is blocked or returns empty data on its own, and you are willing to trade extra bandwidth and run time for a higher success rate.
See [Authentication](/docs/api/authentication) for more details on managing API tokens.
### Response
```json title="Example response"
{
"code": null,
"screenshots": [],
"recording_path": null,
"extractions": "{\"Product Link\": [{\"follow_url\": \"https://books.toscrape.com//catalogue/a-light-in-the-attic_1000/index.html\", \"result\": {\"product_name\": \"\\n \\n In stock (22 available)\\n \\n\"}}]}",
"data": {
"Product Link": [
{
"follow_url": "https://books.toscrape.com//catalogue/a-light-in-the-attic_1000/index.html",
"result": {
"product_name": "\n \n In stock (22 available)\n \n"
}
}
]
},
"data_path": "results/b09aab93-717c-4804-9d37-a37084be4627/data.json",
"html_path": "results/b09aab93-717c-4804-9d37-a37084be4627/page.html",
"error": null,
"residential_proxy_usage": {
"received": 0.157379150390625,
"sent": 0.0006866455078125,
"total": 0.1580657958984375
},
"runtime": 13.358241081237793,
"token_usage": 2,
"listen_network_data": {},
"html": " ... full page HTML truncated ... ",
"markdown": "",
"screenshot": "",
"retry_count": 0
}
```
You can also review the run and its output on the [Results page](https://app.mrscraper.com/scrapers-results) in the app.
# Templates
import { Step, Steps } from 'fumadocs-ui/components/steps';
The Manual Scraper combines low-code workflow steps with custom JavaScript. Use low-code steps to click elements, scroll the page, follow URLs, listen to network requests, add delays, and extract text with CSS selectors.
For more advanced workflows, the **Inject JavaScript** step runs browser-side code—the same code you would run in the developer console—to extract data with selectors, call page APIs, or intercept network responses.
## Prerequisites
Before using these templates:
* Replace all placeholder selectors and API endpoints with values from your target website.
* Each script is an [Immediately Invoked Function Expression (IIFE)](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) and must return JSON-serializable data.
* Test your selectors and scripts in the browser developer console before adding them to a workflow.
## Parse Page Data
Use this template when the data you need is already rendered in the page HTML.
### Setup Steps
Open the target URL in a Manual Scraper.
If the content loads dynamically, add a **Delay** step before extraction.
Add an **Inject JavaScript** step.
Set an **Extraction Name** (for example, `products`).
Paste the script below into the script box and replace the example selectors with selectors from your target page.
```js title="Parse page data with querySelectorAll"
(() => {
const products = Array.from(
document.querySelectorAll(".product-card")
).map((product) => ({
title:
product.querySelector(".product-title")?.textContent?.trim() || null,
price:
product.querySelector(".product-price")?.textContent?.trim() || null,
url: product.querySelector("a")?.href || null,
}));
return products;
})();
```
Test your selectors in the browser console first. Run `document.querySelectorAll(".product-card").length` and confirm it returns the expected number of elements before adding the script to your workflow.
## Fetch API Data
Use this template when the page loads its data from an API endpoint. You can identify the endpoint with the browser's **Network → Fetch/XHR** panel or a Manual Scraper **Listen Network** step.
### Setup Steps
Open the target URL in a Manual Scraper.
Add an **Inject JavaScript** step.
Set an **Extraction Name** (for example, `apiData`).
Replace `/api/products` with the endpoint used by the target page.
```js title="Fetch data from a page API"
(async () => {
const apiUrl = new URL("/api/products", window.location.origin);
const response = await fetch(apiUrl, {
method: "GET",
credentials: "include",
headers: {
Accept: "application/json",
},
});
if (!response.ok) {
throw new Error(`API request failed with status ${response.status}`);
}
const data = await response.json();
return data;
})();
```
This template works best for same-origin APIs that use the page's existing cookies. Some endpoints also require request headers, query parameters, or tokens copied from the website's own request.
## Scroll and Capture Fetch Responses
Use this template on infinite-scroll pages that load additional data through the browser Fetch API. The script intercepts matching JSON responses while scrolling, then returns all collected data once scrolling completes.
### Setup Steps
Open the listing page in a Manual Scraper.
Add an **Inject JavaScript** step.
Set a **Script timeout** long enough for the scrolling loop to finish (for example, `30000` ms for a page with many scroll loads).
Replace `/api/products` with a unique part of the endpoint you want to capture.
```js title="Scroll and capture Fetch API responses"
(async () => {
const endpointPattern = "/api/products";
const capturedResponses = [];
const pendingCaptures = [];
const originalFetch = window.fetch;
const wait = (milliseconds) =>
new Promise((resolve) => setTimeout(resolve, milliseconds));
const patchedFetch = async (...args) => {
const response = await originalFetch.apply(window, args);
const requestUrl =
typeof args[0] === "string" ? args[0] : args[0]?.url || "";
if (requestUrl.includes(endpointPattern)) {
const capture = response
.clone()
.json()
.then((data) => {
capturedResponses.push({
url: requestUrl,
data,
});
})
.catch(() => {
// Ignore matching responses that are not JSON.
});
pendingCaptures.push(capture);
}
return response;
};
window.fetch = patchedFetch;
try {
let previousHeight = document.body.scrollHeight;
let stableRounds = 0;
for (let attempt = 0; attempt < 20; attempt += 1) {
window.scrollTo(0, document.body.scrollHeight);
await wait(1500);
const currentHeight = document.body.scrollHeight;
stableRounds =
currentHeight === previousHeight ? stableRounds + 1 : 0;
previousHeight = currentHeight;
if (stableRounds >= 2) {
break;
}
}
await wait(1000);
await Promise.allSettled(pendingCaptures);
return capturedResponses;
} finally {
if (window.fetch === patchedFetch) {
window.fetch = originalFetch;
}
}
})();
```
This template captures requests made with `window.fetch` after the script starts. It does not capture `XMLHttpRequest`, requests made before injection, or non-JSON responses. Use the **Listen Network** step when you need broader network capture.
## Run the Workflow
After adding a template to your workflow:
Replace all placeholder selectors, endpoints, and timeouts with values from the target website.
Click **Save**.
Run the scraper and inspect the returned field that matches the extraction name you set.
If the result is empty or the website blocks the request, see [Troubleshooting](/docs/features/manual-scraper#troubleshooting) on the Manual Scraper page.
# Get Screenshot
## Overview
Selecting **Get Screenshot** in the Playground Use Case panel pre-configures the Playground environment specifically for visual page capture. When this preset is active, the Playground enables real browser rendering (`browserRendering=true`) by default so you can visually verify how dynamic web pages, client-side scripts, and layout elements render.
You can toggle between capturing the visible viewport (`top`) or rendering the full scrollable page (`full`).
### Practical Applications
* **Visual QA & Deployment Audits**: Verify visual layout integrity across dynamic responsive viewports after deployments or design updates.
* **Compliance & Legal Archiving**: Maintain time-stamped visual proof of pricing, terms of service, disclosures, or ad placements.
* **Competitor UI & Campaign Tracking**: Monitor visual changes on competitor landing pages, promotional banners, and checkout flows over time.
* **Scraper & Extraction Debugging**: Inspect the exact page state when data extraction fails—instantly spot CAPTCHAs, cookie banners, bot blocks, or unexpected layouts.
* **Automated Previews & Dashboards**: Generate real-time page thumbnails and visual previews for internal dashboards, link previews, or reports.
## Default Parameters
| Parameter | Description |
| --------------------- | ---------------------------------------------------- |
| html=true | Used by this endpoint to return html in the response |
| browserRendering=true | In this use case, `Render JavaScript` default to On |
| waitUntil | Default to `DOM Content Loaded` |
| timeout | Default to `300` |
## Example
### Request
Scrape `https://www.walmart.com/search?q=table%20lamps` with `Record` toggled on, `Render JavaScript` toggled on, and `Screenshot area` set to `Full`
```sh title="Request"
curl --location --request POST 'https://api.mrscraper.com?token={MRSCRAPER_API_TOKEN}&browserRendering=true&waitUntil=networkidle0&timeout=300&geoCode=us&html=true&screenshot=full&record=true&saveResult=true&proxyCountry=us' \
-H 'x-api-token: {MRSCRAPER_API_TOKEN}' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://www.walmart.com/search?q=table%20lamps"
}'
```
### Response
Images :
Recording :
# Playground
import { Play, Code2, FileJson, Wand2 } from 'lucide-react';
import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';
The [**Playground**](https://app.mrscraper.com/playground) lets you build, test, and validate scraping requests without writing any code. It provides an interactive interface for configuring requests, previewing results, and generating production-ready API code.
## What You Can Do
}>
Send API requests and view results instantly.
}>
Experiment with extraction settings and options.
}>
Generate ready-to-use code snippets in multiple languages.
}>
Inspect the returned data before building your integration.
## Playground Overview
The Playground has these main panels:
* **Target URL**: Configure and run the request.
* **Example Code**: Copy generated request code.
* **Extracted Data**: View the response.
* **Settings**: Adjust optional loading, rendering, and extraction options (Basic Settings, Advanced Settings, and Automation).
* **Alert Settings**: Get notified when a scrape returns errors or incomplete data.
## Target URL
In the **Target URL** panel, you configure and run the request:
* Enter the target URL.
* Select **Run** to send the request, or **Reset** to clear the current configuration.
* Select a country to load the page from. (Default to `United States`)
## Example Code
The **Example Code** panel builds an API request from your current configuration and updates it automatically as you make changes. Copy the code and use it directly in your application.
Supported languages:
* cURL
* Python
* JavaScript
* PHP
* Go
* Java
* Ruby
* C#
You can view the ready-made prompt for your AI coding agent to integrate MrScraper.
## Extracted Data
The **Extracted Data** panel displays the response MrScraper returns after a request completes :
* HTTP status code
* Total runtime
* Token used
Depending on the use case, the response may include:
* Raw HTML
* Markdown
* JSON
Use this panel to confirm the extracted content matches your requirements before you integrate the request into your application.
This panel can also show history of your previous requests and analytic of your requests.
## Default Parameters
| Parameter | Description |
| --------------- | ----------------------------------------------------------- |
| saveResult=true | Used to save the result to Result tab. |
| geoCode | country to load the page from. (Default to `United States`) |
| proxyCountry | country to load the page from. (Default to `United States`) |
## Settings
The settings panels contain optional features that control how MrScraper loads, renders, and extracts content. Most websites work with the default settings. Enable these options only when a website needs extra handling, such as JavaScript rendering, geographic targeting, or user interactions.
These settings are optional. In most cases, the default configuration is enough. The available settings vary depending on the selected use case.
### Basic Settings
| Setting | Description | Common Use Case | Default |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------- | -------------------- |
| **Super** | Uses additional resources to improve extraction accuracy on complex websites. | Websites protected by anti-bot systems or containing heavily dynamic content. | `Off` |
| **Retry** | Enable retry-related settings for the request. | Unreliable pages or requests that fail intermittently. | `Off` |
| **Max retries** | Maximum number of retries for the request. Leave empty for no limit. | Limiting how many times a scrape retries. | `3` |
| **Token cap** | Maximum total tokens the scrape and its retries can use. | Controlling token usage during testing. See [Token Cap](#token-cap). | `No Limit` |
| **Render JavaScript** | Render the page using a real Chromium browser. | Required for JavaScript-heavy sites, SPAs, and pages that load content dynamically. | `Off` |
| **Wait Until** | Defines when the browser considers navigation complete. 'Network Idle 0' waits until all network activity stops. Most thorough but slowest | Content that loads asynchronously after the initial page load. | `Dom Content Loaded` |
| **Timeout (s)** | Maximum seconds to wait for the page to fully load before the request times out. Increase for slow or complex pages | Website that load slowly. | `300` |
| **Record** | Captures a full-page recording of the rendered page | Get a video to confirm the web load correctly | `Off` |
| **Screenshot area** | `Top` or `Full`. Top captures the visible viewport at the top of the page. Full captures the entire scroll height. | Get the website view | `Full` |
#### Token Cap
The Token Cap limits how many tokens a single scrape and its retries can use in the Playground. It applies to Unblocker and Manual Scraper only.
Use the token cap to keep your costs predictable. Automatic retries are bounded by the cap, so the total tokens for a single run stay at or below the value you set. This makes it easier to estimate and budget token usage while testing.
For how the cap works with retries and how tokens are counted, see [Playground Token Cap](/docs/getting-started/api-token#playground-token-cap) in Token Plan.
### Advanced Settings
Advanced Setting are vary based on [Use Cases](#use-cases), check each pages for more details
## Alert Settings
The **Alert Settings** panel notifies you when a scrape returns errors or incomplete data. Configure where alerts go, what triggers them, and how often they're sent.
### Channel
Choose where MrScraper sends alerts. Set one or both.
| Field | Description |
| --------------------- | -------------------------------------------------------------- |
| **Email** | Sends alerts to this email address. |
| **Slack Webhook URL** | Sends alerts to a Slack channel using an incoming webhook URL. |
### Flag
Set the conditions that trigger an alert. Type a value and press **Enter** to add it.
| Field | Description | Examples |
| ------------------------- | ------------------------------------------------------------------------- | ----------------------------------- |
| **Error Flags** | Triggers an alert when the response contains one of these errors. | `captcha`, `security`, `404`, `500` |
| **Data Incomplete Flags** | Triggers an alert when the extracted data is missing one of these fields. | `title`, `price`, `url` |
### Notification Rate
The **Identifier** sets the key MrScraper uses to group alerts, so the same alert isn't sent repeatedly. **Rate Limit** and **TTL** apply separately to each group.
| Field | Description |
| ----------------- | ---------------------------------------------------------------------------------------------- |
| **Identifier** | The key used to group alerts: **Domain** or **URL**. Each group is rate-limited on its own. |
| **Rate Limit** | Maximum number of alerts sent per group within the TTL period. |
| **TTL (seconds)** | Time to Live — the length of the rate-limit period, in seconds (for example, `3600` = 1 hour). |
#### Example
With a rate limit of 3 and errors on `example.com` and `shopee.com`:
* **Domain**: Grouped by domain. Once `example.com` hits the limit, its alerts pause for the TTL period, while `shopee.com` keeps its own separate count.
* **URL**: Grouped by full URL. `example.com/path1` and `example.com/path2` are tracked separately, so each can send its own alert.
## Use Cases
Fetch complete DOM markup with automatic proxy rotation, geo-targeting, and anti-bot bypass.
Convert web pages into clean, LLM-friendly Markdown by stripping HTML noise and boilerplate.
Capture full-page or viewport screenshots of dynamic, JavaScript-rendered web pages.
Extract structured, strongly-typed JSON data from single pages using natural language prompts or JSON schemas.
Extract paginated item lists, catalog grids, and search results across multiple pages in a single execution.
Crawl target sites to map URL architecture, discover endpoints, and generate seed URL lists.
## Troubleshooting
If a scrape returns unexpected results, start by enabling **Screenshot** in the Target URL panel and inspecting the returned image. You can also copy the raw HTML and open it in an HTML viewer to see what MrScraper received. The accordion items below walk through the most common issues in the order you should check them.
The website likely relies on client-side JavaScript to render its content.
1. Go to **Basic Settings** and turn on **Render JavaScript**.
2. Run the request again and check the screenshot or HTML.
Most single-page applications (React, Vue, Angular) require this setting.
Websites with anti-bot protection may block standard requests. Work through these steps in order:
1. Go to **Basic Settings** and turn on **Super** mode. This uses a real browser environment that is harder for anti-bot systems to detect.
2. If the request is still blocked, select the country where the website's primary audience is located. Many sites serve different content or apply stricter protections depending on the request's origin.
3. Run the request again after each change to isolate which setting resolves the block.
# Listing Page
## Overview
Selecting **Listing Page** in the Playground Use Case panel configures an AI-based scraper optimized for multi-page catalog and search result extraction. Powered by MrScraper's **`listing`** AI agent (`agent: "listing"`), it combines AI data parsing with automated browser navigation to crawl numbered pagination, infinite scrolling, and "Load More" buttons.
While single-page scrapers process one URL at a time, the `listing` agent sweeps across multi-page catalog grids or search results, using your prompt or JSON schema to extract repeating item arrays across all requested pages into a consolidated JSON array.
### Practical Applications
* **E-Commerce Catalog Extraction**: Sweep multi-page category listings to capture product titles, pricing, ratings, and availability status.
* **Marketplace & Job Board Scraping**: Collect job postings, real estate listings, or marketplace inventory across multi-page results.
* **Search Result Scraping**: Retrieve complete search result sets across pagination instead of capping extraction at page one.
* **Bulk Inventory & Price Monitoring**: Track entire category lines or brand assortments on a scheduled basis.
* **Seed Generation for Detail Scrapes**: Extract item URLs from catalog pages to populate downstream target lists for deep [Scrape JSON](/docs/getting-started/playground/scrape-json) processing.
## Advanced settings
| Setting | Description | Default |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------- |
| **Listing (Max pages)** | This feature handles pagination, load more or infinite scroll in listing pages. For load more and infinite scroll, one page is calculated as one time data loaded. | `3` |
| **Data type** | Select a predefined data schema to auto-fill the `JSON Schema`. | `General` |
| **Prompt** | Describe the data shape you want back (e.g. fields like title, price, rating). This prompt only parses the scraped content. It cannot instruct the scraper itself. | `Extract all entry data as complete as possible.` |
| **JSON Schema** | Build a JSON schema to shape the extraction output. It is appended to the prompt as a 'Json Schema:' section when the request is sent. | None |
## Default Parameters
| Parameter | Description |
| ---------- | -------------------------------------- |
| super=true | In this use case, `super` must be `On` |
## Default Request Body
| Parameter | Description | Default |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- |
| maxPages | This feature handles pagination, load more or infinite scroll in listing pages. For load more and infinite scroll, one page is calculated as one time data loaded. | `3` |
## Example
### Request
Scrape `https://books.toscrape.com/` with default setting
```sh title="Request"
curl --location --request POST 'https://api.mrscraper.com?token={MRSCRAPER_API_TOKEN}&geoCode=us&super=true&proxyCountry=us' \
-H 'x-api-token: {MRSCRAPER_API_TOKEN}' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://books.toscrape.com",
"prompt": "Extract all entry data as complete as possible.",
"agent": "listing",
"maxPages": 3
}'
```
### Response
```json title="Response"
{
"0": {
"page_num": 1,
"data": {
"mode": "direct",
"data": [
{
"title": "A Light in the Attic",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/a-light-in-the-attic_1000/index.html",
"price": "£51.77",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/2c/da/2cdad67c44b002e7ead0cc35693c0e8b.jpg"
]
},
{
"title": "Tipping the Velvet",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/tipping-the-velvet_999/index.html",
"price": "£53.74",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/26/0c/260c6ae16bce31c8f8c95daddd9f4a1c.jpg"
]
},
{
"title": "Soumission",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/soumission_998/index.html",
"price": "£50.10",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/3e/ef/3eef99c9d9adef34639f510662022830.jpg"
]
},
{
"title": "Sharp Objects",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/sharp-objects_997/index.html",
"price": "£47.82",
"availability": "In stock",
"rating": "Four",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/32/51/3251cf3a3412f53f339e42cac2134093.jpg"
]
},
{
"title": "Sapiens: A Brief History of Humankind",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/sapiens-a-brief-history-of-humankind_996/index.html",
"price": "£54.23",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/be/a5/bea5697f2534a2f86a3ef27b5a8c12a6.jpg"
]
},
{
"title": "The Requiem Red",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-requiem-red_995/index.html",
"price": "£22.65",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/68/33/68339b4c9bc034267e1da611ab3b34f8.jpg"
]
},
{
"title": "The Dirty Little Secrets of Getting Your Dream Job",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-dirty-little-secrets-of-getting-your-dream-job_994/index.html",
"price": "£33.34",
"availability": "In stock",
"rating": "Four",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/92/27/92274a95b7c251fea59a2b8a78275ab4.jpg"
]
},
{
"title": "The Coming Woman: A Novel Based on the Life of the Infamous Feminist, Victoria Woodhull",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-coming-woman-a-novel-based-on-the-life-of-the-infamous-feminist-victoria-woodhull_993/index.html",
"price": "£17.93",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/3d/54/3d54940e57e662c4dd1f3ff00c78cc64.jpg"
]
},
{
"title": "The Boys in the Boat: Nine Americans and Their Epic Quest for Gold at the 1936 Berlin Olympics",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-boys-in-the-boat-nine-americans-and-their-epic-quest-for-gold-at-the-1936-berlin-olympics_992/index.html",
"price": "£22.60",
"availability": "In stock",
"rating": "Four",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/66/88/66883b91f6804b2323c8369331cb7dd1.jpg"
]
},
{
"title": "The Black Maria",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-black-maria_991/index.html",
"price": "£52.15",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/58/46/5846057e28022268153beff6d352b06c.jpg"
]
},
{
"title": "Starving Hearts (Triangular Trade Trilogy, #1)",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/starving-hearts-triangular-trade-trilogy-1_990/index.html",
"price": "£13.99",
"availability": "In stock",
"rating": "Two",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/be/f4/bef44da28c98f905a3ebec0b87be8530.jpg"
]
},
{
"title": "Shakespeare's Sonnets",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/shakespeares-sonnets_989/index.html",
"price": "£20.66",
"availability": "In stock",
"rating": "Four",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/10/48/1048f63d3b5061cd2f424d20b3f9b666.jpg"
]
},
{
"title": "Set Me Free",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/set-me-free_988/index.html",
"price": "£17.46",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/5b/88/5b88c52633f53cacf162c15f4f823153.jpg"
]
},
{
"title": "Scott Pilgrim's Precious Little Life (Scott Pilgrim #1)",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/scott-pilgrims-precious-little-life-scott-pilgrim-1_987/index.html",
"price": "£52.29",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/94/b1/94b1b8b244bce9677c2f29ccc890d4d2.jpg"
]
},
{
"title": "Rip it Up and Start Again",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/rip-it-up-and-start-again_986/index.html",
"price": "£35.02",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/81/c4/81c4a973364e17d01f217e1188253d5e.jpg"
]
},
{
"title": "Our Band Could Be Your Life: Scenes from the American Indie Underground, 1981-1991",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/our-band-could-be-your-life-scenes-from-the-american-indie-underground-1981-1991_985/index.html",
"price": "£57.25",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/54/60/54607fe8945897cdcced0044103b10b6.jpg"
]
},
{
"title": "Olio",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/olio_984/index.html",
"price": "£23.88",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/55/33/553310a7162dfbc2c6d19a84da0df9e1.jpg"
]
},
{
"title": "Mesaerion: The Best Science Fiction Stories 1800-1849",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/mesaerion-the-best-science-fiction-stories-1800-1849_983/index.html",
"price": "£37.59",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/09/a3/09a3aef48557576e1a85ba7efea8ecb7.jpg"
]
},
{
"title": "Libertarianism for Beginners",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/libertarianism-for-beginners_982/index.html",
"price": "£51.33",
"availability": "In stock",
"rating": "Two",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/0b/bc/0bbcd0a6f4bcd81ccb1049a52736406e.jpg"
]
},
{
"title": "It's Only the Himalayas",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/its-only-the-himalayas_981/index.html",
"price": "£45.17",
"availability": "In stock",
"rating": "Two",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/27/a5/27a53d0bb95bdd88288eaf66c9230d7e.jpg"
]
}
],
"page": "Page 1 of 50",
"next_url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/page-2.html",
"total_results": 1000,
"showing_from": 1,
"showing_to": 20,
"__counts__": {
"data": 20
}
},
"total_items": 20,
"next_found": true
},
"1": {
"page_num": 2,
"data": {
"mode": "direct",
"data": [
{
"title": "In Her Wake",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/in-her-wake_980/index.html",
"price": "£12.84",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/5d/72/5d72709c6a7a9584a4d1cf07648bfce1.jpg"
]
},
{
"title": "How Music Works",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/how-music-works_979/index.html",
"price": "£37.32",
"availability": "In stock",
"rating": "Two",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/5c/c8/5cc8e107246cb478960d4f0aba1e1c8e.jpg"
]
},
{
"title": "Foolproof Preserving: A Guide to Small Batch Jams, Jellies, Pickles, Condiments, and More: A Foolproof Guide to Making Small Batch Jams, Jellies, Pickles, Condiments, and More",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/foolproof-preserving-a-guide-to-small-batch-jams-jellies-pickles-condiments-and-more-a-foolproof-guide-to-making-small-batch-jams-jellies-pickles-condiments-and-more_978/index.html",
"price": "£30.52",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/9f/59/9f59f01fa916a7bb8f0b28a4012179a4.jpg"
]
},
{
"title": "Chase Me (Paris Nights #2)",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/chase-me-paris-nights-2_977/index.html",
"price": "£25.27",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/9c/2e/9c2e0eb8866b8e3f3b768994fd3d1c1a.jpg"
]
},
{
"title": "Black Dust",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/black-dust_976/index.html",
"price": "£34.53",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/44/cc/44ccc99c8f82c33d4f9d2afa4ef25787.jpg"
]
},
{
"title": "Birdsong: A Story in Pictures",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/birdsong-a-story-in-pictures_975/index.html",
"price": "£54.64",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/af/6e/af6e796160fe63e0cf19d44395c7ddf2.jpg"
]
},
{
"title": "America's Cradle of Quarterbacks: Western Pennsylvania's Football Factory from Johnny Unitas to Joe Montana",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/americas-cradle-of-quarterbacks-western-pennsylvanias-football-factory-from-johnny-unitas-to-joe-montana_974/index.html",
"price": "£22.50",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/ef/0b/ef0bed08de4e083dba5e20fdb98d9c36.jpg"
]
},
{
"title": "Aladdin and His Wonderful Lamp",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/aladdin-and-his-wonderful-lamp_973/index.html",
"price": "£53.13",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/d6/da/d6da0371958068bbaf39ea9c174275cd.jpg"
]
},
{
"title": "Worlds Elsewhere: Journeys Around Shakespeare’s Globe",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/worlds-elsewhere-journeys-around-shakespeares-globe_972/index.html",
"price": "£40.30",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/2e/98/2e98c332bf8563b584784971541c4445.jpg"
]
},
{
"title": "Wall and Piece",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/wall-and-piece_971/index.html",
"price": "£44.18",
"availability": "In stock",
"rating": "Four",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/a5/41/a5416b9646aaa7287baa287ec2590270.jpg"
]
},
{
"title": "The Four Agreements: A Practical Guide to Personal Freedom",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-four-agreements-a-practical-guide-to-personal-freedom_970/index.html",
"price": "£17.66",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/0f/7e/0f7ee69495c0df1d35723f012624a9f8.jpg"
]
},
{
"title": "The Five Love Languages: How to Express Heartfelt Commitment to Your Mate",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-five-love-languages-how-to-express-heartfelt-commitment-to-your-mate_969/index.html",
"price": "£31.05",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/38/c5/38c56fba316c07305643a8065269594e.jpg"
]
},
{
"title": "The Elephant Tree",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-elephant-tree_968/index.html",
"price": "£23.82",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/5d/7e/5d7ecde8e81513eba8a64c9fe000744b.jpg"
]
},
{
"title": "The Bear and the Piano",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-bear-and-the-piano_967/index.html",
"price": "£36.89",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/cf/bb/cfbb5e62715c6d888fd07794c9bab5d6.jpg"
]
},
{
"title": "Sophie's World",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/sophies-world_966/index.html",
"price": "£15.94",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/65/71/6571919836ec51ed54f0050c31d8a0cd.jpg"
]
},
{
"title": "Penny Maybe",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/penny-maybe_965/index.html",
"price": "£33.29",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/12/53/1253c21c5ef3c6d075c5fa3f5fecee6a.jpg"
]
},
{
"title": "Maude (1883-1993):She Grew Up with the country",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/maude-1883-1993she-grew-up-with-the-country_964/index.html",
"price": "£18.02",
"availability": "In stock",
"rating": "Two",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/f5/88/f5889d038f5d8e949b494d147c2dcf54.jpg"
]
},
{
"title": "In a Dark, Dark Wood",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/in-a-dark-dark-wood_963/index.html",
"price": "£19.63",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/23/85/238570a1c284e730dbc737a7e631ae2b.jpg"
]
},
{
"title": "Behind Closed Doors",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/behind-closed-doors_962/index.html",
"price": "£52.22",
"availability": "In stock",
"rating": "Four",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/e1/5c/e15c289ba58cea38519e1281e859f0c1.jpg"
]
},
{
"title": "You can't bury them all: Poems",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/you-cant-bury-them-all-poems_961/index.html",
"price": "£33.63",
"availability": "In stock",
"rating": "Two",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/e9/20/e9203b733126c4a0832a1c7885dc27cf.jpg"
]
}
],
"page": "Page 2 of 50",
"next_url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/page-3.html",
"total_results": 1000,
"showing_from": 21,
"showing_to": 40,
"__counts__": {
"data": 20
}
},
"total_items": 20,
"next_found": true
},
"2": {
"page_num": 3,
"data": {
"mode": "direct",
"data": [
{
"title": "Slow States of Collapse: Poems",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/slow-states-of-collapse-poems_960/index.html",
"price": "£57.31",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/72/41/72417db983862010ef0c1a25de98c7d7.jpg"
]
},
{
"title": "Reasons to Stay Alive",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/reasons-to-stay-alive_959/index.html",
"price": "£26.41",
"availability": "In stock",
"rating": "Two",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/cb/bd/cbbdb0222ee8a0f6ab61657412a15794.jpg"
]
},
{
"title": "Private Paris (Private #10)",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/private-paris-private-10_958/index.html",
"price": "£47.61",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/9d/05/9d0533bae1578846d728a82913b95c26.jpg"
]
},
{
"title": "#HigherSelfie: Wake Up Your Life. Free Your Soul. Find Your Tribe.",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/higherselfie-wake-up-your-life-free-your-soul-find-your-tribe_957/index.html",
"price": "£23.11",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/9c/46/9c463c7631c82401160fd3b554b8f0e1.jpg"
]
},
{
"title": "Without Borders (Wanderlove #1)",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/without-borders-wanderlove-1_956/index.html",
"price": "£45.07",
"availability": "In stock",
"rating": "Two",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/24/e2/24e2f5c9d325c4004d8190c054da86dd.jpg"
]
},
{
"title": "When We Collided",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/when-we-collided_955/index.html",
"price": "£31.77",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/08/04/08044269fc197645268a6197c57e6173.jpg"
]
},
{
"title": "We Love You, Charlie Freeman",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/we-love-you-charlie-freeman_954/index.html",
"price": "£50.27",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/5f/15/5f152afdbc42356ecba02f61058a7e5b.jpg"
]
},
{
"title": "Untitled Collection: Sabbath Poems 2014",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/untitled-collection-sabbath-poems-2014_953/index.html",
"price": "£14.27",
"availability": "In stock",
"rating": "Four",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/f9/3b/f93b4a650f03a5d21f2436d7813f42c2.jpg"
]
},
{
"title": "Unseen City: The Majesty of Pigeons, the Discreet Charm of Snails & Other Wonders of the Urban Wilderness",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/unseen-city-the-majesty-of-pigeons-the-discreet-charm-of-snails-other-wonders-of-the-urban-wilderness_952/index.html",
"price": "£44.18",
"availability": "In stock",
"rating": "Four",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/41/a2/41a20f35adf0caea24f208dc01ad7681.jpg"
]
},
{
"title": "Unicorn Tracks",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/unicorn-tracks_951/index.html",
"price": "£18.78",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/76/8e/768ea5924ac1ef6297c2be9959c796c2.jpg"
]
},
{
"title": "Unbound: How Eight Technologies Made Us Human, Transformed Society, and Brought Our World to the Brink",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/unbound-how-eight-technologies-made-us-human-transformed-society-and-brought-our-world-to-the-brink_950/index.html",
"price": "£25.52",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/4a/3b/4a3b055f9e378a95fedbef55e7bab7ce.jpg"
]
},
{
"title": "Tsubasa: WoRLD CHRoNiCLE 2 (Tsubasa WoRLD CHRoNiCLE #2)",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/tsubasa-world-chronicle-2-tsubasa-world-chronicle-2_949/index.html",
"price": "£16.28",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/36/df/36df4caaf1420b1183a8235355d39e69.jpg"
]
},
{
"title": "Throwing Rocks at the Google Bus: How Growth Became the Enemy of Prosperity",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/throwing-rocks-at-the-google-bus-how-growth-became-the-enemy-of-prosperity_948/index.html",
"price": "£31.12",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/03/86/038650c9e7517b4baf2a423cd8eed38f.jpg"
]
},
{
"title": "This One Summer",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/this-one-summer_947/index.html",
"price": "£19.49",
"availability": "In stock",
"rating": "Four",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/c4/dd/c4ddd9ced89966b0602ec85e00cd5b61.jpg"
]
},
{
"title": "Thirst",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/thirst_946/index.html",
"price": "£17.27",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/c4/0a/c40a64f59e7487b1a80a049f6ceb2ba5.jpg"
]
},
{
"title": "The Torch Is Passed: A Harding Family Story",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-torch-is-passed-a-harding-family-story_945/index.html",
"price": "£19.09",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/33/e5/33e507172541628acfd421503196b578.jpg"
]
},
{
"title": "The Secret of Dreadwillow Carse",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-secret-of-dreadwillow-carse_944/index.html",
"price": "£56.13",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/c4/a2/c4a2a1a026c67bcceb5a411c724d7d0c.jpg"
]
},
{
"title": "The Pioneer Woman Cooks: Dinnertime: Comfort Classics, Freezer Food, 16-Minute Meals, and Other Delicious Ways to Solve Supper!",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-pioneer-woman-cooks-dinnertime-comfort-classics-freezer-food-16-minute-meals-and-other-delicious-ways-to-solve-supper_943/index.html",
"price": "£56.41",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/b7/f4/b7f4843dbe062d44be1ffcfa16b2faa4.jpg"
]
},
{
"title": "The Past Never Ends",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-past-never-ends_942/index.html",
"price": "£56.50",
"availability": "In stock",
"rating": "Four",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/89/b8/89b850edb01851a91f64ba114b96acb6.jpg"
]
},
{
"title": "The Natural History of Us (The Fine Art of Pretending #2)",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-natural-history-of-us-the-fine-art-of-pretending-2_941/index.html",
"price": "£45.22",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/5d/7f/5d7f496cdf5e5962a73ecdcc1505c1d5.jpg"
]
}
],
"page": "Page 3 of 50",
"next_url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/page-4.html",
"total_results": 1000,
"showing_from": 41,
"showing_to": 60,
"__counts__": {
"data": 20
}
},
"total_items": 20,
"next_found": true
},
"data": {
"link": "https://books.toscrape.com/",
"response": [
{
"page_num": 1,
"data": {
"mode": "direct",
"data": [
{
"title": "A Light in the Attic",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/a-light-in-the-attic_1000/index.html",
"price": "£51.77",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/2c/da/2cdad67c44b002e7ead0cc35693c0e8b.jpg"
]
},
{
"title": "Tipping the Velvet",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/tipping-the-velvet_999/index.html",
"price": "£53.74",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/26/0c/260c6ae16bce31c8f8c95daddd9f4a1c.jpg"
]
},
{
"title": "Soumission",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/soumission_998/index.html",
"price": "£50.10",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/3e/ef/3eef99c9d9adef34639f510662022830.jpg"
]
},
{
"title": "Sharp Objects",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/sharp-objects_997/index.html",
"price": "£47.82",
"availability": "In stock",
"rating": "Four",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/32/51/3251cf3a3412f53f339e42cac2134093.jpg"
]
},
{
"title": "Sapiens: A Brief History of Humankind",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/sapiens-a-brief-history-of-humankind_996/index.html",
"price": "£54.23",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/be/a5/bea5697f2534a2f86a3ef27b5a8c12a6.jpg"
]
},
{
"title": "The Requiem Red",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-requiem-red_995/index.html",
"price": "£22.65",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/68/33/68339b4c9bc034267e1da611ab3b34f8.jpg"
]
},
{
"title": "The Dirty Little Secrets of Getting Your Dream Job",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-dirty-little-secrets-of-getting-your-dream-job_994/index.html",
"price": "£33.34",
"availability": "In stock",
"rating": "Four",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/92/27/92274a95b7c251fea59a2b8a78275ab4.jpg"
]
},
{
"title": "The Coming Woman: A Novel Based on the Life of the Infamous Feminist, Victoria Woodhull",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-coming-woman-a-novel-based-on-the-life-of-the-infamous-feminist-victoria-woodhull_993/index.html",
"price": "£17.93",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/3d/54/3d54940e57e662c4dd1f3ff00c78cc64.jpg"
]
},
{
"title": "The Boys in the Boat: Nine Americans and Their Epic Quest for Gold at the 1936 Berlin Olympics",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-boys-in-the-boat-nine-americans-and-their-epic-quest-for-gold-at-the-1936-berlin-olympics_992/index.html",
"price": "£22.60",
"availability": "In stock",
"rating": "Four",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/66/88/66883b91f6804b2323c8369331cb7dd1.jpg"
]
},
{
"title": "The Black Maria",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-black-maria_991/index.html",
"price": "£52.15",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/58/46/5846057e28022268153beff6d352b06c.jpg"
]
},
{
"title": "Starving Hearts (Triangular Trade Trilogy, #1)",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/starving-hearts-triangular-trade-trilogy-1_990/index.html",
"price": "£13.99",
"availability": "In stock",
"rating": "Two",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/be/f4/bef44da28c98f905a3ebec0b87be8530.jpg"
]
},
{
"title": "Shakespeare's Sonnets",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/shakespeares-sonnets_989/index.html",
"price": "£20.66",
"availability": "In stock",
"rating": "Four",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/10/48/1048f63d3b5061cd2f424d20b3f9b666.jpg"
]
},
{
"title": "Set Me Free",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/set-me-free_988/index.html",
"price": "£17.46",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/5b/88/5b88c52633f53cacf162c15f4f823153.jpg"
]
},
{
"title": "Scott Pilgrim's Precious Little Life (Scott Pilgrim #1)",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/scott-pilgrims-precious-little-life-scott-pilgrim-1_987/index.html",
"price": "£52.29",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/94/b1/94b1b8b244bce9677c2f29ccc890d4d2.jpg"
]
},
{
"title": "Rip it Up and Start Again",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/rip-it-up-and-start-again_986/index.html",
"price": "£35.02",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/81/c4/81c4a973364e17d01f217e1188253d5e.jpg"
]
},
{
"title": "Our Band Could Be Your Life: Scenes from the American Indie Underground, 1981-1991",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/our-band-could-be-your-life-scenes-from-the-american-indie-underground-1981-1991_985/index.html",
"price": "£57.25",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/54/60/54607fe8945897cdcced0044103b10b6.jpg"
]
},
{
"title": "Olio",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/olio_984/index.html",
"price": "£23.88",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/55/33/553310a7162dfbc2c6d19a84da0df9e1.jpg"
]
},
{
"title": "Mesaerion: The Best Science Fiction Stories 1800-1849",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/mesaerion-the-best-science-fiction-stories-1800-1849_983/index.html",
"price": "£37.59",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/09/a3/09a3aef48557576e1a85ba7efea8ecb7.jpg"
]
},
{
"title": "Libertarianism for Beginners",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/libertarianism-for-beginners_982/index.html",
"price": "£51.33",
"availability": "In stock",
"rating": "Two",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/0b/bc/0bbcd0a6f4bcd81ccb1049a52736406e.jpg"
]
},
{
"title": "It's Only the Himalayas",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/its-only-the-himalayas_981/index.html",
"price": "£45.17",
"availability": "In stock",
"rating": "Two",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/27/a5/27a53d0bb95bdd88288eaf66c9230d7e.jpg"
]
}
],
"page": "Page 1 of 50",
"next_url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/page-2.html",
"total_results": 1000,
"showing_from": 1,
"showing_to": 20,
"__counts__": {
"data": 20
}
},
"total_items": 20,
"next_found": true
},
{
"page_num": 2,
"data": {
"mode": "direct",
"data": [
{
"title": "In Her Wake",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/in-her-wake_980/index.html",
"price": "£12.84",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/5d/72/5d72709c6a7a9584a4d1cf07648bfce1.jpg"
]
},
{
"title": "How Music Works",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/how-music-works_979/index.html",
"price": "£37.32",
"availability": "In stock",
"rating": "Two",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/5c/c8/5cc8e107246cb478960d4f0aba1e1c8e.jpg"
]
},
{
"title": "Foolproof Preserving: A Guide to Small Batch Jams, Jellies, Pickles, Condiments, and More: A Foolproof Guide to Making Small Batch Jams, Jellies, Pickles, Condiments, and More",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/foolproof-preserving-a-guide-to-small-batch-jams-jellies-pickles-condiments-and-more-a-foolproof-guide-to-making-small-batch-jams-jellies-pickles-condiments-and-more_978/index.html",
"price": "£30.52",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/9f/59/9f59f01fa916a7bb8f0b28a4012179a4.jpg"
]
},
{
"title": "Chase Me (Paris Nights #2)",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/chase-me-paris-nights-2_977/index.html",
"price": "£25.27",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/9c/2e/9c2e0eb8866b8e3f3b768994fd3d1c1a.jpg"
]
},
{
"title": "Black Dust",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/black-dust_976/index.html",
"price": "£34.53",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/44/cc/44ccc99c8f82c33d4f9d2afa4ef25787.jpg"
]
},
{
"title": "Birdsong: A Story in Pictures",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/birdsong-a-story-in-pictures_975/index.html",
"price": "£54.64",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/af/6e/af6e796160fe63e0cf19d44395c7ddf2.jpg"
]
},
{
"title": "America's Cradle of Quarterbacks: Western Pennsylvania's Football Factory from Johnny Unitas to Joe Montana",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/americas-cradle-of-quarterbacks-western-pennsylvanias-football-factory-from-johnny-unitas-to-joe-montana_974/index.html",
"price": "£22.50",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/ef/0b/ef0bed08de4e083dba5e20fdb98d9c36.jpg"
]
},
{
"title": "Aladdin and His Wonderful Lamp",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/aladdin-and-his-wonderful-lamp_973/index.html",
"price": "£53.13",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/d6/da/d6da0371958068bbaf39ea9c174275cd.jpg"
]
},
{
"title": "Worlds Elsewhere: Journeys Around Shakespeare’s Globe",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/worlds-elsewhere-journeys-around-shakespeares-globe_972/index.html",
"price": "£40.30",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/2e/98/2e98c332bf8563b584784971541c4445.jpg"
]
},
{
"title": "Wall and Piece",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/wall-and-piece_971/index.html",
"price": "£44.18",
"availability": "In stock",
"rating": "Four",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/a5/41/a5416b9646aaa7287baa287ec2590270.jpg"
]
},
{
"title": "The Four Agreements: A Practical Guide to Personal Freedom",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-four-agreements-a-practical-guide-to-personal-freedom_970/index.html",
"price": "£17.66",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/0f/7e/0f7ee69495c0df1d35723f012624a9f8.jpg"
]
},
{
"title": "The Five Love Languages: How to Express Heartfelt Commitment to Your Mate",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-five-love-languages-how-to-express-heartfelt-commitment-to-your-mate_969/index.html",
"price": "£31.05",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/38/c5/38c56fba316c07305643a8065269594e.jpg"
]
},
{
"title": "The Elephant Tree",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-elephant-tree_968/index.html",
"price": "£23.82",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/5d/7e/5d7ecde8e81513eba8a64c9fe000744b.jpg"
]
},
{
"title": "The Bear and the Piano",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-bear-and-the-piano_967/index.html",
"price": "£36.89",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/cf/bb/cfbb5e62715c6d888fd07794c9bab5d6.jpg"
]
},
{
"title": "Sophie's World",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/sophies-world_966/index.html",
"price": "£15.94",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/65/71/6571919836ec51ed54f0050c31d8a0cd.jpg"
]
},
{
"title": "Penny Maybe",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/penny-maybe_965/index.html",
"price": "£33.29",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/12/53/1253c21c5ef3c6d075c5fa3f5fecee6a.jpg"
]
},
{
"title": "Maude (1883-1993):She Grew Up with the country",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/maude-1883-1993she-grew-up-with-the-country_964/index.html",
"price": "£18.02",
"availability": "In stock",
"rating": "Two",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/f5/88/f5889d038f5d8e949b494d147c2dcf54.jpg"
]
},
{
"title": "In a Dark, Dark Wood",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/in-a-dark-dark-wood_963/index.html",
"price": "£19.63",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/23/85/238570a1c284e730dbc737a7e631ae2b.jpg"
]
},
{
"title": "Behind Closed Doors",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/behind-closed-doors_962/index.html",
"price": "£52.22",
"availability": "In stock",
"rating": "Four",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/e1/5c/e15c289ba58cea38519e1281e859f0c1.jpg"
]
},
{
"title": "You can't bury them all: Poems",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/you-cant-bury-them-all-poems_961/index.html",
"price": "£33.63",
"availability": "In stock",
"rating": "Two",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/e9/20/e9203b733126c4a0832a1c7885dc27cf.jpg"
]
}
],
"page": "Page 2 of 50",
"next_url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/page-3.html",
"total_results": 1000,
"showing_from": 21,
"showing_to": 40,
"__counts__": {
"data": 20
}
},
"total_items": 20,
"next_found": true
},
{
"page_num": 3,
"data": {
"mode": "direct",
"data": [
{
"title": "Slow States of Collapse: Poems",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/slow-states-of-collapse-poems_960/index.html",
"price": "£57.31",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/72/41/72417db983862010ef0c1a25de98c7d7.jpg"
]
},
{
"title": "Reasons to Stay Alive",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/reasons-to-stay-alive_959/index.html",
"price": "£26.41",
"availability": "In stock",
"rating": "Two",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/cb/bd/cbbdb0222ee8a0f6ab61657412a15794.jpg"
]
},
{
"title": "Private Paris (Private #10)",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/private-paris-private-10_958/index.html",
"price": "£47.61",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/9d/05/9d0533bae1578846d728a82913b95c26.jpg"
]
},
{
"title": "#HigherSelfie: Wake Up Your Life. Free Your Soul. Find Your Tribe.",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/higherselfie-wake-up-your-life-free-your-soul-find-your-tribe_957/index.html",
"price": "£23.11",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/9c/46/9c463c7631c82401160fd3b554b8f0e1.jpg"
]
},
{
"title": "Without Borders (Wanderlove #1)",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/without-borders-wanderlove-1_956/index.html",
"price": "£45.07",
"availability": "In stock",
"rating": "Two",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/24/e2/24e2f5c9d325c4004d8190c054da86dd.jpg"
]
},
{
"title": "When We Collided",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/when-we-collided_955/index.html",
"price": "£31.77",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/08/04/08044269fc197645268a6197c57e6173.jpg"
]
},
{
"title": "We Love You, Charlie Freeman",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/we-love-you-charlie-freeman_954/index.html",
"price": "£50.27",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/5f/15/5f152afdbc42356ecba02f61058a7e5b.jpg"
]
},
{
"title": "Untitled Collection: Sabbath Poems 2014",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/untitled-collection-sabbath-poems-2014_953/index.html",
"price": "£14.27",
"availability": "In stock",
"rating": "Four",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/f9/3b/f93b4a650f03a5d21f2436d7813f42c2.jpg"
]
},
{
"title": "Unseen City: The Majesty of Pigeons, the Discreet Charm of Snails & Other Wonders of the Urban Wilderness",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/unseen-city-the-majesty-of-pigeons-the-discreet-charm-of-snails-other-wonders-of-the-urban-wilderness_952/index.html",
"price": "£44.18",
"availability": "In stock",
"rating": "Four",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/41/a2/41a20f35adf0caea24f208dc01ad7681.jpg"
]
},
{
"title": "Unicorn Tracks",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/unicorn-tracks_951/index.html",
"price": "£18.78",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/76/8e/768ea5924ac1ef6297c2be9959c796c2.jpg"
]
},
{
"title": "Unbound: How Eight Technologies Made Us Human, Transformed Society, and Brought Our World to the Brink",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/unbound-how-eight-technologies-made-us-human-transformed-society-and-brought-our-world-to-the-brink_950/index.html",
"price": "£25.52",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/4a/3b/4a3b055f9e378a95fedbef55e7bab7ce.jpg"
]
},
{
"title": "Tsubasa: WoRLD CHRoNiCLE 2 (Tsubasa WoRLD CHRoNiCLE #2)",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/tsubasa-world-chronicle-2-tsubasa-world-chronicle-2_949/index.html",
"price": "£16.28",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/36/df/36df4caaf1420b1183a8235355d39e69.jpg"
]
},
{
"title": "Throwing Rocks at the Google Bus: How Growth Became the Enemy of Prosperity",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/throwing-rocks-at-the-google-bus-how-growth-became-the-enemy-of-prosperity_948/index.html",
"price": "£31.12",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/03/86/038650c9e7517b4baf2a423cd8eed38f.jpg"
]
},
{
"title": "This One Summer",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/this-one-summer_947/index.html",
"price": "£19.49",
"availability": "In stock",
"rating": "Four",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/c4/dd/c4ddd9ced89966b0602ec85e00cd5b61.jpg"
]
},
{
"title": "Thirst",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/thirst_946/index.html",
"price": "£17.27",
"availability": "In stock",
"rating": "Five",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/c4/0a/c40a64f59e7487b1a80a049f6ceb2ba5.jpg"
]
},
{
"title": "The Torch Is Passed: A Harding Family Story",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-torch-is-passed-a-harding-family-story_945/index.html",
"price": "£19.09",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/33/e5/33e507172541628acfd421503196b578.jpg"
]
},
{
"title": "The Secret of Dreadwillow Carse",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-secret-of-dreadwillow-carse_944/index.html",
"price": "£56.13",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/c4/a2/c4a2a1a026c67bcceb5a411c724d7d0c.jpg"
]
},
{
"title": "The Pioneer Woman Cooks: Dinnertime: Comfort Classics, Freezer Food, 16-Minute Meals, and Other Delicious Ways to Solve Supper!",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-pioneer-woman-cooks-dinnertime-comfort-classics-freezer-food-16-minute-meals-and-other-delicious-ways-to-solve-supper_943/index.html",
"price": "£56.41",
"availability": "In stock",
"rating": "One",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/b7/f4/b7f4843dbe062d44be1ffcfa16b2faa4.jpg"
]
},
{
"title": "The Past Never Ends",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-past-never-ends_942/index.html",
"price": "£56.50",
"availability": "In stock",
"rating": "Four",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/89/b8/89b850edb01851a91f64ba114b96acb6.jpg"
]
},
{
"title": "The Natural History of Us (The Fine Art of Pretending #2)",
"url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/the-natural-history-of-us-the-fine-art-of-pretending-2_941/index.html",
"price": "£45.22",
"availability": "In stock",
"rating": "Three",
"image_urls": [
"http://ajax.googleapis.com/ajax/libs/jquery/media/cache/5d/7f/5d7f496cdf5e5962a73ecdcc1505c1d5.jpg"
]
}
],
"page": "Page 3 of 50",
"next_url": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/page-4.html",
"total_results": 1000,
"showing_from": 41,
"showing_to": 60,
"__counts__": {
"data": 20
}
},
"total_items": 20,
"next_found": true
}
]
},
"runtime": 171141,
"event": "done"
}
```
# Scrape HTML
## Overview
Selecting **Scrape HTML** in the Playground Use Case panel optimizes the Playground for raw DOM retrieval. This preset pre-configures default request settings (such as `html=true`) to return unparsed markup directly from target sites while automatically routing through MrScraper's proxy network and anti-bot bypass engine.
Use this preset when you already have custom parsers (such as Cheerio, BeautifulSoup, or XPath engines) and simply need guaranteed access to raw page markup in the Playground.
### Practical Applications
* **Custom Parser Integration**: Feed clean, unblocked raw HTML directly into existing BeautifulSoup, Cheerio, or custom extraction pipelines.
* **Raw Markup Archiving**: Snapshot raw DOM content for historical auditing, compliance tracking, or HTML diffing.
* **SEO & Meta Structure Audits**: Inspect meta tags, OpenGraph data, canonical headers, JSON-LD schemas, and heading structures.
* **Anti-Bot Bypass & Proxy Offloading**: Access protected sites without managing residential proxies, browser fingerprinting, or CAPTCHA solvers yourself.
* **Extraction Troubleshooting**: Inspect the exact HTML payload returned by target servers before defining structured JSON schemas or markdown transformations.
## Advanced settings
| Setting | Description | Common Use Case | Default |
| --------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------------------- | ------- |
| **Block resources** | Skips non-essential assets such as images and fonts to improve performance. | Text-only or structured data extraction. | `Off` |
| **Wait for selector** | Waits until a specific element appears before starting extraction. | Content that loads asynchronously after the initial page load. | None |
| **Action** | Use this to route the request to a specific scraper action or simply flag it. | If you want to separate the analytic for a domain. | `Off` |
| **Custom Proxy** | Sends requests through your own proxy server. | Using dedicated or third-party proxy infrastructure. | `Off` |
| **Return cookies** | Returns cookies generated during the request. | Debugging sessions or reusing authenticated requests. | `Off` |
## Default Parameters
| Parameter | Description |
| --------- | ---------------------------------------------------- |
| html=true | Used by this endpoint to return html in the response |
## Example
### Request
Scrape `https://www.scrapethissite.com` with default setting
```sh title="Request"
curl --location 'https://api.mrscraper.com?token={MRSCRAPER_API_TOKEN}&geoCode=us&html=true&proxyCountry=us&url=https%3A%2F%2Fwww.scrapethissite.com' \
-H 'x-api-token: {MRSCRAPER_API_TOKEN}'
```
### Response
```html title="Response"
Scrape This Site | A public sandbox for learning web scraping
```
# Scrape JSON
## Overview
Selecting **Scrape JSON** in the Playground Use Case panel configures an AI-based scraper tailored for single-page structured data extraction. Powered by MrScraper's **`general`** AI agent (`agent: "general"`), it analyzes target web pages against your natural language prompt or optional JSON schema to return clean, strongly-typed JSON without writing fragile CSS selectors or custom XPath parsers.
The Playground pre-loads the prompt editor, schema builder, and `general` agent parameters with optimized defaults for single-page parsing.
### Practical Applications
* **E-Commerce Product Detail Extraction**: Extract structured product attributes—such as title, price, SKU, availability, variants, and image URLs—into a standardized schema.
* **Article & Editorial Metadata**: Automatically pull publication dates, author bios, headline tags, body copy, and category tags from news sites and blogs.
* **Directory & Profile Scraping**: Gather contact details, business metadata, addresses, and social links from company landing pages or user profiles.
* **Cross-Site Data Normalization**: Map disparate target websites into a single, uniform JSON schema regardless of differences in site markup.
* **Automated Data Ingestion**: Feed structured payload data directly into databases, webhooks, or downstream ETL pipelines without manual cleanup.
**Scrape JSON** is optimized for single web pages. To automatically paginate through search results, category listings, or infinite-scroll catalogs, select the [Listing Page](/docs/getting-started/playground/listing-page) Use Case preset in the Playground.
## Advanced settings
| Setting | Description | Default |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------- |
| **Data type** | Select a predefined data schema to auto-fill the `JSON Schema`. | `General` |
| **Prompt** | Describe the data shape you want back (e.g. fields like title, price, rating). This prompt only parses the scraped content. It cannot instruct the scraper itself. | `Extract all entry data as complete as possible.` |
| **JSON Schema** | Build a JSON schema to shape the extraction output. It is appended to the prompt as a 'Json Schema:' section when the request is sent. | None |
## Example
### Request
Scrape `https://quotes.toscrape.com/` with default settings.
```sh title="Request"
curl --location --request POST 'https://api.mrscraper.com?token={MRSCRAPER_API_TOKEN}&geoCode=us&html=true&proxyCountry=us' \
-H 'x-api-token: {MRSCRAPER_API_TOKEN}' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://quotes.toscrape.com/",
"prompt": "Extract all data as complete as possible.",
"agent": "general"
}'
```
### Response
```json title="Response"
{
"html": "\n\n\n\t\n\tQuotes to Scrape \n \n \n \n \n\n\n \n \n \n \n Quotes to Scrape\n
\n \n \n \n \n Login\n \n
\n \n \n \n\n\n \n\n \n “The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”\n by Albert Einstein\n (about)\n \n \n \n\n \n “It is our choices, Harry, that show what we truly are, far more than our abilities.”\n by J.K. Rowling\n (about)\n \n \n \n\n \n “There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.”\n by Albert Einstein\n (about)\n \n \n \n\n \n “The person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.”\n by Jane Austen\n (about)\n \n \n \n\n \n “Imperfection is beauty, madness is genius and it's better to be absolutely ridiculous than absolutely boring.”\n by Marilyn Monroe\n (about)\n \n \n \n\n \n “Try not to become a man of success. Rather become a man of value.”\n by Albert Einstein\n (about)\n \n \n \n\n \n “It is better to be hated for what you are than to be loved for what you are not.”\n by André Gide\n (about)\n \n \n \n\n \n “I have not failed. I've just found 10,000 ways that won't work.”\n by Thomas A. Edison\n (about)\n \n \n \n\n \n “A woman is like a tea bag; you never know how strong it is until it's in hot water.”\n by Eleanor Roosevelt\n (about)\n \n \n \n\n \n “A day without sunshine is like, you know, night.”\n by Steve Martin\n (about)\n \n \n \n\n \n \n \n \n Top Ten tags
\n \n \n love\n \n \n \n inspirational\n \n \n \n life\n \n \n \n humor\n \n \n \n books\n \n \n \n reading\n \n \n \n friendship\n \n \n \n friends\n \n \n \n truth\n \n \n \n simile\n \n \n \n \n\n\n \n \n\n",
"data": {
"quotes": [
{
"text": "The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.",
"author": "Albert Einstein",
"author_url": "/author/Albert-Einstein",
"tags": [
"change",
"deep-thoughts",
"thinking",
"world"
]
},
{
"text": "It is our choices, Harry, that show what we truly are, far more than our abilities.",
"author": "J.K. Rowling",
"author_url": "/author/J-K-Rowling",
"tags": [
"abilities",
"choices"
]
},
{
"text": "There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.",
"author": "Albert Einstein",
"author_url": "/author/Albert-Einstein",
"tags": [
"inspirational",
"life",
"live",
"miracle",
"miracles"
]
},
{
"text": "The person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.",
"author": "Jane Austen",
"author_url": "/author/Jane-Austen",
"tags": [
"aliteracy",
"books",
"classic",
"humor"
]
},
{
"text": "Imperfection is beauty, madness is genius and it's better to be absolutely ridiculous than absolutely boring.",
"author": "Marilyn Monroe",
"author_url": "/author/Marilyn-Monroe",
"tags": [
"be-yourself",
"inspirational"
]
},
{
"text": "Try not to become a man of success. Rather become a man of value.",
"author": "Albert Einstein",
"author_url": "/author/Albert-Einstein",
"tags": [
"adulthood",
"success",
"value"
]
},
{
"text": "It is better to be hated for what you are than to be loved for what you are not.",
"author": "André Gide",
"author_url": "/author/Andre-Gide",
"tags": [
"life",
"love"
]
},
{
"text": "I have not failed. I've just found 10,000 ways that won't work.",
"author": "Thomas A. Edison",
"author_url": "/author/Thomas-A-Edison",
"tags": [
"edison",
"failure",
"inspirational",
"paraphrased"
]
},
{
"text": "A woman is like a tea bag; you never know how strong it is until it's in hot water.",
"author": "Eleanor Roosevelt",
"author_url": "/author/Eleanor-Roosevelt",
"tags": [
"misattributed-eleanor-roosevelt"
]
},
{
"text": "A day without sunshine is like, you know, night.",
"author": "Steve Martin",
"author_url": "/author/Steve-Martin",
"tags": [
"humor",
"obvious",
"simile"
]
}
],
"top_ten_tags": [
"love",
"inspirational",
"life",
"humor",
"books",
"reading",
"friendship",
"friends",
"truth",
"simile"
],
"next_page": "/page/2/"
},
"runtime": 8967,
"event": "done"
}
```
# Scrape Markdown
## Overview
Selecting **Scrape Markdown** in the Playground Use Case panel optimizes the Playground environment for clean text conversion. When this preset is selected, the Playground pre-configures parameters (`markdown=true`) to automatically filter out navigation menus, scripts, advertisements, and layout HTML while preserving semantic content structures like headers, lists, code blocks, and links.
This preset generates token-efficient output (typically 70–90% smaller than raw HTML), making it ideal for testing payloads destined for AI models, RAG pipelines, or document stores.
### Practical Applications
* **LLM & RAG Pipelines**: Feed clean, token-efficient text directly into retrieval-augmented generation pipelines and AI prompt contexts without wasting token limits on raw HTML.
* **Knowledge Base Ingestion**: Convert documentation hubs, help centers, and technical guides into markdown files for indexing in vector databases or search engines.
* **Content Sync & Publishing**: Pull external articles and blog posts directly into CMS platforms, Notion, or internal wikis in ready-to-render Markdown format.
* **Automated Summarization & Analysis**: Extract core body text for downstream NLP tasks, sentiment analysis, entity extraction, or automated text summarization.
* **AI Agent Web Browsing**: Provide clean, structured context to autonomous AI agents navigating web documentation or researching online sources.
## Advanced settings
| Setting | Description | Common Use Case | Default |
| --------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------------------- | ------- |
| **Block resources** | Skips non-essential assets such as images and fonts to improve performance. | Text-only or structured data extraction. | `Off` |
| **Wait for selector** | Waits until a specific element appears before starting extraction. | Content that loads asynchronously after the initial page load. | None |
| **Action** | Use this to route the request to a specific scraper action or simply flag it. | If you want to separate the analytic for a domain. | `Off` |
| **Custom Proxy** | Sends requests through your own proxy server. | Using dedicated or third-party proxy infrastructure. | `Off` |
| **Return cookies** | Returns cookies generated during the request. | Debugging sessions or reusing authenticated requests. | `Off` |
## Default Parameters
| Parameter | Description |
| ------------- | --------------------------------------------------------- |
| markdown=true | Used by this usecase to convert the result into markdown. |
## Example
### Request
Scrape `https://books.toscrape.com/` with default setting
```sh title="Request"
curl --location --request POST 'https://api.mrscraper.com?token={MRSCRAPER_API_TOKEN}&geoCode=us&markdown=true&proxyCountry=us' \
-H 'x-api-token: {MRSCRAPER_API_TOKEN}' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://books.toscrape.com/"
}'
```
### Response
```md title="Response"
[Books to Scrape](index.html) We love being scraped!
* [Home](index.html)
* All products
* [ Books ](catalogue/category/books_1/index.html)
* [ Travel ](catalogue/category/books/travel_2/index.html)
* [ Mystery ](catalogue/category/books/mystery_3/index.html)
* [ Historical Fiction ](catalogue/category/books/historical-fiction_4/index.html)
* [ Sequential Art ](catalogue/category/books/sequential-art_5/index.html)
* [ Classics ](catalogue/category/books/classics_6/index.html)
* [ Philosophy ](catalogue/category/books/philosophy_7/index.html)
* [ Romance ](catalogue/category/books/romance_8/index.html)
* [ Womens Fiction ](catalogue/category/books/womens-fiction_9/index.html)
* [ Fiction ](catalogue/category/books/fiction_10/index.html)
* [ Childrens ](catalogue/category/books/childrens_11/index.html)
* [ Religion ](catalogue/category/books/religion_12/index.html)
* [ Nonfiction ](catalogue/category/books/nonfiction_13/index.html)
* [ Music ](catalogue/category/books/music_14/index.html)
* [ Default ](catalogue/category/books/default_15/index.html)
* [ Science Fiction ](catalogue/category/books/science-fiction_16/index.html)
* [ Sports and Games ](catalogue/category/books/sports-and-games_17/index.html)
* [ Add a comment ](catalogue/category/books/add-a-comment_18/index.html)
* [ Fantasy ](catalogue/category/books/fantasy_19/index.html)
* [ New Adult ](catalogue/category/books/new-adult_20/index.html)
* [ Young Adult ](catalogue/category/books/young-adult_21/index.html)
* [ Science ](catalogue/category/books/science_22/index.html)
* [ Poetry ](catalogue/category/books/poetry_23/index.html)
* [ Paranormal ](catalogue/category/books/paranormal_24/index.html)
* [ Art ](catalogue/category/books/art_25/index.html)
* [ Psychology ](catalogue/category/books/psychology_26/index.html)
* [ Autobiography ](catalogue/category/books/autobiography_27/index.html)
* [ Parenting ](catalogue/category/books/parenting_28/index.html)
* [ Adult Fiction ](catalogue/category/books/adult-fiction_29/index.html)
* [ Humor ](catalogue/category/books/humor_30/index.html)
* [ Horror ](catalogue/category/books/horror_31/index.html)
* [ History ](catalogue/category/books/history_32/index.html)
* [ Food and Drink ](catalogue/category/books/food-and-drink_33/index.html)
* [ Christian Fiction ](catalogue/category/books/christian-fiction_34/index.html)
* [ Business ](catalogue/category/books/business_35/index.html)
* [ Biography ](catalogue/category/books/biography_36/index.html)
* [ Thriller ](catalogue/category/books/thriller_37/index.html)
* [ Contemporary ](catalogue/category/books/contemporary_38/index.html)
* [ Spirituality ](catalogue/category/books/spirituality_39/index.html)
* [ Academic ](catalogue/category/books/academic_40/index.html)
* [ Self Help ](catalogue/category/books/self-help_41/index.html)
* [ Historical ](catalogue/category/books/historical_42/index.html)
* [ Christian ](catalogue/category/books/christian_43/index.html)
* [ Suspense ](catalogue/category/books/suspense_44/index.html)
* [ Short Stories ](catalogue/category/books/short-stories_45/index.html)
* [ Novels ](catalogue/category/books/novels_46/index.html)
* [ Health ](catalogue/category/books/health_47/index.html)
* [ Politics ](catalogue/category/books/politics_48/index.html)
* [ Cultural ](catalogue/category/books/cultural_49/index.html)
* [ Erotica ](catalogue/category/books/erotica_50/index.html)
* [ Crime ](catalogue/category/books/crime_51/index.html)
# All products
**1000** results - showing **1** to **20**.
**Warning!** This is a demo website for web scraping purposes. Prices and ratings here were randomly assigned and have no real meaning.
1. [](catalogue/a-light-in-the-attic_1000/index.html)
__________
### [A Light in the ...](catalogue/a-light-in-the-attic_1000/index.html "A Light in the Attic")
£51.77
__In stock
Add to basket
2. [](catalogue/tipping-the-velvet_999/index.html)
__________
### [Tipping the Velvet](catalogue/tipping-the-velvet_999/index.html "Tipping the Velvet")
£53.74
__In stock
Add to basket
3. [](catalogue/soumission_998/index.html)
__________
### [Soumission](catalogue/soumission_998/index.html "Soumission")
£50.10
__In stock
Add to basket
4. [](catalogue/sharp-objects_997/index.html)
__________
### [Sharp Objects](catalogue/sharp-objects_997/index.html "Sharp Objects")
£47.82
__In stock
Add to basket
5. [](catalogue/sapiens-a-brief-history-of-humankind_996/index.html)
__________
### [Sapiens: A Brief History ...](catalogue/sapiens-a-brief-history-of-humankind_996/index.html "Sapiens: A Brief History of Humankind")
£54.23
__In stock
Add to basket
6. [](catalogue/the-requiem-red_995/index.html)
__________
### [The Requiem Red](catalogue/the-requiem-red_995/index.html "The Requiem Red")
£22.65
__In stock
Add to basket
7. [](catalogue/the-dirty-little-secrets-of-getting-your-dream-job_994/index.html)
__________
### [The Dirty Little Secrets ...](catalogue/the-dirty-little-secrets-of-getting-your-dream-job_994/index.html "The Dirty Little Secrets of Getting Your Dream Job")
£33.34
__In stock
Add to basket
8. [](catalogue/the-coming-woman-a-novel-based-on-the-life-of-the-infamous-feminist-victoria-woodhull_993/index.html)
__________
### [The Coming Woman: A ...](catalogue/the-coming-woman-a-novel-based-on-the-life-of-the-infamous-feminist-victoria-woodhull_993/index.html "The Coming Woman: A Novel Based on the Life of the Infamous Feminist, Victoria Woodhull")
£17.93
__In stock
Add to basket
9. [](catalogue/the-boys-in-the-boat-nine-americans-and-their-epic-quest-for-gold-at-the-1936-berlin-olympics_992/index.html)
__________
### [The Boys in the ...](catalogue/the-boys-in-the-boat-nine-americans-and-their-epic-quest-for-gold-at-the-1936-berlin-olympics_992/index.html "The Boys in the Boat: Nine Americans and Their Epic Quest for Gold at the 1936 Berlin Olympics")
£22.60
__In stock
Add to basket
10. [](catalogue/the-black-maria_991/index.html)
__________
### [The Black Maria](catalogue/the-black-maria_991/index.html "The Black Maria")
£52.15
__In stock
Add to basket
11. [](catalogue/starving-hearts-triangular-trade-trilogy-1_990/index.html)
__________
### [Starving Hearts (Triangular Trade ...](catalogue/starving-hearts-triangular-trade-trilogy-1_990/index.html "Starving Hearts \(Triangular Trade Trilogy, #1\)")
£13.99
__In stock
Add to basket
12. [](catalogue/shakespeares-sonnets_989/index.html)
__________
### [Shakespeare's Sonnets](catalogue/shakespeares-sonnets_989/index.html "Shakespeare's Sonnets")
£20.66
__In stock
Add to basket
13. [](catalogue/set-me-free_988/index.html)
__________
### [Set Me Free](catalogue/set-me-free_988/index.html "Set Me Free")
£17.46
__In stock
Add to basket
14. [](catalogue/scott-pilgrims-precious-little-life-scott-pilgrim-1_987/index.html)
__________
### [Scott Pilgrim's Precious Little ...](catalogue/scott-pilgrims-precious-little-life-scott-pilgrim-1_987/index.html "Scott Pilgrim's Precious Little Life \(Scott Pilgrim #1\)")
£52.29
__In stock
Add to basket
15. [](catalogue/rip-it-up-and-start-again_986/index.html)
__________
### [Rip it Up and ...](catalogue/rip-it-up-and-start-again_986/index.html "Rip it Up and Start Again")
£35.02
__In stock
Add to basket
16. [](catalogue/our-band-could-be-your-life-scenes-from-the-american-indie-underground-1981-1991_985/index.html)
__________
### [Our Band Could Be ...](catalogue/our-band-could-be-your-life-scenes-from-the-american-indie-underground-1981-1991_985/index.html "Our Band Could Be Your Life: Scenes from the American Indie Underground, 1981-1991")
£57.25
__In stock
Add to basket
17. [](catalogue/olio_984/index.html)
__________
### [Olio](catalogue/olio_984/index.html "Olio")
£23.88
__In stock
Add to basket
18. [](catalogue/mesaerion-the-best-science-fiction-stories-1800-1849_983/index.html)
__________
### [Mesaerion: The Best Science ...](catalogue/mesaerion-the-best-science-fiction-stories-1800-1849_983/index.html "Mesaerion: The Best Science Fiction Stories 1800-1849")
£37.59
__In stock
Add to basket
19. [](catalogue/libertarianism-for-beginners_982/index.html)
__________
### [Libertarianism for Beginners](catalogue/libertarianism-for-beginners_982/index.html "Libertarianism for Beginners")
£51.33
__In stock
Add to basket
20. [](catalogue/its-only-the-himalayas_981/index.html)
__________
### [It's Only the Himalayas](catalogue/its-only-the-himalayas_981/index.html "It's Only the Himalayas")
£45.17
__In stock
Add to basket
* Page 1 of 50
* [next](catalogue/page-2.html)
```
# Scrape Sitemap
## Overview
Selecting **Scrape Sitemap** in the Playground Use Case panel configures an AI-based discovery crawler for site mapping. Powered by MrScraper's **`map`** AI agent (`agent: "map"`), it recursively traverses website link structures to discover endpoints and map site architecture without downloading full page content payloads.
The Playground pre-configures crawler parameters for the `map` agent—exposing maximum crawl depth (`maxDepth`), page limits (`maxPages`), and URL regex filters (include/exclude patterns)—making it ideal for generating seed URL lists before running bulk data extraction tasks.
### Practical Applications
* **Pre-Crawl Site Topology Discovery**: Analyze website hierarchy and URL distributions before triggering large-scale data extraction pipelines.
* **Seed List Generation**: Build comprehensive target URL lists to feed into bulk **Scrape JSON**, **Scrape Markdown**, or **Scrape HTML** runs.
* **SEO Architecture Audits**: Discover internal link structures, audit indexable routes, and detect orphan pages or broken URL paths.
* **Scoped Endpoint Filtering**: Restrict discovery to specific paths (e.g., `/docs/*`, `/store/*`) while ignoring unwanted routes like user dashboards or admin panels.
* **Site Change Detection**: Periodically crawl target domains to monitor newly published pages or removed URL paths over time.
## Advanced settings
| Setting | Description | Default |
| ---------------- | ---------------------------------------------------------------------------- | ------- |
| Max Pages | Maximum number of pages to crawl | `3` |
| Max Depth | Maximum crawl depth from the starting URL | `2` |
| Limit | Maximum number of URLs to collect | `1000` |
| Include Patterns | One URL pattern per line. Only URLs matching these patterns will be crawled. | None |
| Exclude Patterns | One URL pattern per line. URLs matching these patterns will be skipped. | None |
## Example
### Request
Scrape `https://quotes.toscrape.com/` with default settings.
```sh title="Request"
curl --location --request POST 'https://api.mrscraper.com?token={MRSCRAPER_API_TOKEN}&geoCode=us&proxyCountry=us' \
-H 'x-api-token: {MRSCRAPER_API_TOKEN}' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://quotes.toscrape.com/",
"agent": "map",
"maxDepth": 2,
"maxPages": 3,
"limit": 1000
}'
```
### Response
```json title="Response"
{
"data": {
"count": 47,
"urls": [
"https://quotes.toscrape.com",
"https://quotes.toscrape.com/author/Albert-Einstein",
"https://quotes.toscrape.com/author/Andre-Gide",
"https://quotes.toscrape.com/author/Eleanor-Roosevelt",
"https://quotes.toscrape.com/author/J-K-Rowling",
"https://quotes.toscrape.com/author/Jane-Austen",
"https://quotes.toscrape.com/author/Marilyn-Monroe",
"https://quotes.toscrape.com/author/Steve-Martin",
"https://quotes.toscrape.com/author/Thomas-A-Edison",
"https://quotes.toscrape.com/login",
"https://quotes.toscrape.com/page/2",
"https://quotes.toscrape.com/tag/abilities/page/1",
"https://quotes.toscrape.com/tag/adulthood/page/1",
"https://quotes.toscrape.com/tag/aliteracy/page/1",
"https://quotes.toscrape.com/tag/be-yourself/page/1",
"https://quotes.toscrape.com/tag/books",
"https://quotes.toscrape.com/tag/books/page/1",
"https://quotes.toscrape.com/tag/change/page/1",
"https://quotes.toscrape.com/tag/choices/page/1",
"https://quotes.toscrape.com/tag/classic/page/1",
"https://quotes.toscrape.com/tag/deep-thoughts/page/1",
"https://quotes.toscrape.com/tag/edison/page/1",
"https://quotes.toscrape.com/tag/failure/page/1",
"https://quotes.toscrape.com/tag/friends",
"https://quotes.toscrape.com/tag/friendship",
"https://quotes.toscrape.com/tag/humor",
"https://quotes.toscrape.com/tag/humor/page/1",
"https://quotes.toscrape.com/tag/inspirational",
"https://quotes.toscrape.com/tag/inspirational/page/1",
"https://quotes.toscrape.com/tag/life",
"https://quotes.toscrape.com/tag/life/page/1",
"https://quotes.toscrape.com/tag/live/page/1",
"https://quotes.toscrape.com/tag/love",
"https://quotes.toscrape.com/tag/love/page/1",
"https://quotes.toscrape.com/tag/miracle/page/1",
"https://quotes.toscrape.com/tag/miracles/page/1",
"https://quotes.toscrape.com/tag/misattributed-eleanor-roosevelt/page/1",
"https://quotes.toscrape.com/tag/obvious/page/1",
"https://quotes.toscrape.com/tag/paraphrased/page/1",
"https://quotes.toscrape.com/tag/reading",
"https://quotes.toscrape.com/tag/simile",
"https://quotes.toscrape.com/tag/simile/page/1",
"https://quotes.toscrape.com/tag/success/page/1",
"https://quotes.toscrape.com/tag/thinking/page/1",
"https://quotes.toscrape.com/tag/truth",
"https://quotes.toscrape.com/tag/value/page/1",
"https://quotes.toscrape.com/tag/world/page/1"
]
},
"runtime": 5305,
"event": "done"
}
```
# Apify
import { Step, Steps } from 'fumadocs-ui/components/steps';
## Apify Integration
[Apify](https://apify.com/) is a cloud platform for running, scheduling, and scaling web scraping and automation programs called **Actors**. Actors run in managed containers, store their output in datasets, and can be triggered from the Apify Console, the Apify API, the CLI, or from other Actors in a workflow.
MrScraper publishes its scraping engine as Actors on the [MrScraper Apify profile](https://apify.com/mrscrapercom), so you can use MrScraper's unblocking and AI extraction without managing proxies, browsers, or infrastructure yourself.
## Available Actors
Unblock and extract structured data from detail pages — products, articles, hotels, job postings, properties, and more.
Extract data from listing and category pages with AI, including pagination across multiple pages.
Retrieve raw HTML from any page, bypassing anti-bot protection and geo restrictions.
## Why Use MrScraper on Apify?
* **No API token required**: Billing and authentication are handled by your Apify account, so you don't need a separate MrScraper API token.
* **Managed infrastructure**: Apify handles the runtime, retries, storage, and scheduling.
* **Built-in storage**: Results land in an Apify dataset that you can export as JSON, CSV, XLSX, or push to other integrations.
* **Composable**: Chain the Actors together or with any other Actor in the Apify Store.
* **Pay per event**: You're charged for what each run actually consumes rather than for a fixed subscription.
Use **Unblocker** when you want the raw HTML and will parse it yourself. Use **PDP** when you want structured fields from a single item page. Use **Listing** when you want many items from a category, search, or directory page.
## Prerequisites
Before you start, make sure you have:
* An [**Apify account**](https://console.apify.com/sign-up).
* An [**Apify API token**](https://console.apify.com/settings/integrations) (only needed for API or CLI runs).
You do **not** need a MrScraper account or API token to run these Actors — usage is billed through Apify.
## Running an Actor
### Open the Actor
Go to the [MrScraper profile on Apify](https://apify.com/mrscrapercom) and open the Actor you want to run, or search for **MrScraper** in the Apify Store.
### Configure the input
Fill in the input fields in the Console form, or switch to the **JSON** tab to paste an input object directly. Each Actor's fields are documented on its own page.
### Start the run
Click **Start**. The run log streams live, and results appear in the **Dataset** tab as they're produced.
### Export or forward the results
Export the dataset as JSON, CSV, or XLSX from the Console, fetch it through the Apify API, or connect it to a webhook or another Actor to continue the pipeline.
### Running via the Apify API
You can start any of the Actors with a single HTTP request. Replace `` with your token and `` with `mrscraper-pdp`, `mrscraper-listing`, or `mrscraper-unblocker`.
```bash
curl -X POST "https://api.apify.com/v2/acts/mrscrapercom~/runs?token=" \
-H "Content-Type: application/json" \
-d '{
"urls": [{ "url": "https://www.ebay.com/itm/236604718789" }],
"category": "product"
}'
```
To run the Actor and wait for the dataset items in one call, use the `run-sync-get-dataset-items` endpoint:
```bash
curl -X POST "https://api.apify.com/v2/acts/mrscrapercom~/run-sync-get-dataset-items?token=" \
-H "Content-Type: application/json" \
-d '{
"urls": [{ "url": "https://www.ebay.com/itm/236604718789" }],
"category": "product"
}'
```
### Running via the Apify CLI
```bash
npm install -g apify-cli
apify login
apify call mrscrapercom/mrscraper-pdp --input-file input.json
```
## Shared Input Options
The MrScraper Actors share a common set of proxy and output options. Individual Actor pages list the fields each one supports.
### Proxy options
| Parameter | Type | Required | Default | Description |
| --------------------- | ------- | -------- | ------- | ---------------------------------------------------------------------------------------------------- |
| `proxy_use_proxy` | boolean | No | `true` | Route requests through residential and mobile IPs to avoid blocks. |
| `proxy_proxy_country` | string | No | `""` | Country code for geo-targeted requests (e.g. `US`, `GB`, `SG`). Leave empty to let MrScraper choose. |
| `proxy_bypass_proxy` | boolean | No | `true` | Block images, fonts, and stylesheets to reduce bandwidth and speed up the run. |
### Browser rendering options
Available on the **PDP** and **Unblocker** Actors, for pages that build their content with JavaScript.
| Parameter | Type | Required | Default | Description |
| ------------------------------------- | ------- | -------- | ------- | ------------------------------------------------------------------------ |
| `browser_rendering_enabled` | boolean | No | `false` | Load the page in a full browser instead of a plain HTTP request. |
| `browser_rendering_wait_for_selector` | string | No | `""` | CSS selector to wait for before extracting, for content that loads late. |
| `browser_rendering_listen_network` | boolean | No | `false` | Capture network requests made while the page loads. **PDP only.** |
Browser rendering and network listening are billed as separate events on top of the standard request. Leave them off unless the page genuinely needs them — start with a plain request and enable rendering only if the data is missing.
### Output options
Available on the **PDP** and **Listing** Actors.
| Parameter | Type | Required | Default | Description |
| ----------------- | ------- | -------- | ------- | ----------------------------------------------------------------------- |
| `output_html` | boolean | No | `false` | Include the raw HTML of the page alongside the extracted data. |
| `output_markdown` | boolean | No | `false` | Include a Markdown rendering of the page, useful for feeding into LLMs. |
## Pricing
All three Actors use Apify's **pay-per-event** model, so cost scales with what a run actually does rather than with compute time alone.
| Actor | Starting price |
| ------------------------------------------------------------------------- | -------------------------------------- |
| [MrScraper Unblocker](https://apify.com/mrscrapercom/mrscraper-unblocker) | From $2.00 / 1,000 standard requests |
| [MrScraper PDP](https://apify.com/mrscrapercom/mrscraper-pdp) | From $3.00 / 1,000 standard requests |
| [MrScraper Listing](https://apify.com/mrscrapercom/mrscraper-listing) | From $100.00 / 1,000 standard requests |
Runs can also incur these event charges:
* **Standard request**: Charged per URL processed.
* **Browser rendering**: Charged when `browser_rendering_enabled` is on.
* **Network listening**: Charged when `browser_rendering_listen_network` is on.
* **Time-based cost**: Charged per 30-second interval of run time.
* **Bandwidth cost**: Charged per MB transferred.
* **AI token cost**: Charged based on tokens consumed by AI extraction.
Prices above are starting rates and Apify Store discounts vary by subscription tier. Check the Actor's page on Apify for the current rates before running at volume.
## Enterprise and Custom Actors
For custom integrations, higher volumes, or Actors tailored to a specific site, contact the MrScraper team through [mrscraper.com](https://www.mrscraper.com).
# MrScraper Listing
import { Step, Steps } from 'fumadocs-ui/components/steps';
The [**MrScraper Listing**](https://apify.com/mrscrapercom/mrscraper-listing) Actor unblocks pages and scrapes **listing pages** from any website. It uses AI-powered extraction, so instead of writing selectors you describe what you want in a prompt and the Actor returns structured data for every item on the page.
## What It Does
Point the Actor at a listing URL — a category page, search results, a product grid, a job board, a directory — and it extracts every item it finds. Set `max_pages` above `1` and it follows pagination automatically.
The `prompt` field controls what gets extracted. The default asks for everything available, but a specific prompt gives you cleaner, more predictable output.
## When to Use It
* **Ecommerce**: Product names, prices, ratings, and links from category or search pages.
* **Job boards**: Titles, companies, locations, and posting URLs across paginated results.
* **Real estate**: Property listings with prices, addresses, and specifications.
* **News aggregation**: Headlines, summaries, and article links from index pages.
* **Business directories**: Company names, contact details, and profile URLs.
* **Research**: Any dataset that lives behind a paginated list.
The Listing Actor is often the first half of a pipeline: use it to collect item URLs from a category page, then feed those URLs into the [MrScraper PDP Actor](/docs/integrations/apify/pdp) to get the full detail of each item.
## Input
| Parameter | Type | Required | Default | Description |
| --------------------- | ------- | -------- | --------------------------------------------------- | ------------------------------------------------------------- |
| `url` | string | Yes | — | The listing or category page URL to scrape. |
| `prompt` | string | No | `"Extract all available data as much as possible."` | Natural-language instructions telling the AI what to extract. |
| `max_pages` | integer | No | `1` | How many paginated pages to process. |
| `proxy_use_proxy` | boolean | No | `true` | Route requests through residential and mobile IPs. |
| `proxy_proxy_country` | string | No | `""` | Country code for accessing geo-restricted listings. |
| `proxy_bypass_proxy` | boolean | No | `true` | Block images and fonts to speed up the run. |
| `output_html` | boolean | No | `false` | Include the raw HTML in the output. |
| `output_markdown` | boolean | No | `false` | Include a Markdown version of the page in the output. |
Unlike the PDP and Unblocker Actors, this Actor takes a single `url`, not an array. To process several listing pages, start one run per URL.
### Example input
```json
{
"url": "https://www.walmart.com/shop/tech/tvs-and-home-theater-new-arrivals?povid=XCAT_NewArrivals_MerchModule_Tech_tvsandhometheatre",
"prompt": "Extract all available data as much as possible.",
"max_pages": 1,
"proxy_use_proxy": true,
"proxy_proxy_country": "",
"proxy_bypass_proxy": true,
"output_html": false,
"output_markdown": false
}
```
### Writing a good prompt
The default prompt extracts everything the AI can find, which is useful for exploring a page but noisy for production. Naming the fields you want produces a tighter schema:
```json
{
"url": "https://example.com/laptops",
"prompt": "Extract product name, current price, original price, rating, review count, and the product URL for each laptop.",
"max_pages": 5
}
```
## Output
The Actor writes a `result` field to the Apify dataset as a single row. It contains the MrScraper API response with the extracted structured data in JSON format.
## Usage
### Open the Actor
Go to [apify.com/mrscrapercom/mrscraper-listing](https://apify.com/mrscrapercom/mrscraper-listing) and click **Try for free**.
### Set the URL and prompt
Paste the listing page URL, then write a prompt describing the fields you want. Be specific — the prompt is what shapes the output.
### Choose how many pages to scrape
Set `max_pages` to the number of paginated pages you want. Start with `1` to check the output shape before scaling up.
### Run and export
Click **Start**, then export the dataset from the **Dataset** tab or fetch it through the Apify API.
### Run via the API
```bash
curl -X POST "https://api.apify.com/v2/acts/mrscrapercom~mrscraper-listing/run-sync-get-dataset-items?token=" \
-H "Content-Type: application/json" \
-d '{
"url": "https://www.walmart.com/shop/tech/tvs-and-home-theater-new-arrivals",
"prompt": "Extract product name, price, and rating for each item.",
"max_pages": 1
}'
```
## Pricing
Pay-per-event, starting from **$100.00 per 1,000 standard requests**. Charges break down as:
* `standard-request`: Per URL processed.
* `time-based-cost`: Per 30-second interval of run time.
* `bandwidth-cost`: Per MB transferred.
* `ai-token-cost`: Based on AI token consumption.
This Actor costs substantially more per request than PDP or Unblocker because each run performs AI extraction across a full page of items. Run once with `max_pages: 1` to confirm your prompt returns what you expect, then raise `max_pages`.
# MrScraper PDP
import { Step, Steps } from 'fumadocs-ui/components/steps';
The [**MrScraper PDP**](https://apify.com/mrscrapercom/mrscraper-pdp) Actor unblocks pages and scrapes **detail pages** from any website. It's stealth, reliable, and scalable — you give it a list of URLs and a content category, and it returns structured fields for each page.
"PDP" stands for *product detail page*, but the Actor handles many kinds of single-item pages, not just products.
## What It Does
The Actor fetches each URL through MrScraper's unblocking engine, then extracts structured data according to the **category** you select. Supported categories:
* `article`
* `post`
* `hotel`
* `job posting`
* `product`
* `property`
* `restaurant`
* `social media profile`
* `tour/attraction`
## When to Use It
* Extracting product name, price, images, and specifications from ecommerce item pages.
* Pulling article titles, authors, and body text from news or blog posts.
* Collecting hotel, restaurant, or attraction details for travel data.
* Gathering job posting fields from careers pages.
* Building a structured dataset from a list of URLs you already have — for example, URLs produced by the [Listing Actor](/docs/integrations/apify/listing).
Run the [MrScraper Listing Actor](/docs/integrations/apify/listing) over a category or search page to collect item URLs, then feed those URLs into this Actor for the full detail of each item.
## Input
| Parameter | Type | Required | Default | Description |
| ------------------------------------- | ------- | -------- | ------- | ------------------------------------------------------------------------------------------ |
| `urls` | array | Yes | — | List of detail page URLs to scrape. Each entry is an object with a `url` field. |
| `category` | string | Yes | — | The type of page being scraped. Determines which fields are extracted. See the list above. |
| `browser_rendering_enabled` | boolean | No | `false` | Enable browser rendering for JavaScript-heavy pages. |
| `browser_rendering_listen_network` | boolean | No | `false` | Capture network requests made during page loading. |
| `browser_rendering_wait_for_selector` | string | No | `""` | CSS selector to wait for before extraction. |
| `proxy_use_proxy` | boolean | No | `true` | Route requests through residential and mobile IPs. |
| `proxy_proxy_country` | string | No | `""` | Country code for geo-targeted proxy routing. |
| `proxy_bypass_proxy` | boolean | No | `true` | Block images, fonts, and stylesheets to speed up the run. |
| `output_html` | boolean | No | `false` | Include the raw HTML in the output. |
| `output_markdown` | boolean | No | `false` | Include a Markdown version of the page in the output. |
### Example input
```json
{
"urls": [
{
"url": "https://www.ebay.com/itm/236604718789"
}
],
"category": "product",
"browser_rendering_enabled": false,
"browser_rendering_listen_network": false,
"browser_rendering_wait_for_selector": "",
"proxy_use_proxy": true,
"proxy_proxy_country": "",
"proxy_bypass_proxy": true,
"output_html": false,
"output_markdown": false
}
```
## Output
Each scraped page is pushed to the Apify dataset as one item. The extracted fields depend on the `category` you selected — a `product` page returns price and images, while an `article` page returns author and body content.
```json
{
"url": "https://example.com/product/123",
"category": "product",
"title": "Product Name",
"description": "Product description...",
"price": "$99.99",
"images": ["https://example.com/image1.jpg"],
"html": "",
"markdown": ""
}
```
The `html` field appears only when `output_html` is `true`, and `markdown` only when `output_markdown` is `true`.
## Usage
### Open the Actor
Go to [apify.com/mrscrapercom/mrscraper-pdp](https://apify.com/mrscrapercom/mrscraper-pdp) and click **Try for free**.
### Add your URLs and category
Paste the detail page URLs into the **urls** field, then pick the **category** that matches the page type. Getting the category right matters — it determines which fields the extractor looks for.
### Adjust proxy and rendering options
Leave the defaults for most sites. If the page returns empty or partial data, enable `browser_rendering_enabled` and set `browser_rendering_wait_for_selector` to an element that appears once the content has loaded.
### Run and export
Click **Start**, then export the dataset as JSON, CSV, or XLSX from the **Dataset** tab.
### Run via the API
```bash
curl -X POST "https://api.apify.com/v2/acts/mrscrapercom~mrscraper-pdp/run-sync-get-dataset-items?token=" \
-H "Content-Type: application/json" \
-d '{
"urls": [
{ "url": "https://www.ebay.com/itm/236604718789" }
],
"category": "product"
}'
```
## Pricing
Pay-per-event, starting from **$3.00 per 1,000 standard requests**. Additional charges apply for browser rendering, network listening, run time (per 30-second interval), bandwidth, and AI token usage. Apify Store discounts apply based on your subscription tier.
Browser rendering, network listening, and the `output_html` / `output_markdown` options all add cost — rendering and listening as separate events, and the output options through bandwidth. Enable them only when you need them.
# MrScraper Unblocker
import { Step, Steps } from 'fumadocs-ui/components/steps';
The [**MrScraper Unblocker**](https://apify.com/mrscrapercom/mrscraper-unblocker) Actor unblocks websites and retrieves the **raw HTML** of any page. It handles anti-bot protection and geo restrictions through residential and mobile proxies, and returns the page source for you to parse however you like.
## What It Does
This is the lowest-level of the three MrScraper Actors. It does no extraction — it gets you past the block and hands back the HTML. Use it when you already have parsing logic and just need reliable access to the page.
## When to Use It
* You have your own parser and only need the HTML.
* You're debugging why a scrape returns nothing, and want to see what the server actually sends.
* You need to reach a page that's restricted to a specific country.
* You're feeding raw HTML into a downstream Actor or an LLM.
If you want parsed fields rather than HTML, use the [PDP Actor](/docs/integrations/apify/pdp) for detail pages or the [Listing Actor](/docs/integrations/apify/listing) for category and search pages.
## Input
| Parameter | Type | Required | Default | Description |
| ------------------------------------- | ------- | -------- | ------- | -------------------------------------------------------------------- |
| `urls` | array | Yes | — | List of URLs to unblock. Each entry is an object with a `url` field. |
| `browser_rendering_enabled` | boolean | No | `false` | Load the page in a full browser for JavaScript-heavy sites. |
| `browser_rendering_wait_for_selector` | string | No | `""` | CSS selector to wait for before capturing the HTML. |
| `proxy_use_proxy` | boolean | No | `true` | Route requests through residential and mobile IPs. |
| `proxy_proxy_country` | string | No | `""` | Country code for accessing geo-restricted pages. |
| `proxy_bypass_proxy` | boolean | No | `true` | Block images, fonts, and stylesheets to optimize the request. |
### Example input
```json
{
"urls": [
{
"url": "https://www.ebay.com/itm/236604718789"
}
],
"browser_rendering_enabled": false,
"browser_rendering_wait_for_selector": "",
"proxy_use_proxy": true,
"proxy_proxy_country": "",
"proxy_bypass_proxy": true
}
```
## Output
Each URL produces a dataset item containing the page's HTML.
```json
{
"html": ""
}
```
## Usage
### Open the Actor
Go to [apify.com/mrscrapercom/mrscraper-unblocker](https://apify.com/mrscrapercom/mrscraper-unblocker) and click **Try for free**.
### Add your URLs
Paste the URLs you want to unblock into the **urls** field.
### Handle JavaScript-rendered pages
If the returned HTML is missing the content you expect, the page likely builds it client-side. Enable `browser_rendering_enabled` and set `browser_rendering_wait_for_selector` to an element that only exists once the content has rendered.
### Target a country if needed
For pages that vary by region or block foreign traffic, set `proxy_proxy_country` to the relevant country code (for example `US`, `GB`, or `SG`).
### Run and collect the HTML
Click **Start**, then read the HTML from the dataset or fetch it through the Apify API.
### Run via the API
```bash
curl -X POST "https://api.apify.com/v2/acts/mrscrapercom~mrscraper-unblocker/run-sync-get-dataset-items?token=" \
-H "Content-Type: application/json" \
-d '{
"urls": [
{ "url": "https://www.ebay.com/itm/236604718789" }
],
"proxy_use_proxy": true,
"proxy_proxy_country": "US"
}'
```
## Pricing
Pay-per-event, starting from **$2.00 per 1,000 standard requests** — the cheapest of the three MrScraper Actors, since it performs no AI extraction. Additional charges apply for browser rendering, bandwidth, and run time (per 30-second interval).
Leaving `proxy_bypass_proxy` enabled blocks images, fonts, and stylesheets. The HTML you get back is unaffected, and you pay for noticeably less bandwidth.
# Get Your Account Information
import { Step, Steps } from 'fumadocs-ui/components/steps';
This example workflow demonstrates how to:
* Retrieve your MrScraper account information directly in n8n
* Store the returned account data in Google Sheets for tracking and reuse
This guide uses the exact working three-node workflow: Manual Trigger, MrScraper Get Account Info, and Google Sheets Append or Update Row.
## Workflow Setup
### Set Up the Manual Trigger
1. Add a **Manual Trigger** node called **When clicking 'Execute workflow'**.
2. Use this trigger to run the workflow on demand whenever you need updated account data.
### Get Account Information from MrScraper
1. Add the **MrScraper** node called **Get Account Info**.
2. Configure your MrScraper credential in **Credential to connect with**:
* Click **Create new credential**
* Paste your **MrScraper API token**
* Save the credential
3. Configure the node:
* **Resource**: `Account`
* **Operation**: `Get Account Info`
This node returns your account information as JSON output for downstream nodes.
### Append or Update the Data in Google Sheets
1. Add a **Google Sheets** node called **Append or update row in sheet**.
2. Connect your Google credential:
* Click **Create new credential** if needed
* Complete the OAuth flow and save
3. Configure the node:
* **Operation**: `Append or Update`
* **Document**: select your target spreadsheet
* **Sheet**: select your target tab
* **Columns**: choose **Auto-map Input Data**
4. Keep optional settings at defaults unless your sheet requires custom matching behavior.
This writes the account information from MrScraper into your selected Google Sheet.
# Create a Scraper
import { Step, Steps } from 'fumadocs-ui/components/steps';
This example workflow demonstrates how to:
* **Create a scraper**: Set up a new Scraper in MrScraper directly in n8n
* **Create a spreadsheet**: Automatically create a new Google Sheets spreadsheet and store the scraper ID and URL of the newly created scraper
This workflow is designed as a foundational building block. By saving the scraper ID and URL to a sheet, you can later reference those values to build a full end-to-end scraping pipeline without needing to manually look up or re-enter scraper details.
## Workflow Setup
### Set Up the Manual Trigger
1. Add a **Manual Trigger** node called "When clicking 'Execute workflow'".
2. This allows you to run the workflow on demand whenever you need to create a new scraper.
### Create a Scraper
1. Add the **MrScraper** node and select **Create Prompt-Based Scraper**, or another creation operation that fits your target page.
2. In **Credential to connect with**, add your MrScraper API credentials:
* Click **Create new credential**
* Paste your **MrScraper API token**
* Save the credential
3. Configure the scraper settings:
* **Resource**: Select **Scraper Creation**
* **Operation**: Select **Create Prompt-Based Scraper**, **Create Listing Scraper**, or **Create Website Crawl Scraper**
* **URL**: Enter the URL you want to scrape (e.g., `https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html`)
* **Prompt**: Describe what data you want to extract (e.g., "please get all details data")
* **Mode**: Choose scraping mode:
* Select **Cheap** for websites with weak security
* Select **Super** for websites with strong protection ([learn more](/docs/features/ai-scraper#scraper-modes))
* **Proxy Country** (optional): Choose a proxy country if needed (e.g., `US`, `GB`, `SG`)
This creates the Scraper along with its scraper ID and target URL.
### Create a New Google Spreadsheet
1. Add a **Google Sheets** node called "Create spreadsheet".
2. Authenticate with your Google account:
* Click **Create new credential**
* Follow the OAuth flow to authorize n8n
3. Configure the node:
* **Resource**: Select **Spreadsheet**
* **Operation**: Select **Create**
* **Title** (optional): Give your spreadsheet a name, or leave blank for auto-generated name
This creates a new Google Sheets spreadsheet to store the scraper ID and target URL.
### Append Data to the Spreadsheet
1. Add another **Google Sheets** node called "Append row in sheet".
2. Use the same Google credentials from Step 3.
3. Configure the node:
* **Resource**: Select **Sheet**
* **Operation**: Select **Append**
* **Document**: Select the spreadsheet created in the previous step
* **Sheet**: Select the sheet (typically "Sheet1")
* **Columns**: Choose **Auto-map Input Data** to automatically map all fields from the scraper data
The scraper data will be automatically appended to your new spreadsheet.
# n8n
import { Step, Steps } from 'fumadocs-ui/components/steps';
## n8n Integration
[n8n](https://n8n.io/) is an open-source workflow automation tool that lets teams connect apps, services, and APIs using a visual, node-based interface. Similar to Zapier or Make, n8n automates repetitive tasks and builds workflows without custom code.
Workflows in n8n run automatically based on triggers such as schedules, webhooks, or events from connected tools.
## Overview
The MrScraper n8n integration enables you to:
* **Extract data on demand** - Run one-off scrapes by prompt, preset schema, or raw rendered HTML
* **Discover URLs** - Crawl a website for links or pull Google search results
* **Create scrapers** - Set up reusable AI scrapers directly from your workflow
* **Run scrapers** - Trigger existing AI or manual scrapers with a single URL or in batch
* **Get results** - Retrieve scraped data including latest results, paginated results, or a specific result by ID
* **Monitor your account** - Check token usage and limits
## Why Use This Integration?
Integrating MrScraper with n8n enables fully automated data pipelines:
* Automatically create and run scrapers on a schedule or trigger
* Fetch and process scraping results programmatically
* Send scraped data to other tools (Google Sheets, databases, APIs, webhooks, notification systems)
* Build end-to-end workflows by connecting MrScraper with hundreds of n8n-supported services
This transforms scraping from a standalone task into a seamless part of broader automation workflows.
The MrScraper node is tool-enabled. You can attach it to an n8n **AI Agent** node and let the model call MrScraper operations on its own, instead of wiring them into a fixed workflow path.
## Prerequisites
Before you start, ensure you have:
* [A **MrScraper API token**](https://app.mrscraper.com/api-tokens)
* [A **MrScraper scraper** with API access enabled](https://app.mrscraper.com/scrapers) (for Scraper Run operations)
* Access to an **n8n** instance (self-hosted or cloud)
The node authenticates with a single **API Token** credential, sent as an `x-api-token` header.
## Understanding MrScraper Resources
The MrScraper node in n8n groups its actions into six **Resources**. Understanding these resources will help you choose the right one for your workflow.
If you built workflows against an earlier version of the node, resource and operation names have changed. See [What changed](#what-changed) for the full mapping.
| Resource | What it does | Runs immediately? |
| -------------------- | ------------------------------------------------------ | ----------------- |
| **Account** | Read account details, token usage and limits | Yes |
| **Discovery** | Find URLs by crawling a site or searching Google | Yes |
| **Extraction** | One-off scraping by prompt, preset schema, or raw HTML | Yes |
| **Result** | Fetch data produced by your scrapers | Yes |
| **Scraper Creation** | Create a reusable scraper in your MrScraper account | Yes |
| **Scraper Run** | Run an existing scraper on new URLs | Yes |
### Account
Retrieve your MrScraper account information, including account type, usage limits, and token consumption.
**Operation:** Get Account Info
**Use Case:** Monitor account status and usage in automated workflows. This operation takes no parameters.
### Discovery
Find URLs and search results to feed into the rest of your workflow.
Discover URLs by crawling links from a starting website.
**Best for:** Site mapping, URL discovery, building link inventories before a detail-page scrape.
**Parameters:**
| Parameter | Required | Default | Description |
| ---------------- | -------- | ------- | ------------------------------------------ |
| URL | Yes | — | Starting URL for the crawl |
| Max Depth | No | `2` | How many levels deep to follow links |
| Max Pages | No | `50` | Maximum pages to evaluate during discovery |
| Limit | No | `50` | Maximum number of results to return |
| Include Patterns | No | — | Pipe-separated regex for URLs to include |
| Exclude Patterns | No | — | Pipe-separated regex for URLs to exclude |
Include and exclude patterns are regular expressions separated by `|`, for example `^https://www\.example\.com/blog/|^https://www\.example\.com/products/`.
Fetch Google search results as JSON or HTML through the synchronous MrScraper SERP API.
**Best for:** Keyword monitoring, competitor tracking, seeding a workflow with search results.
**Parameters:**
| Parameter | Required | Default | Description |
| ----------------- | -------- | ------- | ---------------------------------------------------------- |
| Search Query | Yes | — | Google search terms, e.g. `best hotels in New York` |
| Region | Yes | `us` | Two-letter country/region code for localized results |
| Language | Yes | `en` | Two-letter result language code |
| Page | Yes | `1` | Google results page number |
| Format | No | `JSON` | `JSON` for parsed results, `HTML` for the raw results page |
| Render JavaScript | No | `false` | Render JavaScript before collecting results |
### Extraction
Run a scrape and get data back immediately, without creating a persistent scraper first.
Extract data from a single page using your own prompt.
**Best for:** Product detail pages, article pages, profile pages, single-item extraction.
**Parameters:**
| Parameter | Required | Default | Description |
| ---------------------- | -------- | ------- | ----------------------------------------------------------------------------------------------------------------- |
| URL | Yes | — | The target URL to scrape |
| Prompt | No | — | Instructions for what data to extract |
| Expected Output Schema | No | — | JSON describing the expected output shape |
| Mode | No | `Super` | `Cheap` for weak security, `Super` for stronger protection. [Learn more](/docs/features/ai-scraper#scraper-modes) |
| Proxy Country | No | — | ISO country code for the proxy, e.g. `US`, `GB`, `ID`, `SG` |
The schema is not sent as a separate field. It is stringified and appended to your prompt, so the agent returns JSON matching the shape you described. Example: `{"name":"string","price":"number","inStock":"boolean"}`.
Extract repeated items across one or more pages of a listing.
**Best for:** Product category pages, search results, directory pages, multi-page listings.
**Parameters:**
| Parameter | Required | Default | Description |
| ---------------------- | -------- | ------- | ------------------------------------------------------- |
| URL | Yes | — | The target URL to scrape |
| Prompt | No | — | Instructions for what to extract from each listing page |
| Expected Output Schema | No | — | JSON describing each expected listing item |
| Max Pages | No | `1` | Maximum pagination pages to scrape |
| Proxy Country | No | — | ISO country code for the proxy |
Extract data using a preset schema instead of writing your own prompt.
**Best for:** Common page types where a standard set of fields is enough.
**Parameters:**
| Parameter | Required | Default | Description |
| ------------------------ | -------- | --------- | -------------------------------- |
| URL | Yes | — | The target URL to scrape |
| Structured Data Category | Yes | `Article` | Preset extraction schema |
| Mode | No | `Super` | `Cheap` or `Super` scraping mode |
| Proxy Country | No | — | ISO country code for the proxy |
**Available Categories:** Article, Forum Thread, Hotel, Job Posting, Post, Product, Property, Restaurant, Social Media Profile, Tour / Attraction.
Fetch the rendered HTML of a page through the MrScraper stealth browser, with JavaScript execution, bot evasion, and optional geo proxy.
**Best for:** Troubleshooting scraping issues, retrieving page source, or when you need raw HTML or Markdown rather than structured extraction.
**Parameters:**
| Parameter | Required | Default | Description |
| --------------- | -------- | ------- | ---------------------------------------------------------------------------------------- |
| URL | Yes | — | Target URL to fetch |
| Max Retries | No | `3` | Retry attempts when the request fails |
| Timeout | No | `300` | Maximum seconds to wait for the page to load |
| Geo Code | No | `us` | Country code used for geolocation |
| Proxy Country | No | `us` | Country code for the proxy location |
| Screenshot | No | `false` | Capture and return a screenshot |
| Screenshot Mode | No | `Full` | `Full` for the entire page or `Top` for the top only. Appears once Screenshot is enabled |
| Return HTML | No | `true` | Include the rendered HTML in the response |
| Return Markdown | No | `false` | Include Markdown converted from the rendered page |
**Advanced Options:**
Click **Add Option** to reach these.
| Option | Default | Description |
| ----------------- | -------------------- | ------------------------------------------------------------------------------------ |
| Token Cap | `30` | Maximum token allowance for processing the scraped content |
| Wait for Selector | — | CSS selector to wait for before returning the page |
| Wait Until | `DOM Content Loaded` | Browser lifecycle event to wait for: `DOM Content Loaded`, `Load`, or `Network Idle` |
| Block Resources | `true` | Block images, fonts, and stylesheets for faster, cheaper loads |
| Home Page | `false` | Navigate via the site's home page before the target URL |
| Return Cookie | `true` | Include browser cookies in the response |
| Super | `true` | Use a real device for sites requiring stronger capabilities |
This operation always renders the page in a browser, so JavaScript content loads. There is no toggle to disable it.
### Result
Retrieve data produced by your scrapers. This is typically the final step in a scraping workflow, where you fetch the data to send to other systems.
Retrieve paginated results with sorting.
**Best for:** Large result sets that need pagination or specific sorting.
**Parameters:**
| Parameter | Required | Default | Description |
| ---------- | -------- | ------------ | ---------------------------------------- |
| Scraper ID | Yes | — | ID of the scraper whose results to fetch |
| Page | Yes | `1` | Page number for pagination |
| Page Size | Yes | `10` | Number of results per page |
| Sort By | Yes | `Created At` | Field used to sort results |
| Sort Order | Yes | `Descending` | `Ascending` or `Descending` |
Retrieve the most recent results for a scraper.
**Best for:** Monitoring workflows where you only need the latest data.
**Parameters:**
| Parameter | Required | Default | Description |
| ---------- | -------- | ------- | ----------------------------------------------- |
| Scraper ID | Yes | — | ID of the scraper whose latest results to fetch |
| N | Yes | `10` | Number of latest results to fetch |
Retrieve a specific result by its ID.
**Best for:** Fetching a known result, or following up on a batch run.
**Parameters:**
| Parameter | Required | Default | Description |
| --------- | -------- | ------- | ---------------------------- |
| Result ID | Yes | — | Unique result ID to retrieve |
Retrieve batch run results by passing the batch operation ID to this operation. A Scraper ID is not required here.
Result operations are commonly used to pass scraped data to other n8n nodes like Google Sheets, databases, webhooks, or notifications.
### Scraper Creation
Create a persistent scraper in your MrScraper account that can be reused and triggered multiple times with the **Scraper Run** resource.
**Use Case:** When you need a reusable scraper configuration that you'll run repeatedly with different URLs.
Create an AI scraper from a URL, an extraction prompt, and an expected JSON output schema.
**Parameters:**
| Parameter | Required | Default | Description |
| ---------------------- | -------- | ------- | ----------------------------------------- |
| URL | Yes | — | The target URL to scrape |
| Prompt | No | — | Instructions for what data to extract |
| Expected Output Schema | No | — | JSON describing the expected output shape |
| Mode | No | `Super` | `Cheap` or `Super` scraping mode |
| Proxy Country | No | — | ISO country code for the proxy |
Create an AI scraper for repeated listing data using a prompt and an expected JSON output schema.
**Parameters:**
| Parameter | Required | Default | Description |
| ---------------------- | -------- | ------- | ----------------------------------------------- |
| URL | Yes | — | The target URL to scrape |
| Prompt | No | — | Instructions for what to extract from each item |
| Expected Output Schema | No | — | JSON describing each expected listing item |
| Max Pages | No | `1` | Maximum pagination pages to scrape |
| Proxy Country | No | — | ISO country code for the proxy |
Create a scraper that discovers URLs by crawling a website.
**Parameters:**
| Parameter | Required | Default | Description |
| ---------------- | -------- | ------- | ------------------------------------------ |
| URL | Yes | — | Starting URL for the crawl |
| Max Depth | No | `2` | How many levels deep to follow links |
| Max Pages | No | `50` | Maximum pages to evaluate during discovery |
| Limit | No | `50` | Maximum number of results to return |
| Include Patterns | No | — | Pipe-separated regex for URLs to include |
| Exclude Patterns | No | — | Pipe-separated regex for URLs to exclude |
### Scraper Run
Run an existing scraper again with new URLs. Requires a scraper created through **Scraper Creation** or in the MrScraper dashboard.
**Operations:**
* **Run Existing Scraper** - run one URL
* **Run Existing Scraper in Batch** - run multiple URLs in a single request
Instead of a separate operation per agent type, you pick the scraper's shape with two selectors:
| Selector | Values | Shown when |
| ---------------- | --------------------------- | ---------------------------------------------------------- |
| **Scraper Type** | `AI`, `Manual` | Always |
| **Agent Type** | `General`, `Listing`, `Map` | Scraper Type is `AI` and operation is Run Existing Scraper |
The selectors must match how the scraper was built. Choosing `Manual` routes the request to the manual-scraper endpoint, and each Agent Type exposes a different set of run settings.
#### Run Existing Scraper
Every single run takes these fields:
| Parameter | Required | Default | Description |
| ------------- | -------- | ------- | -------------------------------------------------------- |
| Scraper ID | Yes | — | ID of the existing scraper, from the scraper detail page |
| URL | Yes | — | Full URL to process in this run |
| Max Retry | No | `3` | Maximum retry attempts if the run fails |
| Proxy Country | No | — | Proxy country code, e.g. `US` or `GB` |
Additional fields depend on the selected type:
No extra required fields beyond the common ones.
**Options:**
| Option | Default | Description |
| ----------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Bypass Proxy | `false` | Block images, fonts, and stylesheets to speed up scraping |
| HTML | `false` | Include HTML in the result |
| Markdown | `false` | Include Markdown in the result |
| Render JavaScript | `false` | Render JavaScript before extracting content |
| Return Cookies | `false` | Include browser cookies in the result |
| Screenshot | `false` | Capture a screenshot during the run |
| Use Home Page | `false` | Visit the site's home page first. Improves success rate on some sites, but adds latency — enable only if the scraper is blocked |
| Wait for Selector | — | CSS selector to wait for before extraction |
**Extra parameters:**
| Parameter | Required | Default | Description |
| --------- | -------- | ------- | ------------------------------------------- |
| Max Pages | No | `5` | Maximum pagination pages to scrape |
| Timeout | No | `300` | Maximum seconds to wait for the listing run |
**Options:** the same set as AI · General, plus:
| Option | Default | Description |
| ------ | ------- | ----------------------------------------------- |
| Stream | `false` | Stream listing results as they become available |
**Extra parameters:**
| Parameter | Required | Default | Description |
| ---------------- | -------- | ------- | ------------------------------------------------- |
| Max Depth | No | `2` | Maximum link depth to crawl from the starting URL |
| Max Pages | No | `50` | Maximum pages to evaluate during URL discovery |
| Limit | No | `50` | Maximum number of results to return |
| Include Patterns | No | — | Pipe-separated regex for URLs to include |
| Exclude Patterns | No | — | Pipe-separated regex for URLs to exclude |
Map runs do not expose an Options collection.
Manual scrapers have their own Options set, covering browser session control and pagination.
**Options:**
| Option | Default | Description |
| ----------------- | ------- | ------------------------------------------------------------------------ |
| Bypass Proxy | `true` | Block images, fonts, and stylesheets to speed up scraping |
| Cookie Jar | — | Cookie jar identifier or serialized cookie jar value |
| Cookies | `[]` | JSON array of browser cookie objects for this run |
| Home Page | `false` | Visit the site's home page before the target URL |
| Home Page Timeout | `10` | Maximum seconds to wait for the home page |
| HTML | `false` | Include HTML in the result |
| Markdown | `false` | Include Markdown in the result |
| Paginator | `{}` | JSON pagination configuration, e.g. `{"selector":"a.next","maxPages":5}` |
| Proxy | — | Proxy URL used for this run |
| Record | `false` | Record the browser session |
| Return Cookie | `false` | Include browser cookies in the result |
| Screenshot | `false` | Capture a screenshot and return it Base64-encoded |
| Stream | `false` | Stream results as they become available |
| Timeout | `600` | Maximum seconds to wait for the run |
| Token Cap | `0` | Maximum token count for the result; `0` means no explicit limit |
#### Run Existing Scraper in Batch
Run multiple URLs against one existing scraper in a single operation.
**Use Case:** Scrape many product pages, profiles, or articles with the same scraper configuration without creating separate workflow nodes.
**Parameters:**
| Parameter | Required | Description |
| ------------ | -------- | ---------------------------------------------------- |
| Scraper Type | Yes | `AI` or `Manual`, matching how the scraper was built |
| Scraper ID | Yes | ID of your AI or manual scraper |
| URLs | Yes | The URLs to scrape |
The URLs field accepts a JSON array (`["https://example.com/a", "https://example.com/b"]`), or a comma- or newline-separated list. The value is normalized to an array before it is sent.
Retrieve batch results by passing the batch operation ID to the **Get Result Detail** operation.
## What Changed
Resource and operation names were reorganized in recent versions of the node. If you are updating older workflows or older notes, use this mapping:
| Previously | Now |
| ----------------------------------------------------------------- | ------------------------------------------------------------------ |
| **Agent** resource | **Extraction** resource |
| **Scraping** resource | **Extraction** resource |
| **Web Unblocker** resource | Extraction → **Fetch Rendered HTML** |
| **Batch Operation** resource | Scraper Run → **Run Existing Scraper in Batch** |
| **Create Scraper** resource | **Scraper Creation** resource |
| **Rerun Scraper** resource | **Scraper Run** resource |
| **Results** resource | **Result** resource |
| Scrape Dynamic Content | Extract Page by Prompt |
| Scrape Paginated Content | Extract Listings and Paginated Content |
| Scrape Structured Data | Extract Structured Data |
| Scrape Web Page | Fetch Rendered HTML |
| Crawl Website Sitemap | Discovery → Crawl Website URLs |
| Scrape Search Results | Discovery → **Search Google SERP** (now a real Google SERP API) |
| Run General / Listing / Map / Manual Agent Scraper (4 operations) | Run Existing Scraper + **Scraper Type** / **Agent Type** selectors |
New in the current node:
* **Discovery** resource, including the synchronous Google SERP API
* **Expected Output Schema** on prompt-based and listing operations
* **Options** collections on Scraper Run (screenshot, HTML, Markdown, cookies, streaming, wait-for-selector, and more)
* An **Advanced Options** collection on Extraction → Fetch Rendered HTML
* The node is usable as an **AI Agent tool**
Fetch Rendered HTML was also reshuffled. If you configured it on an earlier node version:
* `Token Cap`, `Block Resources`, `Wait Until`, `Return Cookie`, and `Super` moved into **Advanced Options**
* `Browser Rendering` was removed — the page is always rendered in a browser
* `Screenshot` is now a toggle plus a separate `Screenshot Mode` (`Full` / `Top`), instead of a text field
* `Wait Until` is now a dropdown rather than free text
* `Return Markdown` now defaults to `false`
## Understanding n8n Upstream Node Execution
When you execute a node in n8n, **all upstream nodes automatically re-execute silently**. With MrScraper, this means hidden token costs.
**Common example workflow:**
```
Create Scraper → Run Scraper → Get Results
```
**What happens when you only want to test the Get Results node:**
You click "Test" on Get Results, but n8n silently executes ALL upstream nodes:
1. Scraper Creation runs → Creates new scraper
2. Scraper Run runs → Runs the scraper
3. Result runs → Retrieves results
Every test click on Get Results creates a brand new scraper. Testing 10 times = 10 new scrapers created and more tokens burned.
## Setup Guide
Now that you understand the available resources, let's set up your first MrScraper workflow.
### Add the MrScraper Node
1. Open the **n8n workflow editor**
2. Click the **+** button to add a new node
3. Search for **MrScraper**
4. Select the MrScraper node
### Configure Credentials
1. In **Credential to connect with**, click **Create new credential**
2. Paste your **MrScraper API token**
3. Click **Save**
### Choose Your Resource and Configure
1. Select the **Resource** that matches your use case (see [Understanding MrScraper Resources](#understanding-mrscraper-resources) above)
2. Select the **Operation**
3. Fill in the required parameters, then add optional ones as needed
### Test and Execute
1. Click **Test step** to verify your configuration
2. Review the returned data
3. Connect the output to other nodes in your workflow
Start with the **Extraction** resource for testing and one-off scraping. Once you have a working configuration, use **Scraper Creation** to save it for reuse with the **Scraper Run** resource.
## Example Workflows
Create a scraper with the MrScraper n8n node and export results to Google Sheets. Use the generated outputs as reusable inputs for building end-to-end scraping workflows.
Automate data extraction from real estate listing websites using a two-agent approach.
Scrape entire websites using a two-agent approach for comprehensive data collection.
Comprehensive website scraping combining three powerful agents for complete site coverage.
## Prebuilt Workflow Templates
MrScraper provides ready-to-deploy n8n workflow templates for common automation use cases. Each template is built around real-world scenarios and can be deployed in minutes.
Select the template that fits your use case, follow the setup guide, and you'll have a working automation running in minutes.
Scrape Realtor.com listings on a schedule and receive formatted CSV or XLSX reports via Gmail.
Pull structured data from any website and append it automatically to a live Google Sheet.
Extract product names, prices, and ratings from a batch of search result URLs into Google Sheets.
Crawl your documentation site and power a GPT-4.1-mini chatbot that answers user questions accurately.
Scrape news articles, analyze sentiment with GPT-4o-mini, and receive Slack digests on coverage shifts.
Track platform reviews with GPT-4o-mini and receive Slack alerts when negative patterns emerge.
# Listing & General Agents
import { Step, Steps } from 'fumadocs-ui/components/steps';
This example workflow uses two agents:
* **Listing Agent**: Collects property URLs from search results pages
* **General Agent**: Scrapes each property URL and extract detailed information
## Set up All Agents
Create and configure the Map Agent, Listing Agent, and General Agent so each one is ready to perform its specific role in the workflow.
#### Set Up the Manual Trigger
1. Add a **Manual Trigger** node called "When clicking 'Execute workflow'".
2. This allows you to run the complete three-agent workflow on demand.
#### Load Listing Agent Configuration
1. Add another **Google Sheets** node called "Get Listing Agent Scraper".
2. Select **Read Rows** or **Lookup** operation.
3. Authenticate with your Google account.
4. Select the Google Sheets file that stores your Listing Agent Scraper ID and target URL.
If you have not yet created a spreadsheet containing scraper IDs and target URLs, refer to the\
[Create a Scraper](/docs/integrations/n8n/create-scraper) guide to configure your Google Sheets.
5. This node reads the Listing Agent scraper ID and target URL from your sheet.
#### Load General Agent Configuration
1. Add a third **Google Sheets** node called "Get General Agent Scraper".
2. Connect it after the "Get Listing Agent Scraper" node.
3. Select the Google Sheets file that stores your General Agent Scraper ID and target URL.
If you have not yet created a spreadsheet containing scraper IDs and target URLs, refer to the\
[Create a Scraper](/docs/integrations/n8n/create-scraper) guide to configure your Google Sheets.
4. This loads the General Agent scraper ID for extracting property details.
## Run the Listing Agent
Execute the Listing Agent to scrape search results and extract property URLs.
#### Run the Listing Agent
1. Add the **MrScraper** node called "Run listing agent scraper".
2. Set **Resource** to **Scraper Run**, **Operation** to **Run Existing Scraper**, **Scraper Type** to **AI**, and **Agent Type** to **Listing**.
3. Configure using values from Google Sheets:
* **Scraper ID**: `{{ $json.listingScraperId }}`
* **URL**: `{{ $json.listingTargetUrl }}`
* **Max Pages**: Set how many result pages to scrape (e.g., 2-5)
* **Timeout**: 720 seconds
#### Extract All Property URLs
1. Add a **Code** node in Python called "Extract All Url".
2. Parse the listing response to collect all property URLs:
```python
items = []
payload = _input.item.json
urls = set()
response = payload.get("data", {}).get("response") or []
for page in response:
listings = page.get("data", {}).get("data") or []
for listing in listings:
url = listing.get("url")
if isinstance(url, str) and url.strip():
urls.add(url)
for url in urls:
items.append({"json": {"url": url}})
return items
```
## Process Property URLs with the General Agent
Execute the General Agent for each property URL to extract detailed information.
#### Loop Through Properties
1. Add a **Loop Over Items** node.
2. This processes each property URL one at a time in batches.
3. Configure the batch size based on your needs.
#### Run the General Agent
1. Add another **MrScraper** node inside the loop called "Run general agent scraper".
2. Set **Resource** to **Scraper Run**, **Operation** to **Run Existing Scraper**, **Scraper Type** to **AI**, and **Agent Type** to **General**.
3. Configure using the scraper ID from Google Sheets:
* **Scraper ID**: `{{ $('Get row(s) in sheet1').item.json.generalScraperId }}`
* **URL**: `{{ $json.url }}`
4. This extracts detailed information from each property page.
5. Connect this node back to the loop to continue processing.
## Export the Results
Send the scraped data to Google Sheets and notify via email.
#### Flatten the JSON Data
1. Add a **Code** node in JavaScript called "Flatten Object".
2. Convert nested JSON into a flat structure for easier export:
```javascript
function flattenObject(obj, prefix = '', result = {}) {
for (const key in obj) {
const newKey = prefix ? `${prefix}_${key}` : key;
const value = obj[key];
if (value === null || value === undefined) {
result[newKey] = null;
} else if (Array.isArray(value)) {
result[newKey] = value.length ? value.join(', ') : null;
} else if (typeof value === 'object') {
flattenObject(value, newKey, result);
} else {
result[newKey] = value;
}
}
return result;
}
const items = $input.all();
return items.map(item => ({ json: flattenObject(item.json) }));
```
#### Save to Google Sheets
1. Add a **Google Sheets** node called "Append row in sheet".
2. Select **Append Row** operation.
3. Authenticate with your Google account.
4. Select your destination spreadsheet and sheet (can be different from your configuration sheet).
5. Map the flattened data fields to your columns.
#### Send Email Notification
1. Add a **Gmail** node called "Send a message".
2. Configure:
* **To**: Your email address
* **Subject**: "Property Scraping Complete"
* **Message**: Include summary or link to the spreadsheet
3. This notifies you when scraping is finished.
# Map & General Agents
import { Step, Steps } from 'fumadocs-ui/components/steps';
This example workflow uses:
* **Map Agent**: Crawls a website and discover all URLs that match the defined criteria
* **General Agent**: Extracts detailed data from each discovered page
## Set up All Agents
Create and configure the Map Agent, Listing Agent, and General Agent so each one is ready to perform its specific role in the workflow.
#### Set Up the Manual Trigger
1. Add a **Manual Trigger** node called "When clicking 'Execute workflow'".
2. This allows you to run the complete three-agent workflow on demand.
#### Load Map Agent Configuration
1. Add a **Google Sheets** node called "Get Map Agent Scraper".
2. Select **Read Rows** or **Lookup** operation.
3. Authenticate with your Google account.
4. Select the Google Sheets file that stores your Map Agent Scraper ID and target URL.
If you have not yet created a spreadsheet containing scraper IDs and target URLs, refer to the\
[Create a Scraper](/docs/integrations/n8n/create-scraper) guide to configure your Google Sheets.
5. This node reads the Map Agent scraper ID and target URL from your sheet.
#### Load General Agent Configuration
1. Add a third **Google Sheets** node called "Get General Agent Scraper".
2. Connect it after the "Get Map Agent Scraper" node.
3. Select the Google Sheets file that stores your General Agent Scraper ID and target URL.
If you have not yet created a spreadsheet containing scraper IDs and target URLs, refer to the\
[Create a Scraper](/docs/integrations/n8n/create-scraper) guide to configure your Google Sheets.
4. This loads the General Agent scraper ID for extracting property details.
## Run the Map Agent
Execute the Map Agent to discover all URLs on the website and filter them.
#### Run the Map Agent
1. Add the **MrScraper** node called "Run map agent scraper".
2. Set **Resource** to **Scraper Run**, **Operation** to **Run Existing Scraper**, **Scraper Type** to **AI**, and **Agent Type** to **Map**.
3. Configure using values from Google Sheets:
* **Scraper ID**: `{{ $json.mapScraperId }}`
* **URL**: `{{ $json.mapTargetUrl }}`
* **Max Pages**: Set how many pages to crawl (e.g., 100)
* **Limit**: Maximum URLs to discover (e.g., 200)
* **Include Patterns**: URL pattern to match (e.g., "property-detail")
4. The Map Agent will crawl the website and discover all matching URLs.
#### Filter & Limit Discovered URLs
1. Add a **Code** node in JavaScript called "Filter & Limit Link".
2. Filter URLs by pattern and limit the total number:
```javascript
// Configuration
const MAX_URLS = 20; // Change this to limit how many URLs you want
// Get the data from the previous node
const inputData = $input.all();
// Extract URLs from the response
let urls = [];
if (inputData.length > 0 && inputData[0].json.data && inputData[0].json.data.urls) {
urls = inputData[0].json.data.urls;
}
// Filter URLs that contain your target pattern
const filteredUrls = urls.filter(url => url.includes('property-detail'));
// Limit the number of URLs
const limitedUrls = filteredUrls.slice(0, MAX_URLS);
// Return as separate items for looping
return limitedUrls.map((url, index) => ({
json: {
url: url,
index: index + 1,
totalUrls: limitedUrls.length
}
}));
```
3. Adjust `MAX_URLS` and the filter pattern (`property-detail`) to match your needs.
## Process URLs with General Agent
Loop through discovered URLs and extract detailed data using the General Agent.
#### Loop Through Discovered URLs
1. Add a **Split in Batches** node called "Looping Detail Page url".
2. This processes each discovered URL one at a time.
3. Keep **Reset** unchecked to continue looping.
#### Run the General Agent
1. Add the **MrScraper** node inside the loop called "Run general agent scraper".
2. Set **Resource** to **Scraper Run**, **Operation** to **Run Existing Scraper**, **Scraper Type** to **AI**, and **Agent Type** to **General**.
3. Configure using the scraper ID from Google Sheets:
* **Scraper ID**: `{{ $('Get General Agent Scraper').item.json.generalScraperId }}`
* **URL**: `{{ $json.url }}`
4. This extracts detailed information from each discovered page.
5. Connect this node back to the loop node to continue processing.
## Export the Results
Finally, export the collected data to Google Sheets and send a notification email via Gmail.
#### Flatten the JSON Data
1. Add a **Code** node in JavaScript called "Flatten Object".
2. Convert nested JSON into flat structure:
```javascript
function flattenObject(obj, prefix = '', result = {}) {
for (const key in obj) {
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
const newKey = prefix ? `${prefix}_${key}` : key;
const value = obj[key];
if (value === null || value === undefined) {
result[newKey] = null;
} else if (Array.isArray(value)) {
result[newKey] = value.length ? value.join(', ') : null;
} else if (typeof value === 'object' && !(value instanceof Date)) {
flattenObject(value, newKey, result);
} else {
result[newKey] = value;
}
}
return result;
}
const items = $input.all();
const output = items.map(item => {
const flattened = flattenObject(item.json);
return { json: flattened };
});
return output;
```
3. This prepares data for spreadsheet export.
#### Save to Google Sheets
1. Add a **Google Sheets** node called "Get row(s) in sheet".
2. Select **Append Row** operation.
3. Authenticate with your Google account.
4. Select your destination spreadsheet and sheet (can be different from your configuration sheet).
5. Map the flattened data fields to your columns.
#### Send Email Notification
1. Add a **Gmail** node called "Send a message".
2. Configure:
* **To**: Your email address
* **Subject**: "Website Scraping Complete"
* **Message**: Include summary of scraped pages or link to spreadsheet
3. This notifies you when the entire workflow is complete.
# Map & Listing & General Agents
import { Step, Steps } from 'fumadocs-ui/components/steps';
This workflow provides the most comprehensive scraping setup by combining three agents for maximum coverage:
* **Map Agent**: Crawls the website to discover all listing and category pages
* **Listing Agent**: Extracts individual property or product URLs from paginated listing pages
* **General Agent**: Visits each extracted URL to scrape detailed data from individual pages
This approach works well for large-scale real estate or e-commerce data extraction.
## Set up All Agents
Create and configure the Map Agent, Listing Agent, and General Agent so each one is ready to perform its specific role in the workflow.
#### Set Up the Manual Trigger
1. Add a **Manual Trigger** node called "When clicking 'Execute workflow'".
2. This allows you to run the complete three-agent workflow on demand.
#### Load Map Agent Configuration
1. Add a **Google Sheets** node called "Get Map Agent Scraper".
2. Select **Read Rows** or **Lookup** operation.
3. Authenticate with your Google account.
4. Select the Google Sheets file that stores your Map Agent Scraper ID and target URL.
If you have not yet created a spreadsheet containing scraper IDs and target URLs, refer to the\
[Create a Scraper](/docs/integrations/n8n/create-scraper) guide to configure your Google Sheets.
5. This node reads the Map Agent scraper ID and target URL from your sheet.
#### Load Listing Agent Configuration
1. Add another **Google Sheets** node called "Get Listing Agent Scraper".
2. Connect it after the "Get Map Agent Scraper" node.
3. Select the Google Sheets file that stores your Listing Agent Scraper ID and target URL.
If you have not yet created a spreadsheet containing scraper IDs and target URLs, refer to the\
[Create a Scraper](/docs/integrations/n8n/create-scraper) guide to configure your Google Sheets.
4. This loads the Listing Agent scraper ID for processing listing pages.
#### Load General Agent Configuration
1. Add a third **Google Sheets** node called "Get General Agent Scraper".
2. Connect it after the "Get Listing Agent Scraper" node.
3. Select the Google Sheets file that stores your General Agent Scraper ID and target URL.
If you have not yet created a spreadsheet containing scraper IDs and target URLs, refer to the\
[Create a Scraper](/docs/integrations/n8n/create-scraper) guide to configure your Google Sheets.
4. This loads the General Agent scraper ID for extracting property details.
## Run the Map Agent
Execute the Map Agent to crawl the website and discover all listing pages.
#### Run the Map Agent
1. Add the **MrScraper** node called "Run map agent scraper".
2. Set **Resource** to **Scraper Run**, **Operation** to **Run Existing Scraper**, **Scraper Type** to **AI**, and **Agent Type** to **Map**.
3. Configure using values from Google Sheets:
* **Scraper ID**: `{{ $json.mapScraperId }}`
* **URL**: `{{ $json.mapTargetUrl }}`
* **Include Patterns**: `{{ $json.mapIncludePatterns }}`
* **Exclude Patterns**: `{{ $json.mapExcludePatterns }}`
4. The Map Agent discovers all listing pages on the website.
#### Filter & Limit Listing Pages
1. Add a **Code** node in JavaScript called "Filter & Limit Link".
2. Filter discovered URLs to only listing pages and limit the count:
```javascript
// Configuration
const MAX_URLS = 3; // Change this to limit listing pages
// Get the data from the previous node
const inputData = $input.all();
// Extract URLs from the response
let urls = [];
if (inputData.length > 0 && inputData[0].json.data && inputData[0].json.data.urls) {
urls = inputData[0].json.data.urls;
}
// Filter URLs that contain your listing pattern
const filteredUrls = urls.filter(url =>
url.includes('/cayman-islands-real-estate-listings')
);
// Limit the number of listing pages
const limitedUrls = filteredUrls.slice(0, MAX_URLS);
// Return as separate items for looping
return limitedUrls.map((url, index) => ({
json: {
url: url,
index: index + 1,
totalUrls: limitedUrls.length
}
}));
```
3. Adjust `MAX_URLS` (default: 3) and the filter pattern to match your listing pages.
## Process Listing Pages
Loop through discovered listing pages and extract property URLs using the Listing Agent.
#### Loop Through Listing Pages
1. Add a **Split in Batches** node called "Looping Listing Page url".
2. This processes each listing page URL one at a time.
3. Keep **Reset** unchecked to continue looping.
#### Run the Listing Agent
1. Add the **MrScraper** node inside the loop called "Run listing agent scraper".
2. Set **Resource** to **Scraper Run**, **Operation** to **Run Existing Scraper**, **Scraper Type** to **AI**, and **Agent Type** to **Listing**.
3. Configure using the scraper ID from Google Sheets:
* **Scraper ID**: `{{ $('Get Listing Agent Scraper').item.json.listingScraperId }}`
* **URL**: `{{ $json.url }}`
* **Max Pages**: Set how many result pages to scrape per listing (e.g., 2)
* **Timeout**: 720 seconds
4. This extracts all property URLs from each listing page.
5. Connect this node back to the "Looping Listing Page url" node to continue.
#### Extract All Property URLs
1. Add a **Code** node in Python called "Extract All Url".
2. Parse listing responses to collect all unique property URLs:
```python
items = []
urls = set()
# Loop through ALL input items, not just one
for input_item in _input.all():
payload = input_item.json
# Extract URLs from response data
response = payload.get("data", {}).get("response") or []
for page in response:
listings = page.get("data", {}).get("data") or []
for listing in listings:
url = listing.get("url")
if isinstance(url, str) and url.strip():
urls.add(url)
# Extract the search link
search_link = payload.get("data", {}).get("link")
if isinstance(search_link, str) and search_link.strip():
urls.add(search_link)
# Convert set to list of items
for url in urls:
items.append({"json": {"url": url}})
return items
```
## Extract and Process Property URLs
Extract all property URLs from listing responses and process them with the General Agent.
#### Extract All Property URLs
1. Add a **Code** node in Python called "Extract All Url".
2. Parse listing responses to collect all unique property URLs:
```python
items = []
urls = set()
# Loop through ALL input items, not just one
for input_item in _input.all():
payload = input_item.json
# Extract URLs from response data
response = payload.get("data", {}).get("response") or []
for page in response:
listings = page.get("data", {}).get("data") or []
for listing in listings:
url = listing.get("url")
if isinstance(url, str) and url.strip():
urls.add(url)
# Extract the search link
search_link = payload.get("data", {}).get("link")
if isinstance(search_link, str) and search_link.strip():
urls.add(search_link)
# Convert set to list of items
for url in urls:
items.append({"json": {"url": url}})
return items
```
#### Loop Through Property URLs
1. Add another **Split in Batches** node called "Looping Detail Page url".
2. This processes each property URL one at a time.
3. Keep **Reset** unchecked.
#### Run the General Agent
1. Add the **MrScraper** node inside the second loop called "Run general agent scraper".
2. Set **Resource** to **Scraper Run**, **Operation** to **Run Existing Scraper**, **Scraper Type** to **AI**, and **Agent Type** to **General**.
3. Configure using the scraper ID from Google Sheets:
* **Scraper ID**: `{{ $('Get General Agent Scraper').item.json.generalScraperId }}`
* **URL**: `{{ $json.url }}`
4. This extracts detailed information from each property page.
5. Connect this node back to the "Looping Detail Page url" node to continue.
## Export the Results
Finally, flatten the data, export it to Google Sheets, and send a notification email.
#### Flatten the JSON Data
1. Add a **Code** node in JavaScript called "Flatten Object".
2. Convert all nested JSON into flat structure:
```javascript
function flattenObject(obj, prefix = '', result = {}) {
for (const key in obj) {
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
const newKey = prefix ? `${prefix}_${key}` : key;
const value = obj[key];
if (value === null || value === undefined) {
result[newKey] = null;
} else if (Array.isArray(value)) {
result[newKey] = value.length ? value.join(', ') : null;
} else if (typeof value === 'object' && !(value instanceof Date)) {
flattenObject(value, newKey, result);
} else {
result[newKey] = value;
}
}
return result;
}
const items = $input.all();
const output = items.map(item => {
const flattened = flattenObject(item.json);
return { json: flattened };
});
return output;
```
#### Save to Google Sheets
1. Add a **Google Sheets** node called "Get row(s) in sheet".
2. Select **Append Row** operation.
3. Authenticate with your Google account.
4. Select your destination spreadsheet and sheet (can be different from your configuration sheet).
5. Map the flattened data fields to your columns.
#### Send Email Notification
1. Add a **Gmail** node called "Send a message".
2. Configure:
* **To**: Your email address
* **Subject**: "Multi-Agent Scraping Complete"
* **Message**: Include summary of total properties scraped
3. This notifies you when the entire three-agent workflow completes.
# Alibaba Search Results Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint scrapes product data from Alibaba's search results page using the provided search URL.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# 1688 Search Results Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint scrapes product data from 1688's search results page using the provided search URL.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Coupang PDP Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape a Coupang Product Detail Page (PDP).
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Coupang Review Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint retrieves a Coupang's product reviews.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Coupang Search Results Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint scrapes product data from Coupang's search results page using the provided search URL.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Lazada Search Results Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint scrapes product data from Lazada's search results page using the provided search URL.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Lazada PDP Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape a Lazada Product Detail Page (PDP).
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Shein PDP Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape a Shein Product Detail Page (PDP).
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Naver PDP Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape Naver coupon data and product details.
# Naver Search Results Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint scrapes product data from Naver Shopping's search results page using the provided search URL.
# Shopee Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape a shopee scraper.
Please [contact us](mailto:support@mrscraper.com) to get a token.
# TikTok PDP Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape a TikTok Product Detail Page.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# TikTok Shop Search Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to search for products listed in TikTok Shop.
Please [contact us](mailto:support@mrscraper.com) to get a token.
# Walmart PDP Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape a Walmart Product Detail Page (PDP).
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Walmart Review Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape a Walmart Product Review.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Get Google SERP Async Result
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint returns the result of an asynchronous Google Search scraping task. While the task is still running the response reports a `PENDING` status, and the scraped data is returned once the status becomes `COMPLETED`.
* Use the Async Scraper API Server (`https://async.scraper.mrscraper.com`) host when calling this endpoint.
* You can get the `{taskId}` parameter from the [Google SERP Scraper (Async)](/docs/api/seo/google/async) endpoint.
* The shape of `data` depends on the `format` used when the task was created: `json` returns the parsed results, `html` returns the raw results page.
# Google SERP Scraper (Async)
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint queues a Google Search scraping task and immediately returns a task ID. Fetch the result with the Get SERP Async Result endpoint, or let it be delivered to your callback URL once the task completes.
* Use the Async Scraper API Server (`https://async.scraper.mrscraper.com`) host when calling this endpoint.
* Pass the returned `data.taskId` to the [Get Google SERP Async Result](/docs/api/seo/google/async-result) endpoint to retrieve the scraped data.
* When `callbackUrl` is set, the result is sent to that URL as soon as the task completes, so you do not have to poll for it.
# Google SERP Scraper (Sync)
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint scrapes Google Search results in real time and returns either the parsed results as JSON or the raw HTML of the results page.
* Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
* Set `format` to `json` for parsed results, or to `html` to receive the raw results page.
* Set `renderJs` to `true` to wait for JavaScript rendering, which makes sure the AI overview is loaded.
* For long-running or high-volume queries, use the [Google SERP Scraper (Async)](/docs/api/seo/google/async) endpoint instead.
# Booking.com Hotel Rates Detail Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape hotel room rates and availability data from Booking.com.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Booking.com Hotel Reviews Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape hotel reviews from Booking.com.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Expedia Hotel Rates and Detail Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape hotel room rates and availability data from Expedia.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Expedia Hotel Details Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape hotel details from Expedia.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Expedia Hotel Reviews Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape hotel reviews from Expedia.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Expedia Hotel Search Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape the hotel search result data from Expedia.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Hotels Hotel Rates and Details Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape hotel rates and availability from Hotels.com.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Hotels Hotel Reviews Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape hotel reviews from Hotels.com.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Scrape Tiket Flight Data Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape flight availability and pricing from Tiket.com.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Tiket Hotel Data Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape hotel availability, pricing, and room details from Tiket.com.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Trip Hotel Rates and Details Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape hotel rates and availability from Trip.com.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Trip Flight Data Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape flight availability and pricing from Trip.com.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Trip Hotel Data Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape hotel availability, pricing, and room details from Trip.com.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Trip Hotel Reviews Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape hotel reviews from Trip.com.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Agoda Hotel Data Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape hotel availability, pricing, and room details from Agoda.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Agoda Hotel Reviews Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape hotel reviews from Agoda.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Get Proxy Requests Bandwidth
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint retrieves the total bandwidth usage aggregated per proxy username within a given date range.
* Use the V3 Platform API Server (`https://api.app.mrscraper.com`) host when calling this endpoint.
# Get Analytic Statuses
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint retrieves scrape status counts for a specified domain within a given date range. You can optionally filter the results by action and API Token name.
* Use the V3 Platform API Server (`https://api.app.mrscraper.com`) host when calling this endpoint.
* This endpoint uses UTC by default. If you want to query data in another timezone, convert the `startDate` and `endDate` values to their UTC equivalents before making the request.
# Trip Advisor Hotel Reviews Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to scrape hotel reviews from Trip Advisor.
* Use the TVLK Scraper API Server (`https://tvlk.mrscraper.com`) host when calling this endpoint.
* Please [contact us](mailto:support@mrscraper.com) to get a token.
# Verify API Token
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
Verify your API token and retrieve subscription account information including token usage, limits, and billing details.
Use the V3 Platform API Server (`https://api.app.mrscraper.com`) host when calling this endpoint.
# Get All Results
This endpoint returns all scraping results, including data, status, token usage, and file paths, with options for sorting, filtering, and date ranges.
Use the V3 Platform API Server (`https://api.app.mrscraper.com`) host when calling this endpoint.
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
# Get a Detailed Result
This endpoint retrieves detailed information for a specific scraping result by its unique identifier.
* Use the V3 Platform API Server (`https://api.app.mrscraper.com`) host when calling this endpoint.
* You can get `{id}` parameter from the [Get All Results](/docs/api/v3/result/all) endpoint.
* The structure of `data.data` in the scrape result varies depending on the agent type and whether the request is single or bulk. For detailed response formats, see [AI Response](/docs/api/v3/scraper/ai-response).
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
# Create and Run AI Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
Create a new AI scraper with natural language instructions. Use this for the first-time scraping of a website. Save the scraperId from the response to re-run the scraper later.
* Use the V3 Platform API Server (`https://api.app.mrscraper.com`) host when calling this endpoint.
* Each AI Scraper agent returns a unique response format. For details, see [here](/docs/api/v3/scraper/ai-response).
The initial AI chat does not return the final results. It only generates example code and responses. To get the full output, you’ll need to use the rerun API.
# Bulk Rerun AI Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
Execute the same scraper configuration across multiple URLs simultaneously. This is an asynchronous operation, use the `bulkResultId` to poll for results. Reruns leverage previously cached results, which can reduce token consumption and improve execution time.
* Use the V3 Platform API Server (`https://api.app.mrscraper.com`) host when calling this endpoint.
* The response from this endpoint may vary based on the scraper's agent. For more details, read the [AI Scraper Response](/docs/api/v3/scraper/ai-response) page.
# Rerun an AI Scraper
This endpoint reruns an existing AI scraper using the specified `scraperId` and `url`. Reruns leverage previously cached results, which can reduce token consumption and improve execution time.
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
* Use the V3 Platform API Server (`https://api.app.mrscraper.com`) host when calling this endpoint.
* Each AI Scraper agent returns a unique response format. For details, see [here](/docs/api/v3/scraper/ai-response).
* The parameters below can be modified only for the **AI Map Agent Scraper**:
* `maxDepth`
* `maxPages`
* `limit`
* `includePatterns`
* `excludePatterns`
# AI Scraper Response
The AI Scraper API returns responses with a consistent wrapper structure across all scraping operations. While the wrapper remains the same, the `data.data` field contains agent-specific data optimized for each scraping type.
## Standard Response Wrapper
Every API response follows this structure:
```json
{
"message": "Successful operation!",
"data": {
"id": "result-unique-identifier",
"createdAt": "2026-03-06T05:30:44.642Z",
"userId": "user-id",
"scraperId": "scraper-id",
"type": "AI",
"url": "https://example.com",
"status": "Finished",
"error": "",
"tokenUsage": 5,
"runtime": 0,
"data": {
// Agent-specific data structure (see below)
},
"htmlPath": "...",
"htmlContent": "...",
"recordingPath": null,
"screenshotPath": "...",
"dataPath": null
}
}
```
### Response Fields
| Field | Type | Description |
| --------------------- | ------ | ----------------------------------------------------- |
| `message` | string | Operation status message |
| `data.id` | string | Unique identifier for this result |
| `data.createdAt` | string | ISO 8601 timestamp when the operation started |
| `data.userId` | string | Your user identifier |
| `data.scraperId` | string | Identifier of the scraper used |
| `data.type` | string | Agent type used for scraping |
| `data.url` | string | Target URL that was scraped |
| `data.status` | string | Operation status (`Finished`, `Processing`, `Failed`) |
| `data.error` | string | Error message if the operation failed |
| `data.tokenUsage` | number | Number of tokens consumed by this operation |
| `data.runtime` | number | Total runtime of the scraping operation in seconds |
| `data.data` | object | Extracted data (structure varies by agent type) |
| `data.htmlPath` | string | Path to the saved HTML content |
| `data.htmlContent` | string | The actual HTML content of the scraped page |
| `data.recordingPath` | string | Path to the scraping session recording (if available) |
| `data.screenshotPath` | string | Path to the page screenshot |
| `data.dataPath` | string | Path to the raw data file (if available) |
## Agent-Specific Response Formats
The `data.data` field structure varies depending on which agent you use. Each agent optimizes the data format for its specific use case.
### General Agent
The General Agent provides two response formats depending on the page type you're scraping.
#### General Table Response Format
General agent returns a dictionary containing an array of structured items when scraping listing pages with multiple items (e.g., product listings, search results, directory pages)
```json Example
{
"books": [
{
"price": "£51.77",
"title": "A Light in the Attic"
},
{
"price": "£53.74",
"title": "Tipping the Velvet"
},
{
"price": "£50.10",
"title": "Soumission"
}
]
}
```
#### General Detail Response Format
General agent returns A flat dictionary with all relevant fields about a single item when scraping individual item pages with comprehensive information (e.g., product details, profile pages, article pages)
```json Example
{
"price": "£51.77",
"title": "A Light in the Attic",
"image_url": "../../media/cache/fe/72/fe72f0532301ec28892ae79a629a293c.jpg",
"description": "It's hard to imagine a world without A Light in the Attic. This now-classic collection of poetry and drawings from Shel Silverstein celebrates its 20th anniversary with this special edition...",
"availability": "In stock (22 available)",
"product_information": {
"UPC": "a897fe39b1053632",
"Product Type": "Books",
"Price (excl. tax)": "£51.77",
"Price (incl. tax)": "£51.77",
"Tax": "£0.00",
"Availability": "In stock (22 available)",
"Number of reviews": 0
}
}
```
### Listing Agent
Listing agent returns an array of page objects, each containing pagination info and extracted data from the page.
```json Example
{
"response": [
{
"page_num": 0,
"data": {
"mode": "direct",
"pagination": {
"current_page": 1,
"total_pages": 50
},
"products": [
{
"title": "Product Name",
"price": "£XX.XX",
"availability": "In stock"
},
{
"title": "Another Product",
"price": "£YY.YY",
"availability": "In stock"
}
],
"product_count": 20,
"__counts__": {
"products": 20
}
},
"total_items": 20,
"next_found": true
},
{
"page_num": 1,
"data": {
"mode": "direct",
"pagination": {
"current_page": 2,
"total_pages": 50
},
"products": [
{
"title": "Product Name Page 2",
"price": "£ZZ.ZZ",
"availability": "In stock"
}
],
"product_count": 20,
"__counts__": {
"products": 20
}
},
"total_items": 20,
"next_found": true
}
],
"link": "https://books.toscrape.com/"
}
```
### Map Agent
Map agent returns a list of all discovered URLs with a total count.
```json Example
{
"count": 581,
"urls": [
"https://books.toscrape.com",
"https://books.toscrape.com/catalogue/10-day-green-smoothie-cleanse-lose-up-to-15-pounds-in-10-days_581/index.html",
"https://books.toscrape.com/catalogue/1000-places-to-see-before-you-die_1/index.html",
"https://books.toscrape.com/catalogue/1491-new-revelations-of-the-americas-before-columbus_650/index.html"
]
}
```
## Bulk Scraping Response
Bulk scraping returns aggregated results for multiple URLs in a single operation. The response keeps the same top-level wrapper, while `data.data` includes merged extraction output, per-URL statuses, and a summary.
```json Example
{
"mergedData": [
{
"products": [
{
"price": "£51.77",
"title": "A Light in the Attic",
"availability": "In stock"
}
],
"page_title": "A Light in the Attic",
"total_results": null
},
{
"products": [
{
"price": "£53.74",
"title": "Tipping the Velvet",
"availability": "In stock (20 available)"
}
],
"page_title": "Tipping the Velvet",
"total_results": null
}
],
"urlDetails": [
{
"url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"status": "Finished",
"error": ""
},
{
"url": "https://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html",
"status": "Finished",
"error": ""
}
],
"summary": {
"totalUrls": 2,
"successfulUrls": 2,
"failedUrls": 0,
"scrapedCount": 2,
"totalTokenUsage": 20,
"estimatedFinishAt": null
}
}
```
### Bulk Data Fields
| Field | Type | Description |
| --------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------- |
| `mergedData` | array | Combined extracted output grouped by processed page. The exact object shape depends on your prompt and target pages. |
| `urlDetails` | array | Per-URL execution result with status and error details for each submitted URL. |
| `summary.totalUrls` | number | Total number of URLs requested in the bulk job. |
| `summary.successfulUrls` | number | Number of URLs completed successfully. |
| `summary.failedUrls` | number | Number of URLs that failed. |
| `summary.scrapedCount` | number | Number of pages with extracted data. |
| `summary.totalTokenUsage` | number | Total token usage across all URLs in the bulk job. |
| `summary.estimatedFinishAt` | string | Estimated completion timestamp for running jobs. `null` when finished. |
## Response Status Values
The `data.status` field indicates the current state of your scraping operation:
| Status | Description |
| ------------ | -------------------------------------------------------------- |
| `Finished` | Scraping completed successfully |
| `Processing` | Scraping is currently in progress |
| `Failed` | Scraping encountered an error (check `data.error` for details) |
# Cancel Bulk Scraping by Result ID
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
Cancel a bulk scraping job using the bulk result ID returned from the bulk rerun response.
Use the V3 Platform API Server (`https://api.app.mrscraper.com`) host when calling this endpoint.
# Cancel Bulk Scraping by Scraper ID
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
Cancel pending URLs from a bulk scraper job by scraper ID.
Use the V3 Platform API Server (`https://api.app.mrscraper.com`) host when calling this endpoint.
# Self-Heal a Manual Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
Ask the AI to repair the current workflow of a manual scraper. Use it when a scraper starts returning empty or partial data because the target website changed its markup.
The scraper's saved workflow is replaced **only** when a valid workflow is returned, so a failed repair leaves your existing configuration untouched. Check `data.workflowUpdated` in the response to confirm whether the workflow actually changed.
Use the V3 Platform API Server (`https://api.app.mrscraper.com`) host when calling this endpoint.
You can copy a ready-made request with your scraper ID and token from the scraper's **⋮ → Self-Heal API Access** menu in the dashboard. See [Self-Healing](/docs/features/manual-scraper/self-healing) for the full feature guide.
# Bulk Rerun Manual Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
Execute the same scraper configuration across multiple URLs simultaneously. This is an asynchronous operation, use the `bulkResultId` to poll for results. Reruns leverage previously cached results, which can reduce token consumption and improve execution time.
Use the V3 Platform API Server (`https://api.app.mrscraper.com`) host when calling this endpoint.
# Rerun a Manual Scraper
This endpoint reruns an existing manual scraper using the specified `scraperId` and `url`. Reruns leverage previously cached results, which can reduce token consumption and improve execution time.
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
Use the V3 Platform API Server (`https://api.app.mrscraper.com`) host when calling this endpoint.
# Web Unblocker
This endpoint scrapes a target URL with Unblocker feature that supports browser rendering, geo-targeting via proxy, and waiting for specific DOM selectors before extracting content.
Use the Playground API Server (`https://api.mrscraper.com`) host when calling this endpoint.
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
# Skyscanner Flight Data Scraper
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
This endpoint allows you to fetch flight search results from Skyscanner.
Use the Sync Scraper API Server (`https://sync.scraper.mrscraper.com`) host when calling this endpoint.
# Multi-Agent Flow
MrScraper's **Multi-Agent Flow** allows you to combine multiple AI scraper agents into a seamless workflow for extracting comprehensive data from entire websites. By chaining together the **Map Agent**, **Listing Agent**, and **General Agent**, you can build scalable scraping systems that handle everything from URL discovery to detailed product data extraction.
**Perfect for large-scale e-commerce scraping, marketplace data collection, and comprehensive website data extraction.**
## Available Multi-Agent Workflows
MrScraper supports two primary multi-agent workflows depending on your starting point:
| Workflow | Starting Point | Use Case |
| -------------------------------------------------------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| [**Map → Listing → General**](/docs/features/ai-scraper/multi-agent-flow/single) | Single seed URL (homepage, domain root) | When you only have the website's main URL and want to extract all product details from the entire site |
| [**Listing → General**](/docs/features/ai-scraper/multi-agent-flow/list) | Specific listing page URL(s) | When you already know which category/listing pages to scrape and want detailed product information |
## Comparison: When to Use Each Workflow
| Criteria | [**Map → Listing → General**](/docs/features/ai-scraper/multi-agent-flow/single) | [**Listing → General**](/docs/features/ai-scraper/multi-agent-flow/list) |
| ------------------ | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| **Starting Point** | Single seed URL only | Known listing page URLs |
| **Use Case** | Full website scraping | Targeted category scraping |
| **Discovery** | Automatic URL discovery | Manual URL input |
| **Execution Time** | Longer (3 steps) | Faster (2 steps) |
| **Data Coverage** | Complete site coverage | Specific sections only |
| **Best For** | New site exploration | Recurring scraping jobs |
## Limitations
MrScraper provides the **API infrastructure only**. You are responsible for:
* **Orchestrating the workflow**: Building the logic to chain agents together
* **Managing the data pipeline**: Handling data between agent calls
* **Error handling**: Implementing retry logic and failure recovery
* **Rate limiting**: Controlling request frequency to avoid blocks
* **Data storage**: Saving and organizing extracted data
* **Monitoring**: Tracking scraping progress and success rates
MrScraper does **not** provide:
* Pre-built workflow automation
* Scheduled scraping jobs
* Automatic data pipelines
* Built-in data storage solutions
## Tips and Best Practices
Follow these best practices for successful multi-agent workflows:
1. **Start Small, Then Scale** - Test with a single URL before processing thousands, **validate data quality** from each agent before moving to the next step, and **monitor API usage** to stay within your plan limits.
2. **Implement Robust Error Handling** - Set up retry logic with exponential backoff, **log failed URLs** separately for review, handle timeouts gracefully, and implement maximum retry limits to prevent infinite loops.
3. **Filter URLs Intelligently** - Include relevant patterns like `/product/`, `/item/`, `/details/`, **exclude non-data pages** like `/account/`, `/login/`, `/cart/`, and **remove static assets** like `.jpg`, `.png`, `.css`, `.js` files.
4. **Batch Your Requests** - Process URLs in batches of 10-50 at a time, **add delays between batches** to respect rate limits, save results after each batch to prevent data loss, and adjust batch size based on success rates.
5. **Track Progress and Resume Capability** - Save progress regularly every 10-20 items, **store the last processed URL**, keep a list of failed URLs for retry, and implement checkpoint system to resume interrupted workflows.
6. **Use Appropriate Modes** - Start with **Cheap Mode** for testing and validation, switch to **Super Mode** when encountering bot protection, consistent blocking issues, or for critical production workflows where failure is costly.
7. **Monitor and Optimize Costs** - Track API calls per agent type, **calculate estimated costs** before running large workflows, review usage regularly, and balance cost vs. success rate based on your data value.
# Two Agents Flow
import { Step, Steps } from 'fumadocs-ui/components/steps';
In this workflow, you’ll use Listing Agent → General Agent.
This flow is more direct and ideal when you already know which listing pages you want to scrape.
## When to Use This Workflow
Use this workflow when you:
* **Already have specific listing page URLs** you want to scrape
* **Know the exact categories** you're interested in
* **Want to scrape targeted sections** rather than entire websites
* **Need faster execution** by skipping the discovery phase
## How It Works
### Scrape Listing Pages
Use Listing Agent on your target category/listing URLs to extract product information and URLs.
### Extract Detailed Data
Use General Agent on each product URL to get comprehensive specifications and details.
## Step-by-Step Process
### Scrape Listing Page with Listing Agent
{/* #no-rag */}
```json
// Input
{
"url": "https://www.walmart.com/browse/electronics/laptops/3944_3951_132960",
"agent": "listing",
"prompt": "Extract all laptop names, prices, ratings, and detail page URLs"
}
// Output (sample)
{
"response": [
{
"page_num": 0,
"data": {
"mode": "direct",
"data": [
{
"id": "1",
"name": "HP 15.6\" Laptop, Intel Core i5",
"price": "$499.00",
"rating": "4.3",
"url": "https://www.walmart.com/ip/123456789"
},
{
"id": "2",
"name": "Dell Inspiron 15 3000",
"price": "$379.99",
"rating": "4.1",
"url": "https://www.walmart.com/ip/987654321"
}
]
}
}
]
}
```
{/* #no-rag */}
### Step 2: Extract Detailed Data with General Agent
{/* #no-rag */}
```json
// Input (for each URL)
{
"url": "https://www.walmart.com/ip/123456789",
"agent": "general",
"prompt": "Extract laptop specifications including processor, RAM, storage, display, graphics, ports, battery life, weight, and full description"
}
// Output (sample)
{
"data": {
"id": "1",
"name": "HP 15.6\" Laptop, Intel Core i5-1235U, 8GB RAM, 256GB SSD",
"price": "$499.00",
"rating": "4.3",
"reviews_count": "1,247",
"specifications": {
"processor": "Intel Core i5-1235U (12th Gen)",
"ram": "8GB DDR4",
"storage": "256GB PCIe NVMe SSD",
"display": "15.6\" FHD (1920 x 1080) Anti-Glare",
"graphics": "Intel Iris Xe Graphics",
"battery": "Up to 8 hours",
"weight": "3.75 lbs",
"operating_system": "Windows 11 Home"
},
"description": "Stay productive and entertained with this HP laptop...",
"features": [
"Fast processor for multitasking",
"Full HD display",
"Long battery life"
]
}
}
```
{/* #no-rag */}
# Three Agents Flow
import { Step, Steps } from 'fumadocs-ui/components/steps';
In this workflow, you’ll move through Map Agent → Listing Agent → General Agent.
This is the most complete approach for extracting data from an entire website when all you have is the main domain URL.
## When to Use This Workflow
Use this workflow when you:
* **Only have the seed URL** (e.g., `https://example.com`) and want to discover all available products
* **Need to scrape an entire e-commerce site** without manually finding category pages
* **Want comprehensive data coverage** across all sections of a website
* **Don't know the site structure** or specific listing page URLs
## How It Works
### Discover URLs with Map Agent
Input the seed URL to discover all pages on the website.
### Filter Listing URLs
Identify and filter URLs that contain product listings or categories.
### Extract Listings with Listing Agent
Scrape all listing pages to collect product URLs and basic information.
### Extract Details with General Agent
Use General Agent on each product URL to get comprehensive data.
## Step-by-Step Process
### Discover All URLs with Map Agent
Start by using the Map Agent to discover every URL on the website:
{/* #no-rag */}
```json
// Input
{
"url": "https://books.toscrape.com",
"agent": "map"
}
// Output (sample)
{
"urls": [
"https://books.toscrape.com",
"https://books.toscrape.com/catalogue/category/books_1/index.html",
"https://books.toscrape.com/catalogue/category/books/travel_2/index.html",
"https://books.toscrape.com/catalogue/category/books/mystery_3/index.html",
"https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
"https://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html"
],
"count": 1053
}
```
{/* #no-rag */}
### Filter Listing URLs
Filter the discovered URLs to identify only listing/category pages. You can do this by:
* **URL pattern matching**: Look for patterns like `/category/`, `/browse/`, `/search/`
* **URL structure analysis**: Identify URLs that typically contain multiple products
* **Manual filtering**: Review and select relevant category pages
{/* #no-rag */}
```javascript
// Example filtering logic
const listingUrls = allUrls.filter(url => {
return url.includes('/category/') ||
url.includes('/catalogue/category/') ||
(url.match(/\/page-\d+/) !== null);
});
// Filtered Result
[
"https://books.toscrape.com/catalogue/category/books/travel_2/index.html",
"https://books.toscrape.com/catalogue/category/books/mystery_3/index.html",
"https://books.toscrape.com/catalogue/category/books/fiction_10/index.html"
]
```
{/* #no-rag */}
### Extract Listings with Listing Agent
Use the Listing Agent on each filtered URL to get all product listings and their detail page URLs:
{/* #no-rag */}
```json
// Input
{
"url": "https://books.toscrape.com/catalogue/category/books/travel_2/index.html",
"agent": "listing",
"prompt": "Extract all book titles, prices, ratings, availability, and detail page URLs"
}
// Output (sample)
{
"response": [
{
"page_num": 0,
"data": {
"mode": "direct",
"data": [
{
"id": "1",
"title": "It's Only the Himalayas",
"price": "£45.17",
"rating": "2",
"availability": "In stock",
"url": "https://books.toscrape.com/catalogue/its-only-the-himalayas_981/index.html"
},
{
"id": "2",
"title": "Full Moon over Noah's Ark",
"price": "£49.43",
"rating": "4",
"availability": "In stock",
"url": "https://books.toscrape.com/catalogue/full-moon-over-noahs-ark_811/index.html"
}
]
}
}
]
}
```
{/* #no-rag */}
### Extract Detailed Data with General Agent
Loop through each detail page URL and use the General Agent to extract comprehensive product information:
{/* #no-rag */}
```json
// Input (for each URL from Listing Agent)
{
"url": "https://books.toscrape.com/catalogue/its-only-the-himalayas_981/index.html",
"agent": "general",
"prompt": "Extract book title, price, rating, availability, product description, UPC, number of reviews, and category"
}
// Output (sample)
{
"data": {
"id": "1",
"title": "It's Only the Himalayas",
"price": "£45.17",
"rating": "2",
"availability": "In stock (19 available)",
"description": "Wherever you go, whatever you do, just don't do anything stupid. ' (Tess' Nan)Tess, an unlucky-in-love city girl, has...",
"upc": "a22124811bfa8350",
"reviews_count": "0",
"category": "Travel",
"product_type": "Books",
"tax": "£0.00"
}
}
```
{/* #no-rag */}
# Real-World Use Cases
import { Step, Steps } from 'fumadocs-ui/components/steps';
## Use Case 1: Complete E-Commerce Catalog Scraping
**Scenario**: Extract all product data from an online bookstore starting with only the homepage URL
**Workflow Process:**
### Discover Site Structure
Use Map Agent on `https://bookstore.com` to discover all URLs including category pages, product pages, and other sections.
### Filter Category URLs
Identify and extract only category/listing page URLs (e.g., URLs containing `/category/`, `/books/`, `/genre/`). Exclude non-relevant pages like account, cart, and legal pages.
### Extract All Product URLs
Use Listing Agent on each category page to collect all book listings with basic info (title, price, rating) and their detail page URLs.
### Scrape Complete Details
Use General Agent on each product URL to extract comprehensive information including full description, specifications, author details, ISBN, reviews, and availability.
### Aggregate and Save
Combine all extracted data into a unified dataset and export as JSON or CSV for analysis or integration.
Complete catalog of all books with detailed information from the entire website.
## Use Case 2: Multi-Category Product Comparison
**Scenario**: Compare laptop specifications across multiple electronics retailers
**Workflow Process:**
### Prepare Target URLs
Compile a list of specific laptop category URLs from different retailers (e.g., `retailer1.com/laptops`, `retailer2.com/computers/notebooks`).
### Extract Product Listings
Use Listing Agent on each retailer's laptop category page to gather all available laptop listings with prices and detail URLs.
### Collect Detailed Specifications
Use General Agent on each laptop's detail page to extract complete specifications: processor, RAM, storage, display, graphics, battery life, and weight.
### Normalize and Compare
Standardize data formats across retailers (e.g., convert all prices to same currency, normalize specification names) for accurate comparison.
### Generate Insights
Analyze price ranges, identify best value products, compare specifications across brands, and create comparison reports.
Comprehensive comparison database enabling price analysis and specification matching across multiple retailers.
## Use Case 3: Real Estate Market Analysis
**Scenario**: Analyze property listings across an entire metropolitan area
**Workflow Process:**
### Discover All Locations
Use Map Agent on the real estate site to find all neighborhood, district, and area listing pages.
### Extract Property Listings
Use Listing Agent on each location page to collect property cards with address, price, bedrooms, bathrooms, and property URLs.
### Get Property Details
Use General Agent to extract complete information: full description, amenities, lot size, year built, property tax, HOA fees, and agent contact.
### Geographic Analysis
Group properties by location, calculate average prices per neighborhood, identify price trends, and map property distribution.
Complete market analysis with pricing trends, property distribution, and neighborhood insights.