` | `US` | Query `geoCode` | Proxy country code. |
| `--proxy-country ` | omitted | Query `proxyCountry` | Compatibility country option. |
| `--no-use-proxy` | proxy allowed | Query `useProxy=false` | Does not use the service's configured proxy. |
| `--proxy ` | omitted | Query `proxy` | Custom proxy as `username:password@host:port`. |
| `--wait-for-selector ` | omitted | Query `waitForSelector` | Waits for a CSS selector. |
| `--wait-until ` | omitted | Query `waitUntil` | Waits for a page lifecycle event, such as `domcontentloaded`. |
| `--home-page` | off | Query `warmStart=true` | Visits the site root before loading the target page. |
| `--block-resources` | off | Query `blockResources=true` | Blocks images, CSS, and fonts. |
| `--bypass-proxy` | off | Query `bypassProxy=true` | Enables the proxy-bypass behavior. |
| `--cookie-jar ` | omitted | Query `cookieJar` | Cookie configuration string. |
| `--headers ` | omitted | Query `headers` | Target page request headers as a JSON object. |
| `--max-retries ` | `3` | Query `maxRetries` | Maximum retries; zero disables retries. |
| `--token-cap ` | omitted | Query `tokenCap` | Running token total that stops further retries. The initial request always runs. |
| `--timeout ` | `120` | Query `timeout` | Page timeout from 1 to 300 seconds. The command allows an additional 30 seconds to receive the response. |
| `--stream` / `--no-stream` | API default | Query `stream` | Sets the streaming preference; the CLI still prints one JSON response. |
| `--discard-token-secret ` | omitted | Header `x-discard-token-secret` | Optional upstream header. |
| `--save ` | omitted | CLI output | Saves `data` to a file: HTML as text, combined outputs as JSON. |
| `--token ` | configured credential | Request headers | Overrides authentication for this command. |
Web Fetching 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.
### `webSearch`
`webSearch` searches the web to retrieve real-time search results, including
relevant website URLs, titles, and descriptions.
```bash
mrscraper webSearch "e-menessaptieka.lv linkedin" --country us --num-results 10
mrscraper webSearch "web scraping best practices"
```
The CLI sends this request:
```bash
curl --location 'https://api.mrscraper.com' \
--header 'x-api-token: {MRSCRAPER_API_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"action": "websearch",
"query": "e-menessaptieka.lv linkedin",
"country": "us",
"numResults": 10
}'
```
`data` contains `success`, `message`, and `data`. Each item in `data.data` has
`rank`, `title`, `url`, `description`, and `source`.
#### `webSearch` parameters
| CLI parameter | Default | API mapping | Behavior |
| --------------------- | --------------------- | ----------------- | ------------------------------------------------------------------------------------- |
| `` | required | Body `query` | The search query. |
| `--country ` | omitted | Body `country` | Country code for localized results, such as `us`. Omitted to use the service default. |
| `--num-results ` | `10` | Body `numResults` | Number of results, an integer from 10 to 100. |
| `--timeout ` | `600` | CLI request | Sets the HTTP request deadline. Not sent in the API body. |
| `--token ` | configured credential | Request headers | Overrides authentication for this command. |
### `account`
`account` checks the remote account's identity, subscription, token quota,
and rate limits. It calls:
```text
GET https://api.app.mrscraper.com/api/v1/subscription-accounts
```
```bash
mrscraper account
mrscraper account --json
mrscraper account --pretty --no-color
```
Interactive terminals show a dashboard by default; redirected output is JSON.
API keys and billing identifiers are excluded, and remaining tokens are
clamped to zero for over-quota accounts.
```json
{
"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
}
}
},
"headers": {}
}
```
#### `account` parameters
| CLI parameter | Default | API mapping | Behavior |
| --------------------- | --------------------- | --------------- | ---------------------------------------------------------------- |
| `--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. |
| `--timeout ` | `30` | CLI request | HTTP request timeout. |
| `--token ` | configured credential | Request headers | Overrides authentication for this command. |
## Migrating from earlier versions
### From 0.5.x
Version 0.6.0 returns to three public operations: `scraperAPI`, `webSearch`,
and `account`. The 0.5.x format-specific commands and package exports
(`scraperHtml`, `scraperMarkdown`, `getScreenshot`, `scraperJson`,
`scraperMultiplePage`, `scraperSitemap`, `scrapeBrand`, `getBrand`, and their
snake-case aliases) are no longer public.
| 0.5.x | 0.6.0 |
| ------------------------------------------- | --------------------------------------------------------- |
| `mrscraper scraperHtml ` | `mrscraper scraperAPI ` |
| `mrscraper scraperMarkdown ` | `mrscraper scraperAPI --no-html --markdown` |
| `mrscraper getScreenshot ` | `mrscraper scraperAPI --no-html --screenshot` |
| `mrscraper webSearch --region us` | `mrscraper webSearch --country us` |
| `scraperMarkdown({ token, url })` | `scraperAPI({ token, url, html: false, markdown: true })` |
| `webSearch({ token, query, region: "us" })` | `webSearch({ token, query, country: "us" })` |
### From 0.4.x
* **`scraperAPI`** now sends a `GET` request with every option in the query
string, and adds `--wait-until` and `--save`. Requesting only HTML returns a
string in `data`, and screenshots are returned as base64 in a JSON object.
* **`webSearch`** now calls `https://api.mrscraper.com` with
`action: "websearch"` and accepts `--country` and `--num-results` (10–100).
The `--region`, `--language`, `--page`, `--format`, `--raw`, `--render-js`,
and `--client-timeout` flags and search URL input are removed, as are the
`raw`, `format`, `region`, `language`, `page`, and `renderJs` programmatic
options and the `url` input alias.
* The `MRSCRAPER_SYNC_BASE_URL` setting and the `SYNC_SCRAPER_BASE_URL` export
are removed.
* **`account`** is unchanged.
### Removed commands
Version 0.4.0 removed the commands below. The CLI exposes only `scraperAPI`,
`webSearch`, and `account` as data commands; `login`, `logout`, `auth`, `init`,
and `setup` remain.
| Previous command | Replacement |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `fetch` | `scraperAPI`; `--super-mode` is now `--super`, and browser rendering is automatic unless set. |
| `serp` | `webSearch`. |
| `status` | `account`; domain analytics are no longer included. |
| `scrape`, `rerun`, `results`, `result` | Manage AI scrapers, reruns, and stored results in the [MrScraper dashboard](https://app.mrscraper.com). |
# 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,
FileSearch,
GlobeLock,
LayoutDashboard,
Search,
Server,
} from "lucide-react";
MrScraper MCP is the official Model Context Protocol server for MrScraper.
It connects AI clients to web page retrieval, web search, and your account
usage.
[MrScraper MCP server source code on GitHub](https://github.com/mrscraper-com/mrscraper-mcp)
· [Install the @mrscraper/mcp npm package](https://www.npmjs.com/package/@mrscraper/mcp)
The server exposes three tools:
} href="#scraperapi">
Retrieve a known page as HTML, Markdown, a screenshot, or a combination.
} href="#websearch">
Search the web and get ranked results with titles, links, and descriptions.
} href="#status">
Check subscription status, token usage, remaining tokens, and limits.
Use the hosted Streamable HTTP endpoint for a managed connection, or run the
published MCP package locally through Streamable HTTP or stdio.
This page documents `@mrscraper/mcp` version **0.3.0**, which moved `webSearch` to MrScraper's new web search endpoint. Earlier versions exposed `fetch`, `scrape`, `serp`, `rerun`, `results`, and `result`. See [Migration from the previous tool set](#migration-from-the-previous-tool-set).
## Capabilities
}>
Retrieve a known URL with automatic browser fallback, real-device routing,
proxy controls, selector waiting, and retry limits.
}>
Search the web for ranked results, for a chosen country and up to 100
results at a time.
}>
Read the subscription, token limit, token usage, remaining tokens, and rate
limit.
}>
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.
}>
Render search results and an account usage meter in hosts that support MCP
Apps.
## 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 `scraperAPI`, `webSearch`, and `status`.
## 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 scraperAPI, webSearch, and status 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 | OAuth 2.1 access token, or `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. A tool called without its
required scope returns `403 insufficient_scope`, and your client can offer to
grant the missing permission.
| Scope | Tools |
| -------------- | ------------ |
| `scrape:write` | `scraperAPI` |
| `scrape:read` | `webSearch` |
| `account:read` | `status` |
API keys remain supported for clients without OAuth and carry full account
authority, so no scope is enforced against them. 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` | — | Alternative stdio credential, also used by the Python SDK. |
| `MRSCRAPER_HTTP_AUTH` | `1` | Enables HTTP bearer verification. |
| `MRSCRAPER_OAUTH` | `1` | Accepts OAuth 2.1 access tokens alongside API keys. |
| `MRSCRAPER_MCP_PUBLIC_URL` | `https://mcp.mrscraper.com` | Public origin; `/mcp` is the required token audience. |
| `MRSCRAPER_OAUTH_ISSUER` | `https://api.app.mrscraper.com` | Authorization server issuer. |
| `MRSCRAPER_OAUTH_JWKS_URL` | `/.well-known/jwks.json` | Key set used to verify access tokens. |
| `MRSCRAPER_ALLOWED_ORIGINS` | — | Comma-separated browser origins allowed to call the HTTP server. |
| `MRSCRAPER_API_BASE_URL` | MrScraper platform API | Platform endpoint override used by `status`. |
| `MRSCRAPER_FETCH_BASE_URL` | MrScraper Scraper API | Endpoint override used by `scraperAPI` and `webSearch`. |
| `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 is redacted, and network errors redact signed
query credentials.
* `status` copies only account usage fields, so the API key and billing
identifiers in the account record never reach the client.
* Browser-origin requests are accepted from trusted local origins, from
`claude.ai` and `chatgpt.com`, and from 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 | HTML, Markdown, a screenshot, or a combination | `scraperAPI` |
| A topic or keyword | Search result discovery | `webSearch` |
| An account | Plan, token usage, and remaining tokens | `status` |
A discovery workflow commonly uses `webSearch` first, followed by `scraperAPI`
for the pages that will inform the answer. Agents produce summaries, tables,
and structured output from the retrieved content.
### Migration from the previous tool set
| Previous tool | Replacement |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `fetch` | `scraperAPI`; `super_mode` becomes `super`, `home_page` is sent as `warmStart`, and browser rendering is automatic unless set. |
| `serp` | `webSearch`; `query_or_url` becomes `url` and `client_timeout` becomes `timeout`. |
| `status` | `status` for account usage; the domain analytics inputs are removed. |
| `scrape`, `rerun`, `results`, `result` | Removed from the MCP server. Manage AI scrapers, reruns, and stored results in the [MrScraper dashboard](https://app.mrscraper.com). |
Reconnect the MCP client after the change so it refreshes its tool list.
In 0.3.0, `webSearch` dropped the `raw`, `format`, `language`, `page`, and
`render_js` options because the new web search endpoint doesn't support them;
calls that still send them succeed and the options are ignored. It added
`num_results`.
## Common response envelope
`scraperAPI` and `webSearch` 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. `status` returns the account summary described in its
[reference](#status).
## Tool reference
The options and defaults of `scraperAPI` follow the Python SDK's `scraper_api`
method. Tool names use camel case; argument names use snake case.
### `scraperAPI`
Use `scraperAPI` for a known URL. It calls:
```text
POST https://api.mrscraper.com/
```
The JSON body contains `url`, `maxRetries`, and optional `tokenCap`. Page
options are sent as query parameters.
#### Basic request
```json
{
"url": "https://www.scrapethissite.com/pages/simple/"
}
```
#### HTML, Markdown, and a screenshot
```json
{
"url": "https://www.scrapethissite.com/pages/simple/",
"html": true,
"markdown": true,
"screenshot": true
}
```
#### Real-device routing from another country
```json
{
"url": "https://www.scrapethissite.com/pages/simple/",
"super": true,
"geo_code": "ID",
"home_page": true
}
```
Omit `browser_rendering`, or set it to `null`, to let the service try without a
browser and fall back to browser loading when needed. `true` forces browser
loading and `false` disables it. A screenshot always forces browser loading.
`super` selects real-device routing independently of browser rendering.
#### Response
The page content is in `data`:
```json
{
"status_code": 200,
"data": {
"html": "...",
"markdown": "...",
"screenshot": "/9j/4AAQSkZJRgABAQAAAQAB...",
"token_usage": 3,
"runtime": 18.02,
"retry_count": 0,
"error": null
},
"headers": {
"content-type": "application/json",
"x-status-code": "200",
"token_usage": "3"
}
}
```
`screenshot` is a base64-encoded JPEG and can be large. `x-status-code` is the
target page's status. Usage is calculated from runtime and bandwidth: one plan
token per 30 seconds and one plan token per 0.25 MB, rounded up per component.
#### Parameters
| Parameter | Required | Default | Request mapping | Description |
| ---------------------- | -------- | --------- | ------------------------------------ | --------------------------------------------------------------------------------------- |
| `url` | Yes | — | Body `url` | Absolute HTTP or HTTPS page URL. |
| `html` | No | `true` | Query `html` | Requests HTML content. |
| `markdown` | No | `false` | Query `markdown` | Requests Markdown content. |
| `screenshot` | No | `false` | Query `screenshot` | Captures a screenshot and forces browser rendering. |
| `browser_rendering` | No | automatic | Query `browserRendering` | `true` forces and `false` disables browser rendering. |
| `super` | No | `false` | Query `super` | Real-device routing. |
| `geo_code` | No | `"US"` | Query `geoCode` | Proxy country code. |
| `proxy_country` | No | omitted | Query `proxyCountry` | Compatibility country option. |
| `use_proxy` | No | `true` | Query `useProxy=false` when disabled | Allows the service's configured proxy. |
| `proxy` | No | omitted | Query `proxy` | Custom proxy as `username:password@host:port`. |
| `wait_for_selector` | No | omitted | Query `waitForSelector` | CSS selector to wait for. |
| `home_page` | No | `false` | Query `warmStart` | Visits the site's root before the target URL. |
| `block_resources` | No | `false` | Query `blockResources` | Blocks images, CSS, and fonts. |
| `bypass_proxy` | No | `false` | Query `bypassProxy` | Enables the proxy-bypass behavior. |
| `cookie_jar` | No | omitted | Query `cookieJar` | Cookie configuration, such as `domain=example.org&country=us&max_used=100&max_age=50m`. |
| `headers` | No | omitted | Query `headers` | Target page request headers as an object or JSON string. |
| `max_retries` | No | `3` | Body `maxRetries` | Maximum retries; `0` disables retries. |
| `token_cap` | No | omitted | Body `tokenCap` | Running token total that stops further retries. |
| `timeout` | No | `120` | Query `timeout` | Page timeout from 1 to 300 seconds. |
| `stream` | No | omitted | Query `stream` | Asks the API to stream; the server returns one buffered response. |
| `discard_token_secret` | No | `""` | Header `x-discard-token-secret` | Optional upstream header. |
### `webSearch`
Use `webSearch` when no target URL is known. It calls MrScraper's web search
action on the Scraper API host:
```text
POST https://api.mrscraper.com
```
The request body carries `action: "websearch"`, the query, and the optional
country and result count. This asks for 20 results from the United Kingdom:
```json
{
"url": "running shoes",
"region": "gb",
"num_results": 20
}
```
A search results URL also works as `url`; its `q` parameter becomes the query.
#### Results
The results are a ranked list in `data.data`:
```json
{
"status_code": 200,
"data": {
"success": true,
"message": "Search completed",
"data": [
{
"rank": 1,
"title": "Web Scraping API | MrScraper",
"url": "https://mrscraper.com/",
"description": "Extract structured data from any website with AI.",
"source": "MrScraper"
}
],
"tokenUsage": 1
},
"headers": {
"content-type": "application/json; charset=utf-8"
}
}
```
#### Parameters
| Parameter | Required | Default | Request mapping | Description |
| ------------- | -------- | ------- | ---------------------- | --------------------------------------------------------------- |
| `url` | Yes | — | Body `query` | Search text, or a search results URL whose `q` value is used. |
| `region` | No | `us` | Body `country` | Two-letter country code for the results. |
| `num_results` | No | `10` | Body `numResults` | Number of results, from 10 to 100. The search may return fewer. |
| `timeout` | No | `600` | Local request deadline | Upstream HTTP deadline in seconds. |
### `status`
Use `status` to check the connected account. It takes no input and calls:
```text
GET https://api.app.mrscraper.com/api/v1/subscription-accounts
```
#### Status summary
```json
{
"kind": "mrscraper-cli-status-summary",
"source_endpoints": ["/subscription-accounts"],
"status_code": 200,
"data": {
"account": {
"subscription_status": "active",
"enterprise": false,
"token_usage": 61240,
"token_limit": 100000,
"token_remaining": 38760,
"usage_percent": 61.24,
"rate_limit": 0,
"rate_ttl": 0,
"auto_renew": true,
"ends_at": "2026-12-01T00:00:00.000Z",
"user": {
"name": "Ada",
"email": "ada@example.com",
"verified": true
}
}
}
}
```
The summary selects account fields and calculates `token_remaining` and
`usage_percent`. An OAuth connection needs the `account:read` scope.
## Troubleshooting
The MCP client may still be using a cached tool list.
1. Reload the MCP client or start a new session.
2. Inspect `tools/list`.
3. Confirm that the server advertises these tools: `scraperAPI`, `webSearch`, and `status`.
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 OAuth grant does not include the tool's scope.
1. `scraperAPI` needs `scrape:write`, `webSearch` needs `scrape:read`, and `status` needs `account:read`.
2. Reconnect the server so the client requests the missing scope.
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 tool.
1. Check the tool's parameter table.
2. Use `scraperAPI` and `webSearch` in place of the removed `fetch` and `serp` tools.
3. Run the request again with the corrected parameters.
The upstream service may need more time to complete the request.
1. Increase `scraperAPI.timeout` (up to 300 seconds) for a page request.
2. Increase `webSearch.timeout` for a search request.
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"
```
Call one tool at a time against the live service:
```bash
npm run test:manual -- scraperAPI --url "https://www.scrapethissite.com/pages/simple/"
npm run test:manual -- webSearch --query "web scraping"
npm run test:manual -- status
```
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, SquareTerminal, 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 scrapers and workflows 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/scraper-api">
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/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/workflow-scraper">
Build and customize your own scraper workflow step by step for full control.
} href="/docs/features/workflow-scraper/self-healing">
Let AI generate, repair, and extend 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/web-fetching">
Retrieve page HTML with browser rendering and geo-targeting.
} 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/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/dify">
Fetch web pages and search Google from Dify agents, chatflows, and workflows.
} 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 reliable web scraping.
## Developer Tools
Work with MrScraper from your terminal, your codebase, or your AI agent.
The [MrScraper MCP server source code](https://github.com/mrscraper-com/mrscraper-mcp)
is available on GitHub for local setup, contributions, and issue reports.
} href="/docs/getting-started/cli">
Fetch pages, search Google, and check account usage from your terminal.
} href="/docs/getting-started/mcp-server">
Let AI agents fetch pages and search Google through the Model Context Protocol.
} href="/docs/integrations/python">
Fetch pages, search Google, and check account usage with the async `mrscraper-sdk` package.
} href="/docs/integrations/node">
Fetch pages, search Google, and check account usage with the `@mrscraper/sdk` package.
} 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 [Scraper API](https://app.mrscraper.com/scraper-api) 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/scraper-api">
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
}
```
# 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 web scraping and data extraction using natural language, backed by the MrScraper API.
## Overview
Once installed, your agent can:
* **Fetch pages**: Retrieve rendered HTML from public pages, with browser rendering and geo-targeted proxies.
* **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 |
| ------------ | ------------------------------- | -------------------------------------------- |
| Web Fetching | `https://api.mrscraper.com` | Fetch HTML from public pages |
| Platform | `https://api.app.mrscraper.com` | Create, rerun, and read scrapers and results |
## Available Endpoints
### Web Fetching
Fetches a public page with browser rendering and geo-targeted proxies, 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.
# Dify
import { Step, Steps } from 'fumadocs-ui/components/steps';
The [MrScraper plugin for Dify](https://marketplace.dify.ai/plugin/ai-mrscraper/mrscraper)
adds web retrieval and search to your Dify applications. Use its tools as workflow
nodes or let an agent choose when to call them.
## Available tools
| Tool | Tool ID | Purpose |
| --------------- | ----------------------- | --------------------------------------------------------------------------------------- |
| **Account** | `mrscraper_account` | Check your MrScraper account, token usage, and limits. |
| **Scraper API** | `mrscraper_scraper_api` | Retrieve a page as HTML, Markdown, a screenshot, or a combination. |
| **Web Search** | `mrscraper_web_search` | Search the web for real-time results, including website URLs, titles, and descriptions. |
This guide covers plugin version **0.2.0**, which requires **Dify 1.17.0 or later**.
See the [marketplace listing](https://marketplace.dify.ai/plugin/ai-mrscraper/mrscraper)
for releases and compatibility details.
## Prerequisites
* A Dify workspace with permission to install tool plugins.
* A [MrScraper API token](https://app.mrscraper.com/api-tokens).
* A model configured in Dify if you want an agent or LLM node to process the results.
## Installation and authentication
### Install the plugin
Open [MrScraper in the Dify Marketplace](https://marketplace.dify.ai/plugin/ai-mrscraper/mrscraper),
click **Install**, and select your Dify environment. You can also find MrScraper
from the marketplace inside your workspace's **Integrations** page.
### Add your API token
In Dify, open **Integrations > Tools > Tool Plugin**, select **MrScraper**, and
add a credential. Paste your MrScraper token into **API Token** and save it.
Dify supplies this credential whenever a MrScraper tool runs. You do not need to
pass the token as a tool input or include it in an agent prompt.
### Verify the connection
Add a MrScraper **Account** tool node to a workflow and select the credential you
saved. Run the node without additional inputs and check that it returns your
account information.
For help creating a token, see [Token Plan](/docs/getting-started/api-token).
Dify's [tools guide](https://docs.dify.ai/en/cloud/use-dify/workspace/tools)
explains workspace credentials and using tools across applications.
## Fetch a page with Scraper API
Use **Scraper API** when you already have a target URL. For example, configure a
tool node with these inputs to retrieve Markdown for an LLM:
```json
{
"url": "https://example.com",
"html": false,
"markdown": true
}
```
### Common inputs
| Input | Default | Description |
| ------------------- | -------- | --------------------------------------------------------------- |
| `url` | Required | The page URL to retrieve. |
| `html` | `true` | Include HTML in the response. |
| `markdown` | `false` | Include Markdown in the response. |
| `screenshot` | `false` | Include a screenshot; this also enables browser rendering. |
| `browser_rendering` | `auto` | Select `auto`, `true`, or `false` to control browser rendering. |
| `timeout` | `120` | Page timeout in seconds, from `1` to `300`. |
| `geo_code` | `US` | Geolocation country code. |
| `max_retries` | `3` | Retry limit. Set to `0` to disable retries. |
At least one of `html`, `markdown`, or `screenshot` must be enabled.
The tool also exposes advanced options for proxy routing (`proxy_country`,
`use_proxy`, `proxy`, `bypass_proxy`, `super`), page loading (`home_page`,
`wait_for_selector`, `wait_until`, `block_resources`), request data
(`cookie_jar`, `headers` as a JSON object string), retry budgets
(`token_cap`), response streaming (`stream`: `auto`, `true`, or `false`; the
plugin buffers streamed responses before returning them), and the optional
`x-discard-token-secret` request header (`discard_token_secret`). Start
with the defaults and adjust them for the target page. See the
[Scraper API guide](/docs/getting-started/scraper-api) for retrieval use cases.
## Discover pages with Web Search
Use **Web Search** when you have a topic or keyword rather than a target page.
It always returns structured JSON results.
```json
{
"query": "web scraping tutorials",
"country": "us",
"num_results": 10
}
```
| Input | Default | Description |
| ------------- | --------------- | --------------------------------------------------------------------- |
| `query` | Required | The search query. |
| `country` | Service default | Optional two-letter country code for localized results, such as `us`. |
| `num_results` | `10` | Number of results to return, from `10` to `100`. |
Each result includes its `rank`, `title`, `url`, `description`, and `source`.
## Example: summarize a web page
Build a workflow that accepts a URL, retrieves its content, and produces a summary:
1. Add a **User Input** node with a required text input named `page_url`.
2. Choose **Add Node > Tools > MrScraper > Scraper API**.
3. Bind the tool's `url` input to `page_url`, set `html` to `false`, and set
`markdown` to `true`.
4. Test the tool node and inspect its output. Bind the returned page text or
Markdown field to an **LLM** node with an instruction such as
`Summarize this page in three bullet points.`
5. Connect the LLM response to an **Output** node, then test the workflow with
`https://example.com`.
For research workflows, run **Web Search** first, select a result URL from its
output, and pass that URL to **Scraper API** before summarizing the page.
See Dify's [Tool node guide](https://docs.dify.ai/en/cloud/use-dify/nodes/tools)
for adding nodes and choosing credentials.
## Use MrScraper in an agent
Add **Web Search** and **Scraper API** to your agent's available tools and select
your MrScraper credential. The agent can fill in the search query and page URL
on its own.
An example agent instruction:
```text
Search the web for pages relevant to the user's question. Fetch the most useful
pages with Scraper API, then answer using the retrieved content and cite the
source URLs.
```
## Working with outputs
The plugin returns the API response data directly. Objects and arrays appear as
Dify JSON messages; strings such as HTML appear as text. HTTP status and response
headers are not included in the tool output.
Default timeouts are 30 seconds for **Account**, 120 seconds (plus 30 seconds of
transport) for **Scraper API**, and 600 seconds for **Web Search**. The plugin's
maximum request time is 660 seconds.
Scraper API can return text or an object containing multiple requested formats.
Inspect a test run before connecting its output to another node. Screenshot data
is returned as base64 inside the JSON response; the plugin does not create a
separate Dify file.
## Troubleshooting
| Issue | What to check |
| ---------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| Plugin will not install | Confirm your Dify version meets the plugin requirement and your workspace permissions allow installation. |
| Authentication fails | Check the provider's **API Token** credential and verify it with **Account**. |
| Web Search rejects the result count | Set `num_results` to an integer from `10` to `100`. |
| A downstream node receives an unexpected value | Inspect the tool's JSON or text output and bind the specific content your next node needs. |
| A request times out | Check the tool timeout and any shorter limits imposed by your Dify deployment or reverse proxy. |
For self-hosted Dify, allow outbound HTTPS access to `api.app.mrscraper.com` and
`api.mrscraper.com`.
## Upgrading
* **From 0.1.x:** Tool IDs are unchanged. Web Search now takes `query`, `country`,
and `num_results`, and always returns JSON; the `url`, `raw`, `format`,
`region`, `language`, and `page` inputs were removed. Update any Web Search
nodes and their bindings. Scraper API adds new options, and Account is
unchanged.
* **From 0.0.1:** The old tools were replaced by the three tools listed above.
Recreate affected nodes and reconnect their bindings. Extraction, crawl,
scraper creation, rerun, and saved-result operations have no equivalent.
# 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, so AI agents can fetch web pages as HTML, Markdown, or screenshots, search the web, and check account usage. It wraps the [Python SDK](/docs/integrations/python) (`mrscraper-sdk`), which is installed as a dependency. MrScraper is also listed in LangChain's [web browsing tools](https://docs.langchain.com/oss/python/integrations/tools/index#web-browsing).
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**
* `mrscraper-sdk` 0.9.x and `langchain-core` 0.3 or later (installed as dependencies)
This page documents version **0.5.0**. 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](https://app.mrscraper.com) as an environment variable:
```python
import os
os.environ["MRSCRAPER_API_KEY"] = "MRSCRAPER_API_TOKEN"
```
The tools resolve the token in this order:
1. The `token` parameter, such as `MrScraperToolkit(token="...")`
2. The `mrscraper_api_key` parameter, such as `load_mrscraper_tools(mrscraper_api_key="...")`
3. The `MRSCRAPER_API_KEY` environment variable
4. The `MRSCRAPER_API_TOKEN` environment variable
You can also pass an existing `mrscraper.MrScraper` client with `client=...`.
For more information on generating API tokens, see the [Generate Token](/docs/getting-started/api-token) guide.
## Quick Start
### Using MrScraperToolkit
Load all three 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. It accepts the same configuration as the toolkit:
```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": "Search the web for MrScraper and summarize the top result."}]
})
```
This example requires `langgraph` and `langchain-openai` packages:
```bash
pip install langgraph langchain-openai
```
## Available Tools
| Class | Tool name | SDK method | Purpose |
| --------------------- | ----------------------- | ------------- | -------------------------------------------------------------------------------------------------------------- |
| `MrScraperScraperAPI` | `mrscraper_scraper_api` | `scraper_api` | Fetch a public web page as rendered HTML, Markdown, screenshot, or a combination |
| `MrScraperWebSearch` | `mrscraper_web_search` | `web_search` | Search the web to retrieve real-time search results, including relevant website URLs, titles, and descriptions |
| `MrScraperAccount` | `mrscraper_account` | `account` | Read account identity, subscription, quota, token usage, and rate limits |
Every tool returns a pretty-printed JSON string containing the SDK's `status_code`, `data`, and `headers`.
## Core Methods
### Scraper API
Fetch a public web page as rendered HTML, Markdown, screenshot, or a combination.
```python
import base64
import json
from langchain_mrscraper import MrScraperScraperAPI
tool = MrScraperScraperAPI(token="MRSCRAPER_API_TOKEN")
# HTML only (the default) returns the HTML string in data
page = json.loads(tool.invoke({"url": "https://example.com"}))
print(page["data"][:200])
# Markdown or a screenshot returns an object with one entry per output
combined = json.loads(tool.invoke({
"url": "https://example.com",
"html": True,
"markdown": True,
"screenshot": True,
}))
print(combined["data"]["markdown"][:200])
image = base64.b64decode(combined["data"]["screenshot"])
```
At least one of `html`, `markdown`, or `screenshot` must be `True`. The screenshot is a base64 string. Setting `screenshot=True` enables browser rendering, so combining it with `browser_rendering=False` is rejected.
**Parameters:**
| Parameter | Type | Required | Default | Description |
| ---------------------- | -------------- | -------- | ------- | --------------------------------------------------------------------------------------- |
| `url` | string | Yes | - | HTTP or HTTPS URL to fetch |
| `html` | boolean | No | `True` | Return the rendered page HTML |
| `markdown` | boolean | No | `False` | Return the page as Markdown |
| `screenshot` | boolean | No | `False` | Return a base64 screenshot. Enables browser rendering |
| `timeout` | integer | No | `120` | Page timeout in seconds (1-300) |
| `geo_code` | string | No | `"US"` | Geographic country code |
| `proxy_country` | string | No | `None` | Proxy country code |
| `block_resources` | boolean | No | `False` | Block images, CSS, and fonts |
| `browser_rendering` | boolean | No | `None` | `True` forces JavaScript rendering, `False` disables it, `None` lets the service decide |
| `super` | boolean | No | `False` | Use real-device routing |
| `use_proxy` | boolean | No | `True` | Use a proxy for this request |
| `proxy` | string | No | `None` | Custom proxy in `username:password@host:port` format |
| `wait_for_selector` | string | No | `None` | CSS selector to wait for |
| `wait_until` | string | No | `None` | Page lifecycle event to wait for, such as `"domcontentloaded"` |
| `home_page` | boolean | No | `False` | Visit the site's root page first |
| `bypass_proxy` | boolean | No | `False` | Enable the API's proxy bypass behavior |
| `cookie_jar` | string | No | `None` | Cookie configuration string |
| `headers` | dict \| string | No | `None` | Target request headers, as a dictionary or JSON string |
| `max_retries` | integer | No | `3` | Maximum retries, 0 or greater |
| `token_cap` | integer | No | `None` | Maximum retry-token budget, 0 or greater |
| `stream` | boolean | No | `None` | Request a streamed response |
| `discard_token_secret` | string | No | `""` | Discard-token secret, if required |
For more examples of what you can fetch, see [Scrape HTML](/docs/getting-started/scraper-api/scrape-html), [Scrape Markdown](/docs/getting-started/scraper-api/scrape-markdown), and [Get Screenshot](/docs/getting-started/scraper-api/get-screenshot).
### Web Search
Search the web to retrieve real-time search results, including relevant website URLs, titles, and descriptions.
```python
import json
from langchain_mrscraper import MrScraperWebSearch
tool = MrScraperWebSearch(token="MRSCRAPER_API_TOKEN")
result = json.loads(tool.invoke({
"query": "python web scraping",
"country": "us",
"num_results": 10,
}))
for item in result["data"]["data"]:
print(item["rank"], item["title"], item["url"])
```
**Parameters:**
| Parameter | Type | Required | Default | Description |
| ------------- | ------- | -------- | ------- | ----------------------------------------------------------------------------------- |
| `query` | string | Yes | - | Search query. Must not be blank |
| `country` | string | No | `None` | Country code for localized results, such as `"us"`. Omit to use the service default |
| `num_results` | integer | No | `10` | Number of results to return (10-100) |
| `timeout` | float | No | `600.0` | HTTP timeout in seconds |
The response `data` contains `success`, `message`, and `data`, a list of ranked results. Each result has `rank`, `title`, `url`, `description`, and `source`.
### Account
Read account identity, subscription status, token usage and limits, remaining quota, and rate limits.
```python
from langchain_mrscraper import MrScraperAccount
tool = MrScraperAccount(token="MRSCRAPER_API_TOKEN")
print(tool.invoke({}))
```
**Parameters:**
| Parameter | Type | Required | Default | Description |
| --------- | ----- | -------- | ------- | ----------------------- |
| `timeout` | float | No | `30.0` | HTTP timeout in seconds |
See [Account](/docs/integrations/python#account) in the Python SDK documentation for the fields in the account summary.
## 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**
`tool_names` filters by the exact tool names. An empty list returns no tools.
```python
from langchain_mrscraper import MrScraperToolkit
tools = MrScraperToolkit(
token="MRSCRAPER_API_TOKEN",
tool_names=["mrscraper_scraper_api", "mrscraper_web_search"],
).get_tools()
```
**4. Per-Tool Constructors**
```python
from langchain_mrscraper import MrScraperScraperAPI
scraper_api = MrScraperScraperAPI(token="MRSCRAPER_API_TOKEN")
```
**5. Shared SDK Client**
```python
from mrscraper import MrScraper
from langchain_mrscraper import MrScraperToolkit
client = MrScraper(token="MRSCRAPER_API_TOKEN")
tools = MrScraperToolkit(client=client).get_tools()
```
## Async Usage
Every tool supports both `.invoke(...)` and `await .ainvoke(...)`:
```python
import asyncio
from langchain_mrscraper import MrScraperScraperAPI
async def async_scrape():
tool = MrScraperScraperAPI(token="MRSCRAPER_API_TOKEN")
output = await tool.ainvoke({
"url": "https://example.com",
"timeout": 120,
})
print(output)
asyncio.run(async_scrape())
```
Synchronous `.invoke(...)` calls also work inside notebooks that already have a running event loop.
## Best Practices
### Token Management
Store your API token securely:
```python
import os
# Load from .env file
from dotenv import load_dotenv
load_dotenv()
token = os.getenv("MRSCRAPER_API_KEY")
```
### Error Handling
Each tool validates its input before sending a request. Invalid URLs, out-of-range limits, and unsupported fields are rejected by the tool schema. API, authentication, and network errors are raised from the [Python SDK](/docs/integrations/python#error-handling).
```python
from langchain_mrscraper import MrScraperScraperAPI
try:
tool = MrScraperScraperAPI(token="MRSCRAPER_API_TOKEN")
output = tool.invoke({"url": "https://example.com"})
except Exception as e:
print(f"Scraping error: {e}")
```
### Tool Selection
Only load the tools your agent needs:
```python
from langchain_mrscraper import MrScraperToolkit
# Good: Only load needed tools
tools = MrScraperToolkit(tool_names=["mrscraper_web_search"]).get_tools()
# Loads all three tools
tools = MrScraperToolkit().get_tools()
```
## Migrating from 0.3.x
Version 0.5.0 requires `mrscraper-sdk>=0.9.0,<0.10.0`, which exposes exactly three public methods. The toolkit now returns three tools instead of ten.
| 0.3.x tool | 0.5.0 replacement |
| --------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `MrScraperHTML` (`mrscraper_scraper_html`) | `MrScraperScraperAPI` with `{"url": ...}` |
| `MrScraperMarkdown` (`mrscraper_scraper_markdown`) | `MrScraperScraperAPI` with `{"url": ..., "html": False, "markdown": True}` |
| `MrScraperScreenshot` (`mrscraper_get_screenshot`) | `MrScraperScraperAPI` with `{"url": ..., "html": False, "screenshot": True}` |
| `MrScraperJSON`, `MrScraperMultiplePage`, `MrScraperSitemap`, `MrScraperBrand`, `MrScraperGetBrand` | Removed. Fetch pages with `MrScraperScraperAPI` and let your model extract data, or pin `langchain-mrscraper<0.4` |
| `MrScraperWebSearch` (`url`, `raw`, `format`, `region`, `language`, `page`, `render_js`) | `MrScraperWebSearch` (`query`, `country`, `num_results`, `timeout`) |
| `MrScraperAccount` | Unchanged |
| `MrScraperFetchHTML` import alias | Removed. Use `MrScraperScraperAPI` |
* Screenshots now come back as a base64 string in `data["screenshot"]`, together with any other requested outputs. The 0.3.x screenshot `full_page` option and its `timeout=300` and `wait_until="domcontentloaded"` defaults no longer exist; pass `timeout` and `wait_until` explicitly when needed.
* Update `tool_names` filters to `mrscraper_scraper_api`, `mrscraper_web_search`, and `mrscraper_account`.
* The scraper and result tools from earlier versions (create, rerun, and bulk-rerun scrapers, and result listing) remain removed. Call the [REST API](/docs/api/overview) directly for scrapers and results.
# Node.js SDK
The official [`@mrscraper/sdk`](https://www.npmjs.com/package/@mrscraper/sdk) package exposes three functions: `scraper_api` to fetch page content (HTML, Markdown, or screenshots), `web_search` to retrieve real-time web search results, and `account` to check your subscription and token usage from your Node.js applications.
## Requirements
* **Node.js 18 or later**
* **ES Modules enabled** in your `package.json`
```json title="package.json"
{
"type": "module"
}
```
This page documents version **5.0.0**. 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. The SDK reads `MRSCRAPER_API_TOKEN` automatically. You can get your API token from the [MrScraper dashboard](https://app.mrscraper.com).
```bash
export MRSCRAPER_API_TOKEN="MRSCRAPER_API_TOKEN"
```
All functions accept an optional `token` in their options object 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 { scraper_api, web_search, account, MrScraperError } from "@mrscraper/sdk";
try {
// 1. Fetch page content
const page = await scraper_api("https://example.com");
console.log(page.status_code, page.data);
// 2. Search the web
const search = await web_search("python web scraping", { country: "us" });
console.log(search.data.data);
// 3. Check remaining tokens
const status = await account();
console.log(status.data.token_remaining);
} catch (err) {
if (err instanceof MrScraperError) {
console.error(`[${err.status ?? "network"}] ${err.message}`);
} else {
throw err;
}
}
```
## Response Format
All functions are async and resolve to a `MrScraperResponse` object:
| Property | Type | Description |
| ------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------ |
| `status_code` | number | HTTP status code of the API response |
| `data` | `T` (default `unknown`) | Parsed JSON for JSON responses, a string for HTML and other text, or a Node.js `Buffer` for binary responses |
| `headers` | `Record` | Response headers |
You can type `data` with a generic parameter:
```ts
const result = await scraper_api("https://example.com");
```
## Core Methods
### Scraper API
Use `scraper_api` to fetch a page through the MrScraper [Scraper API](/docs/getting-started/scraper-api). The service handles JavaScript rendering, bot detection, and optional geolocation proxying.
```ts
import { writeFile } from "node:fs/promises";
import { scraper_api } from "@mrscraper/sdk";
// HTML only (the default) returns the page as a string
const page = await scraper_api("https://example.com");
console.log(page.data);
// Markdown or a screenshot returns an object with one entry per output
const result = await scraper_api("https://example.com", {
html: true,
markdown: true,
screenshot: true,
geo_code: "US",
timeout: 120,
// token: "optional_override_token"
});
if (typeof result.data !== "string") {
console.log(result.data.markdown);
if (result.data.screenshot) {
await writeFile("page.jpg", Buffer.from(result.data.screenshot, "base64"));
}
}
```
Requesting only HTML returns the page as a string. Requesting Markdown or a screenshot returns an object such as `{ html, markdown, screenshot }` with an entry for each requested output, typed as `ScraperApiData`. The screenshot is a base64-encoded JPEG. At least one of `html`, `markdown`, or `screenshot` must be `true`.
The SDK sends a `GET` request to `https://api.mrscraper.com`, with the target URL and every option in the query string.
**Parameters:**
The first argument is the target URL. All other parameters go in the optional options object.
| Parameter | Type | Required | Default | Description |
| ---------------------- | ------------------------ | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------- |
| `url` | string | Yes | - | Target page URL (first argument) |
| `token` | string | No | - | Per-request token override |
| `html` | boolean | No | `true` | Return HTML content |
| `markdown` | boolean | No | `false` | Return Markdown content |
| `timeout` | number | No | `120` | Page timeout in seconds (1-300) |
| `geo_code` | string | No | `"US"` | Two-letter country code for geolocation |
| `proxy_country` | string \| null | No | - | Optional proxy country |
| `browser_rendering` | boolean \| null | No | - | `true` forces browser rendering, `false` disables it, unset tries without a browser first and falls back automatically |
| `screenshot` | boolean | No | `false` | Capture a screenshot. Also forces browser rendering |
| `super` | boolean | No | `false` | Enable real device routing |
| `use_proxy` | boolean | No | `true` | Allow the service to use a proxy |
| `proxy` | string \| null | No | - | Custom proxy in `username:password@host:port` format |
| `home_page` | boolean | No | `false` | Visit the site's root page before the target URL |
| `wait_for_selector` | string \| null | No | - | CSS selector to wait for before returning content |
| `wait_until` | string \| null | No | - | Page lifecycle event to wait for, such as `"domcontentloaded"` |
| `block_resources` | boolean \| null | No | `false` | Block images, CSS, and fonts to speed up the request |
| `bypass_proxy` | boolean | No | `false` | Enable the API's proxy bypass behavior |
| `cookie_jar` | string \| null | No | - | Cookie configuration, e.g. `"domain=example.com&country=us&max_used=100&max_age=50m"` |
| `headers` | object \| string \| null | No | - | Headers forwarded to the target site, as an object or JSON string |
| `max_retries` | number | No | `3` | Maximum number of retries, a nonnegative integer |
| `token_cap` | number \| null | No | - | Optional token budget for retries |
| `stream` | boolean \| null | No | - | Request a streamed response. The SDK buffers it into the normal return value |
| `discard_token_secret` | string | No | `""` | Value sent in the `x-discard-token-secret` request header |
Setting `screenshot: true` always enables browser rendering, even if you pass `browser_rendering: false`.
For more examples of what you can fetch, see [Scrape HTML](/docs/getting-started/scraper-api/scrape-html), [Scrape Markdown](/docs/getting-started/scraper-api/scrape-markdown), and [Get Screenshot](/docs/getting-started/scraper-api/get-screenshot).
### Web Search
Use `web_search` to search the web and retrieve real-time search results, including relevant website URLs, titles, and descriptions. The first argument is the search query.
```ts
import { web_search } from "@mrscraper/sdk";
const result = await web_search("python web scraping", {
country: "us",
num_results: 10,
// token: "optional_override_token"
});
for (const item of result.data.data) {
console.log(item.rank, item.title, item.url);
}
```
The SDK sends this request:
```bash
curl --location 'https://api.mrscraper.com' \
--header 'x-api-token: {MRSCRAPER_API_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"action": "websearch",
"query": "python web scraping",
"country": "us",
"numResults": 10
}'
```
**Parameters:**
| Parameter | Type | Required | Default | Description |
| ------------- | -------------- | -------- | ------- | -------------------------------------------------------------------------------------- |
| `query` | string | Yes | - | Search query (first argument). Must not be empty |
| `token` | string | No | - | Per-request token override |
| `country` | string \| null | No | - | Country code for localized results, such as `"us"`. Omitted to use the service default |
| `num_results` | number | No | `10` | Number of results, an integer from 10 to 100. Sent as `numResults` |
| `timeout` | number | No | `600` | Request timeout in seconds |
**Response (`result.data`, typed as `WebSearchResponse`):**
| Property | Type | Description |
| --------- | ------------------- | ---------------------------------------------------------------------------- |
| `success` | boolean | Whether the search succeeded |
| `message` | string | Status message |
| `data` | `WebSearchResult[]` | Ranked results. Each has `rank`, `title`, `url`, `description`, and `source` |
### Account
Use `account` to check the identity, subscription, token quota, and rate limits of the account that owns the API token.
```ts
import { account } from "@mrscraper/sdk";
const result = await account({
timeout: 30,
// token: "optional_override_token"
});
console.log(result.data.subscription_status);
console.log(result.data.token_remaining);
console.log(result.data.user.email);
```
**Parameters:**
| Parameter | Type | Required | Default | Description |
| --------- | ------ | -------- | ------- | ------------------------------------------------- |
| `token` | string | No | - | Per-request token override |
| `timeout` | number | No | `30` | HTTP request timeout in seconds. Must be positive |
**Account summary (`result.data`, typed as `AccountSummary`):**
| Property | Type | Description |
| --------------------- | -------------- | --------------------------------------------- |
| `subscription_status` | string \| null | Subscription status, such as `"active"` |
| `enterprise` | boolean | Whether the account is on an enterprise plan |
| `token_usage` | number | Tokens used in the current period |
| `token_limit` | number | Token limit for the current period |
| `token_remaining` | number | Remaining tokens, never below 0 |
| `usage_percent` | number | Token usage as a percentage of the limit |
| `rate_limit` | number | Request rate limit |
| `rate_ttl` | number | Rate-limit window |
| `auto_renew` | boolean | Whether the subscription renews automatically |
| `ends_at` | string \| null | Subscription end date |
| `user` | object | `name`, `email`, and `verified` |
API keys, billing identifiers, and sensitive response headers are excluded from the result.
## TypeScript Types
The package ships its own type definitions:
```ts
import type {
ScraperApiOptions,
ScraperApiData,
WebSearchOptions,
WebSearchResponse,
WebSearchResult,
AccountOptions,
AccountSummary,
MrScraperResponse,
} from "@mrscraper/sdk";
```
## Error Handling
All functions reject with `MrScraperError` for API, authentication, network, and timeout failures. Invalid options throw a `TypeError` or `RangeError` before any request is sent.
### 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 { scraper_api, MrScraperError } from "@mrscraper/sdk";
try {
await scraper_api("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`
## Migrating from Earlier Versions
### From Version 4
Version 5.0.0 returns to three public functions. The 4.x format-specific functions (`scraper_html`, `scraper_markdown`, `get_screenshot`, `scraper_json`, `scraper_multiple_page`, `scraper_sitemap`, `scrape_brand`, and `get_brand`) and their option types are no longer exported. Use `scraper_api` with output flags instead:
| Version 4 | Version 5 |
| ------------------------------------------- | --------------------------------------------------------------- |
| `scraper_html(url, options)` | `scraper_api(url, options)` |
| `scraper_markdown(url, options)` | `scraper_api(url, { ...options, html: false, markdown: true })` |
| `get_screenshot(url, { full_page: false })` | `scraper_api(url, { html: false, screenshot: true })` |
| `web_search(query, { region: "us" })` | `web_search(query, { country: "us" })` |
| `ScraperOptions` type | `ScraperApiOptions` |
A screenshot from `scraper_api` is a base64-encoded JPEG in `data.screenshot`, not a `Buffer`.
### From Version 3
* **`web_search`** now calls the MrScraper API with `action: "websearch"` and returns JSON. Its first argument is the search query, and it accepts `country` and `num_results` (10 to 100). The `raw`, `format`, `region`, `language`, `page`, and `render_js` options and search URL input were removed. Results are at `result.data.data`.
* **`scraper_api`** sends a `GET` request with every option in the query string, and adds the `wait_until` option. At least one of `html`, `markdown`, or `screenshot` must be `true`. HTML-only requests return a string, and requests with Markdown or a screenshot return an object with one entry per output.
* **`account`** is unchanged.
### From Version 3.0 to 3.1
Version 3.1.0 adds the [`account`](#account) function and the `AccountOptions` and `AccountSummary` types. No existing functions changed.
### From Version 2
Version 3 renames the public functions and their option types. Request options and the `{ status_code, data, headers }` response are unchanged.
| Version 2 | Version 3 |
| ----------------------------- | --------------------------- |
| `fetch_content(url, options)` | `scraper_api(url, options)` |
| `FetchContentOptions` | `ScraperApiOptions` |
The version 2 names are no longer exported.
### From Version 1
`fetchHtml` and all AI scraper, manual scraper, and results functions (`createAiScraper`, `rerunAiScraper`, `bulkRerunAiScraper`, `rerunManualScraper`, `bulkRerunManualScraper`, `getAllResults`, `getResultById`) were removed in version 2.
* Replace `fetchHtml` with [`scraper_api`](#scraper-api). It now returns a response wrapper instead of only the API payload, and options use `snake_case` (for example, `geoCode` is now `geo_code`).
* For scrapers and results, call the [REST API](/docs/api/overview) directly.
## 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 functions.
| Firecrawl Method | MrScraper Equivalent |
| ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------- |
| [Scrape a URL](https://docs.firecrawl.dev/sdks/node#scraping-a-url) with HTML or Markdown output | [`scraper_api`](#scraper-api) with `html: true` and/or `markdown: true` |
| Scrape a URL with a screenshot | [`scraper_api`](#scraper-api) with `screenshot: true` |
| [Search](https://docs.firecrawl.dev/sdks/node) | [`web_search`](#web-search) |
# Python SDK
The [mrscraper-sdk](https://pypi.org/project/mrscraper-sdk/) is a typed Python client for the MrScraper API. It exposes three methods: `scraper_api` to fetch page content (HTML, Markdown, or screenshots), `web_search` to retrieve real-time web search results, and `account` to check your subscription and token usage. All client methods are **async** and must be used with `asyncio` or another async runtime.
## Requirements
* **Python 3.9 or later**
* Basic familiarity with async/await syntax in Python
This page documents version **0.9.0**. 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 --upgrade mrscraper-sdk
```
Import the client in your Python code:
```python
from mrscraper import MrScraper
```
## Authentication
The client reads your API token from the `MRSCRAPER_API_TOKEN` environment variable automatically. You can get your API token from the [MrScraper dashboard](https://app.mrscraper.com).
```bash
export MRSCRAPER_API_TOKEN="MRSCRAPER_API_TOKEN"
```
```python
from mrscraper import MrScraper
client = MrScraper() # uses MRSCRAPER_API_TOKEN
```
You can also pass the token explicitly:
```python
client = MrScraper(token="MRSCRAPER_API_TOKEN")
```
Pass `http_client=` with your own `httpx.AsyncClient` to reuse connections across requests. Otherwise, the SDK creates a new client for each request.
```python
import httpx
from mrscraper import MrScraper
async with httpx.AsyncClient() as http:
client = MrScraper(http_client=http)
result = await client.scraper_api("https://example.com")
```
For more information on generating API tokens, see the [Generate Token](/docs/getting-started/api-token) guide.
## Quick Start
```python
import asyncio
from mrscraper import MrScraper
async def main():
client = MrScraper()
# 1. Fetch page content
page = await client.scraper_api("https://example.com")
print(page["data"])
# 2. Search the web
search = await client.web_search("python web scraping", country="us")
print(search["data"]["data"])
# 3. Check remaining tokens
account = await client.account()
print(account["data"]["token_remaining"])
asyncio.run(main())
```
## Response Format
All methods return a dictionary with the same structure:
| Key | Type | Description |
| ------------- | ------- | -------------------------------------------------------------------------------------------- |
| `status_code` | integer | HTTP status code of the API response |
| `data` | any | Python values for JSON responses, a string for text responses, or bytes for binary downloads |
| `headers` | dict | Response headers |
## Core Methods
### Scraper API
Use `scraper_api` to fetch a page through the MrScraper [Scraper API](/docs/getting-started/scraper-api). The service handles JavaScript rendering, bot detection, and optional geolocation proxying.
```python
import asyncio
from mrscraper import MrScraper
async def main():
client = MrScraper()
# HTML only (the default) returns the page as a string
page = await client.scraper_api("https://example.com/product")
print(page["data"])
# Markdown or a screenshot returns a dictionary with one entry per output
result = await client.scraper_api(
"https://example.com/product",
html=True,
markdown=True,
screenshot=True,
geo_code="US",
timeout=120,
)
print(result["data"]["markdown"])
asyncio.run(main())
```
Requesting only HTML returns the page as a string. Requesting Markdown or a screenshot returns a dictionary with an entry for each requested output, such as `html`, `markdown`, and `screenshot`. At least one of `html`, `markdown`, or `screenshot` must be `True`.
**Parameters:**
| Parameter | Type | Required | Default | Description |
| ---------------------- | -------------- | -------- | ------- | ----------------------------------------------------------------------------------------------------------------------- |
| `url` | string | Yes | - | Target page URL |
| `html` | boolean | No | `True` | Return HTML content |
| `markdown` | boolean | No | `False` | Return Markdown content |
| `timeout` | integer | No | `120` | Page timeout in seconds (1-300) |
| `geo_code` | string | No | `"US"` | Two-letter country code for geolocation (e.g., `"US"`, `"GB"`, `"SG"`) |
| `proxy_country` | string | No | `None` | Optional proxy country |
| `browser_rendering` | boolean | No | `None` | `True` forces browser rendering, `False` disables it, `None` tries without a browser first and falls back automatically |
| `screenshot` | boolean | No | `False` | Capture a screenshot. Also forces browser rendering |
| `super` | boolean | No | `False` | Enable real device routing |
| `use_proxy` | boolean | No | `True` | Allow the service to use a proxy |
| `proxy` | string | No | `None` | Custom proxy in `username:password@host:port` format |
| `home_page` | boolean | No | `False` | Visit the site's root page before the target URL |
| `wait_for_selector` | string | No | `None` | CSS selector to wait for before returning content |
| `wait_until` | string | No | `None` | Page lifecycle event to wait for, such as `"domcontentloaded"` |
| `block_resources` | boolean | No | `False` | Block images, CSS, and fonts to speed up the request |
| `bypass_proxy` | boolean | No | `False` | Enable the API's proxy bypass behavior |
| `cookie_jar` | string | No | `None` | Cookie configuration, e.g. `"domain=example.com&country=us&max_used=100&max_age=50m"` |
| `headers` | dict \| string | No | `None` | Headers forwarded to the target site, as a dictionary or JSON string |
| `max_retries` | integer | No | `3` | Maximum number of retries |
| `token_cap` | integer | No | `None` | Optional token budget for retries |
| `stream` | boolean | No | `None` | Request a streamed response. The SDK buffers it into the normal return value |
| `discard_token_secret` | string | No | `""` | Value sent in the `x-discard-token-secret` request header |
Setting `screenshot=True` always enables browser rendering, even if you pass `browser_rendering=False`.
For more examples of what you can fetch, see [Scrape HTML](/docs/getting-started/scraper-api/scrape-html), [Scrape Markdown](/docs/getting-started/scraper-api/scrape-markdown), and [Get Screenshot](/docs/getting-started/scraper-api/get-screenshot).
### Web Search
Use `web_search` to search the web and retrieve real-time search results, including relevant website URLs, titles, and descriptions. The first argument is the search query.
```python
import asyncio
from mrscraper import MrScraper
async def main():
client = MrScraper()
result = await client.web_search(
"python web scraping",
country="us",
num_results=10,
)
for item in result["data"]["data"]:
print(item["rank"], item["title"], item["url"])
asyncio.run(main())
```
The SDK sends this request:
```bash
curl --location 'https://api.mrscraper.com' \
--header 'x-api-token: {MRSCRAPER_API_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"action": "websearch",
"query": "python web scraping",
"country": "us",
"numResults": 10
}'
```
**Parameters:**
| Parameter | Type | Required | Default | Description |
| ------------- | ------- | -------- | ------- | -------------------------------------------------------------------------------------- |
| `query` | string | Yes | - | Search query. Must not be empty |
| `country` | string | No | `None` | Country code for localized results, such as `"us"`. Omitted to use the service default |
| `num_results` | integer | No | `10` | Number of results, an integer from 10 to 100. Sent as `numResults` |
| `timeout` | float | No | `600.0` | Request timeout in seconds |
**Response (`result["data"]`):**
| Key | Type | Description |
| --------- | ------- | ---------------------------------------------------------------------------- |
| `success` | boolean | Whether the search succeeded |
| `message` | string | Status message |
| `data` | list | Ranked results. Each has `rank`, `title`, `url`, `description`, and `source` |
### Account
Use `account` to check the identity, subscription, token quota, and rate limits of the account that owns the API token.
```python
import asyncio
from mrscraper import MrScraper
async def main():
client = MrScraper()
result = await client.account(timeout=30)
print(result["data"]["subscription_status"])
print(result["data"]["token_remaining"])
print(result["data"]["user"]["email"])
asyncio.run(main())
```
**Parameters:**
| Parameter | Type | Required | Default | Description |
| --------- | ----- | -------- | ------- | -------------------------------------------------- |
| `timeout` | float | No | `30.0` | Request timeout in seconds. Must be greater than 0 |
**Account summary (`result["data"]`):**
| Key | Type | Description |
| --------------------- | -------------- | --------------------------------------------- |
| `subscription_status` | string \| None | Subscription status, such as `"active"` |
| `enterprise` | boolean | Whether the account is on an enterprise plan |
| `token_usage` | number | Tokens used in the current period |
| `token_limit` | number | Token limit for the current period |
| `token_remaining` | number | Remaining tokens, never below 0 |
| `usage_percent` | number | Token usage as a percentage of the limit |
| `rate_limit` | number | Request rate limit |
| `rate_ttl` | number | Rate-limit window |
| `auto_renew` | boolean | Whether the subscription renews automatically |
| `ends_at` | string \| None | Subscription end date |
| `user` | dict | `name`, `email`, and `verified` |
API keys, billing identifiers, and sensitive response headers are excluded from the result.
## Error Handling
The SDK raises typed exceptions, which you can import from `mrscraper` or `mrscraper.exceptions`.
### Exception Types
| Exception | When It's Raised |
| --------------------- | ------------------------------------------------- |
| `MrScraperError` | Base class for all SDK errors |
| `AuthenticationError` | Missing or invalid API token (HTTP 401) |
| `APIError` | Non-success API response (exposes `.status_code`) |
| `NetworkError` | Network timeouts or connection failures |
Invalid arguments, such as a `timeout` outside 1-300 or a `num_results` outside 10-100, raise `ValueError` before any request is sent.
### Example Error Handling
```python
from mrscraper import MrScraper, AuthenticationError, APIError, NetworkError
client = MrScraper()
try:
result = await client.scraper_api("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`
## Migrating from Earlier Versions
### From 0.7.x
Version 0.9.0 returns to three public methods. The 0.7.x format-specific methods are no longer public; use `scraper_api` with output flags instead:
| 0.7.x | 0.9.0 |
| --------------------------------------------- | ------------------------------------------------------ |
| `client.scraper_html(url)` | `client.scraper_api(url)` |
| `client.scraper_markdown(url)` | `client.scraper_api(url, html=False, markdown=True)` |
| `client.get_screenshot(url, full_page=False)` | `client.scraper_api(url, html=False, screenshot=True)` |
| `client.web_search(query, region="us")` | `client.web_search(query, country="us")` |
### From 0.6.0
* **`web_search`** now calls the MrScraper API with `action: "websearch"` and returns JSON. Its first argument is `query`, and it accepts `country` and `num_results` (10 to 100). The `raw`, `format`, `region`, `language`, `page`, and `render_js` options and search URL input were removed. Results are at `result["data"]["data"]`.
* **`scraper_api`** adds the `wait_until` option. At least one of `html`, `markdown`, or `screenshot` must be `True`. HTML-only requests return a string, and requests with Markdown or a screenshot return a dictionary with one entry per output.
* **`account`** is unchanged.
### From 0.5.0
Version 0.6.0 adds the [`account`](#account) method. No existing methods changed.
### From 0.4.0
Version 0.5.0 renames a public method. Arguments and response formats are unchanged.
| 0.4.0 | 0.5.0 |
| --------------------------- | ------------------------- |
| `client.fetch_content(...)` | `client.scraper_api(...)` |
The previous method names have been removed.
### From 0.3.x and Earlier
`fetch_html` and the AI scraper, manual scraper, results, and account methods (`create_scraper`, `rerun_scraper`, `bulk_rerun_ai_scraper`, `rerun_manual_scraper`, `bulk_rerun_manual_scraper`, `get_all_results`, `get_result_by_id`, `get_analytic_statuses`) are no longer part of the SDK. `get_subscription_account` is replaced by [`account`](#account).
* Replace `fetch_html` with [`scraper_api`](#scraper-api). It returns a dictionary with `status_code`, `data`, and `headers`.
* For scrapers, results, and analytics, call the [REST API](/docs/api/overview) directly.
## 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 or Markdown output | [`scraper_api`](#scraper-api) with `html=True` and/or `markdown=True` |
| Scrape a URL with a screenshot | [`scraper_api`](#scraper-api) with `screenshot=True` |
| [Search](https://docs.firecrawl.dev/sdks/python) | [`web_search`](#web-search) |
# 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)
```
# Vercel AI SDK
The [`@mrscraper/ai-sdk`](https://www.npmjs.com/package/@mrscraper/ai-sdk) package
provides MrScraper tools for the [Vercel AI SDK](https://ai-sdk.dev). Pass them
to `generateText`, `streamText`, or an agent, and the model can retrieve web
pages, search the web, and check your MrScraper usage while it works.
## Requirements
* AI SDK 7 and Node.js 18 or later.
* A MrScraper API key from [app.mrscraper.com/api-tokens](https://app.mrscraper.com/api-tokens).
## Install
```bash
npm install @mrscraper/ai-sdk ai zod
```
Set your key as an environment variable:
```bash
export MRSCRAPER_API_KEY="your_mrscraper_api_key"
```
The tools read `MRSCRAPER_API_KEY`, then `MRSCRAPER_API_TOKEN`. To pass the key
in code instead, use `mrscraperTools({ apiKey })`.
## Quick start
```ts
import { generateText, isStepCount } from "ai";
import { mrscraperTools } from "@mrscraper/ai-sdk";
const { text } = await generateText({
model: "openai/gpt-5",
prompt:
"Read https://www.scrapethissite.com/pages/simple/ and list the five countries with the largest area.",
tools: mrscraperTools(),
stopWhen: isStepCount(5),
});
```
`mrscraperTools()` returns `scraperAPI`, `webSearch`, and `status`, the same
names the [MrScraper MCP server](/docs/getting-started/mcp-server) uses. To add
only some of them, use the individual factories:
```ts
import { scraperApiTool, webSearchTool } from "@mrscraper/ai-sdk";
const tools = {
scraperAPI: scraperApiTool(),
webSearch: webSearchTool(),
};
```
## Tools
| Tool | Inputs | Returns |
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| `scraperAPI` | `url`; `formats` (`markdown`, `html`, `screenshot`; default `markdown`); optional `browserRendering`, `waitForSelector`, `geoCode`, `timeout` | The requested formats, the API status code, and the tokens used |
| `webSearch` | `query` (search terms or a search results URL); optional `region` (two-letter country, default `us`) and `numResults` (10 to 100, default 10) | Ranked results (`rank`, `title`, `link`, `description`, `source`) |
| `status` | None | Subscription status, token limit, tokens used, and tokens remaining |
Screenshots are sent to the model as images rather than as base64 text.
`scraperAPI` and `webSearch` use tokens from your plan; `status` uses none.
## Errors
API errors, such as an invalid key or an exhausted plan, are thrown from the
tool. The AI SDK reports them to the model as tool errors, so the model can
explain the problem or try another approach. The API key is never included in
an error message.
## Related
* [MCP server](/docs/getting-started/mcp-server): connect MCP clients such as Claude, Cursor, or ChatGPT instead.
* [Node.js SDK](/docs/integrations/node): call the MrScraper API directly.
* [Source on GitHub](https://github.com/mrscraper-com/mrscraper-ai-sdk)
# 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/workflow).
* 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.
# 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
```
# Proxy Status Codes
Proxy error responses identify failures that occur while processing or forwarding a request. Use the HTTP status code and the `Proxy-Status` response header to distinguish proxy-generated errors from responses returned by the destination server.
For SOCKS5 connections, inspect the protocol reply codes instead of HTTP status codes or headers.
## Response Format
The following response fields provide status information:
| Field | Location | Purpose |
| --------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------ |
| HTTP status code | Status line | Identifies the response category. Common proxy errors include `403`, `407`, `502`, `503`, and `504`. |
| `Proxy-Status` header | Response headers | Identifies the reporting proxy and error type, following [RFC 9209](https://www.rfc-editor.org/rfc/rfc9209). |
For example:
```text
HTTP/1.1 504 Gateway Timeout
Proxy-Status: mrscraper; error=connection_timeout
```
This response indicates that the proxy gateway could not connect to the destination website through a proxy exit IP within the allowed time.
## Identifying the Response Source
```http
HTTP/1.1 200 Connection Established
```
* **Source:** MrScraper proxy — success.
* **Meaning:** The HTTPS CONNECT tunnel is open. This is the proxy's confirmation, not the target website's response.
```http
HTTP/1.1 502 Bad Gateway
Proxy-Status: mrscraper; error=connection_terminated
Content-Type: text/plain; charset=utf-8
Bad Gateway
```
* **Source:** MrScraper proxy — failure.
* **Meaning:** The `mrscraper; error=...` entry identifies a proxy-classified failure. Here, the connection closed or reset before the proxy could complete the response.
```http
HTTP/1.1 200 OK
Content-Type: text/html
The requested page.
```
* **Source:** Target website — success.
* **Meaning:** The target returned the requested page, which the proxy relayed to the client.
```http
HTTP/1.1 403 Forbidden
Content-Type: text/html
Access denied by the target website.
```
* **Source:** Target website — failure.
* **Meaning:** The target rejected the request. The proxy relayed its response rather than generating a proxy error.
The target-response examples show typical forwarded responses. Body content and the absence of a `mrscraper` error entry alone do not prove target origin: some proxy-generated failures can also lack that entry.
## HTTPS CONNECT Responses
HTTPS connections through the proxy begin with a `CONNECT` request. Before tunnel establishment, the proxy generates the response:
| Status | `error=` | What it means |
| -----: | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `200` | None | `Connection Established` — the tunnel is open. Subsequent encrypted traffic cannot include a proxy-generated status header. |
| `403` | `http_request_denied_by_policy` | The request was blocked by policy. |
| `407` | None | Client authentication or account access was rejected. |
| `502` | `dns_error` | A hostname needed to complete the request could not be resolved. |
| `502` | `connection_terminated` | The connection closed or reset before the tunnel could be established. |
| `502` | None | The proxy gateway could not open the connection. No more specific error code is available. |
| `503` | `destination_unavailable` | No suitable proxy exit IP is available, or the selected proxy exit IP cannot reach the destination website. |
| `504` | `connection_timeout` | The proxy gateway could not connect to the destination website through a proxy exit IP within the allowed time. |
| `504` | `connection_read_timeout` | Waiting for connection data timed out before the tunnel could be established. |
| `504` | `connection_write_timeout` | Sending data required to establish the tunnel timed out. |
| `504` | `http_response_timeout` | The proxy timed out waiting for a response while establishing the tunnel. |
A CONNECT failure does not return the destination server's application error page because the tunnel has not been established. After `200 Connection Established`, the proxy cannot inspect encrypted application traffic or send a replacement HTTP error. Certificate validation failures, authentication pages, and application errors within the tunnel cannot be reported through `Proxy-Status`. Later transport failures close the connection instead.
`destination_unavailable` means no suitable proxy exit IP is available to complete your request, or the selected proxy exit IP cannot reach the destination website. It does not necessarily mean the website is down. Try again after a short delay or broaden your location targeting.
## SOCKS5
If you use SOCKS5, your proxy client reports SOCKS5 reply codes instead of HTTP status codes. Check your client's error message or logs for the code, then use the tables below to find the next step.
Errors can occur when your client signs in or when it asks the proxy to connect to a website. Check which step failed: the same code can mean different things at each step.
### Sign-In Responses
During sign-in, your client first agrees on an authentication method with the proxy gateway, then sends credentials if required.
| Reply | What it means | Client action |
| ------ | ---------------------------------------------------------------------- | ------------------------------------------------------------------ |
| `0x00` | Sign-in succeeded after your client sent a username and password. | Continue with the request. |
| `0x02` | The proxy gateway selected username/password authentication. | Send credentials. |
| `0xFF` | Your client did not offer a supported authentication method. | Enable username/password authentication. |
| `0x01` | The proxy gateway rejected sign-in after your client sent credentials. | Check your username, password, and account access before retrying. |
### SOCKS5 Connection Responses
After sign-in, your client asks the proxy to connect to the destination website. The proxy returns a code indicating whether that request was accepted or why it failed. Some clients label this code `REP`, which means “reply.”
Codes are shown in hexadecimal, a number format commonly used in client logs. For example, `0x04` is code 4. `0x00` means the request was accepted; other values indicate an error.
| Reply code (`REP`) | Name | What it means | Client action |
| -----------------: | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ |
| `0x00` | Succeeded | The request was accepted. For hostname requests, the tunnel is established. For IP-address requests, connection establishment may still be in progress. | Start application traffic. A later failure can close the connection without another reply. |
| `0x02` | Connection not allowed by ruleset | Destination policy, account restrictions, or request-stage authentication rejected the request. `BIND` is also denied. | Resolve the restriction before retrying. |
| `0x03` | Network unreachable | A network needed to establish the requested connection could not be reached. This does not establish that the destination network is unreachable. | Retry a limited number of times with backoff. |
| `0x04` | Host unreachable | The proxy could not connect. Possible causes include an unavailable proxy exit IP, a connection timeout, or a website address that could not be resolved. This code alone does not mean the website is down. | Check the hostname and targeting options. Retry transient failures with bounded backoff. |
You may also see these client errors:
| Code | What it means | What to do |
| ----------------------------------- | -------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| `0x05` — Connection refused | The proxy gateway encountered a refused connection while connecting through a proxy exit IP. | Follow the same steps as for `0x04`. |
| `0x07` — Command not supported | Your client used an unsupported SOCKS5 command or HTTP-only scraper credentials. | Check your client's SOCKS5 settings and use residential proxy credentials. |
| `0x08` — Address type not supported | Your client sent an unsupported destination address format. | Configure your client to use an IPv4 address, IPv6 address, or domain name. |
Retry a few times, waiting longer after each attempt. Avoid retrying requests that could cause duplicate actions. The website may have already processed the first request.
## Plain HTTP Responses
For unencrypted HTTP requests, the proxy can return the following errors before sending response headers to the client. Classified failures include a `mrscraper; error=...` entry in `Proxy-Status`.
| Status | `error=` | What it means |
| -----: | ------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `403` | `http_request_denied_by_policy` | The request was blocked by policy. |
| `407` | None | Client authentication or account access was rejected. |
| `502` | `dns_error` | A hostname needed to complete the request could not be resolved. |
| `502` | `connection_terminated` | The connection closed or reset before response headers could be sent to the client. |
| `502` | None | The proxy gateway could not complete the request. No more specific error code is available. |
| `503` | `destination_unavailable` | No suitable proxy exit IP is available, or the selected proxy exit IP cannot reach the destination website. |
| `504` | `connection_timeout` | The proxy gateway could not connect to the destination website through a proxy exit IP within the allowed time. |
| `504` | `connection_read_timeout` | Waiting for response data timed out before response headers could be sent to the client. |
| `504` | `connection_write_timeout` | Sending request data timed out before the response could start. |
| `504` | `http_response_timeout` | Waiting for the response to start timed out. |
Once HTTP response headers have been sent, a later read timeout or connection termination cannot replace the response with a new `502`, `504`, or `Proxy-Status` header. The client observes a truncated response or a closed connection instead.
## When to Retry
For temporary connection failures, limit the number of retries and wait progressively longer between attempts. Add a small random delay to avoid sending all retries at once.
### HTTP and HTTPS CONNECT
The following guidance applies to plain HTTP responses and HTTPS CONNECT responses before the tunnel opens.
| Response | Client retry guidance |
| --------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Proxy-generated `403` | Do not retry the identical request automatically. Resolve the policy restriction or change the destination. |
| `407` | Do not retry unchanged credentials indefinitely. Check credentials and account access. If those are correct and the rejection persists, contact support. |
| Proxy-generated `502` | Retry a limited number of times for transient connection failures, including `connection_terminated` or an unclassified failure. If errors persist, check the destination and targeting options, then contact support. |
| Proxy-generated `503` | Retry with backoff if availability may recover. If no proxy exit IP matches your location targeting, broaden the targeting instead of repeatedly sending the identical request. |
| Proxy-generated `504` | Retry with backoff. A proxy timeout does not prove that the destination did not receive or process the request. |
| A destination response, including `403`, `429`, or `5xx` | Follow the destination's retry policy and any `Retry-After` header. Do not treat it as a proxy failure solely because of the HTTP status. |
| Connection closure after CONNECT success or a truncated HTTP response | Reconnect and retry only if replaying the application request is safe. There may be no replacement HTTP error or proxy status header. |
### SOCKS5
Check whether the code occurred during sign-in or while connecting to the destination.
| Response | Client retry guidance |
| --------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| Sign-in rejected (`0x01`) or no supported authentication method (`0xFF`) | Check your username, password, account access, and client authentication settings before retrying. |
| Connection not allowed (`0x02`) | Resolve the destination or account restriction before retrying. |
| Network unreachable (`0x03`), host unreachable (`0x04`), or connection refused (`0x05`) | Retry a limited number of times with increasing delays. If errors persist, check the destination and location targeting, then contact support. |
| Unsupported command (`0x07`) or address type (`0x08`) | Correct your client settings before retrying. |
| Connection closes after a successful reply (`0x00`) | Reconnect and retry only if the application request is safe to repeat. The destination may already have received it. |
Only replay requests that are safe to repeat, such as idempotent operations or requests protected by an application-supported idempotency key. Ensure request bodies can be replayed. If the response was lost after the destination processed a request, retrying a non-idempotent operation can duplicate its effects.
# 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 | ✅ Spreading load across IPs | ✅ Appearing as different users |
| ✅ High-volume data extraction | ✅ Distributing load across IPs | ✅ Avoiding IP-based blacklists |
| ✅ Distributed scraping tasks | ✅ Reducing ban risk | ✅ Region-specific content checks |
| ✅ 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)
* Spreading requests across IPs
* Maximum IP distribution
* No session persistence needed
# Target Blocklist
## How Target Blocklist Works
Target Blocklist lets you choose which targets your Residential Proxy should block, helping you keep unwanted requests from consuming your bandwidth.
Manage your rules in the **Save your bandwidth** tab on the Residential Proxy page.
**Behavior:**
* Add up to **50 target entries** to your User Blocklist
* Start blocking without a schedule or choose a future start time
* Changes apply to your account and everyone on your team after saving
* This customer tab shows user entries only; global blocklist entries are not
shown or editable here
* Adding, editing, or removing an entry does not save it automatically
**Shared rules:** If you are using a team account, you edit the team's shared
blocklist, not a separate list for yourself. Review changes with your team
before saving.
## Add a Target
1. Open the **Residential Proxy** page.
2. Select the **Save your bandwidth** tab.
3. In **User Blocklist**, click **Add target**.
4. Enter a target: a hostname, IP address, or CIDR range.
5. Leave **Starts at (UTC)** blank to apply the block as soon as your saved changes take effect, or select a start date and time.
6. Click **Save changes**.
After a successful save, the page shows **All changes saved**.
Your changes will be propagated into our system within around 2 minutes. If it
takes longer, contact our support.
**Save before leaving:** Your changes only apply after you click **Save
changes**. If saving fails, your edits remain on the page so you can try
again.
## Accepted Target Formats
Each target must be a **hostname**, an **IP address**, or a **CIDR range**.
### Hostname
Include the domain extension, and use at least one dot. A hostname also blocks its subdomains.
**Format:**
```
abc.com
```
**Example matches:**
* `www.abc.com`
* `sub.abc.com`
* `dev.sub.abc.com`
### IP Address
Enter a single IPv4 address without a port.
**Formats:**
```
1.2.3.4
```
### CIDR Range
Enter an IPv4 address with a prefix length from 0 to 32.
**Formats:**
```
10.0.0.0/8
```
### Not Accepted
These values are rejected when you save:
```
https://abc.com
abc.com/path
abc.com:443
*.abc.com
abc
10.0.0.0/33
```
**Enter the target on its own:** Do not include a scheme, path, port,
wildcard, or spaces. Wildcards are never needed because subdomains are already
blocked, and a hostname needs at least one dot.
## Schedule When Blocking Starts
Each entry has an optional **Starts at (UTC)** field.
| Start time | Behavior |
| -------------------- | --------------------------------------------------- |
| Blank | Blocking starts once your saved changes take effect |
| Future date and time | Blocking starts at the scheduled time |
**Example:**
To start blocking `abc.com` at a future time:
1. Add `abc.com` to your User Blocklist.
2. Set the **Starts at (UTC)** value on the entry.
3. Click **Save changes** before the scheduled time.
**Use UTC:** All start times are in UTC. Convert your local time to UTC before
choosing a start time.
## Edit or Remove a Target
### Edit an Entry
1. Find the entry in **User Blocklist**.
2. Update its **Target** or **Starts at (UTC)** value.
3. Click **Save changes**.
### Remove an Entry
1. Click the delete button beside the entry.
2. Click **Save changes**.
## Blocklist Limits
* You can save up to **50 user target entries**.
* Every entry must use an accepted format before you can save.
* Scheduled entries count toward the limit, even before their start time.
* At the limit, remove an existing entry before adding another.
* Every entry must have a target value before you can save.
## Best Practices
* Enter a hostname with at least one dot (`abc.com`), an IP address (`1.2.3.4`), or a CIDR range (`10.0.0.0/8`).
* Add one hostname, IP address, or CIDR range per entry.
* Start with targets you know your workflow does not need.
* Review shared rules with your team to avoid interrupting their requests.
* Check your workflow after saving to make sure required targets remain accessible.
## Common Issues
### Only Some Targets Are Blocked
* Check that the entry uses an accepted format: a hostname with a dot, an IP address, or a CIDR range.
* Compare the target with the accepted formats above.
* Check for typos in each entry.
* Make sure you clicked **Save changes** and allow around 2 minutes for your changes to take effect.
* If you set a start time, confirm that it has passed in UTC.
### Save Changes Is Disabled
* Check whether there are any unsaved changes.
* Fix any target marked as invalid below its field.
* Fill in every empty **Target** field, or remove unused entries.
* Make sure the list contains no more than 50 entries.
* Wait for the blocklist to finish loading or saving.
### The Blocklist Could Not Load
* Click **Retry** to load your saved rules again.
* If your team account could not be resolved, reload the page and try again.
* Editing is disabled while the blocklist is unavailable to avoid overwriting rules you cannot see.
### Changes Could Not Be Saved
* Your edits remain on the page after a save error.
* Keep the page open, check your connection, and try **Save changes** again.
* Wait for **All changes saved** before leaving the page.
# CloakBrowser
CloakBrowser is an open source Chromium-based browser developed by CloakHQ, with Playwright-like APIs for browser automation.
CloakBrowser code examples divided by programming language (JavaScript and Python) for browser automation with Residential Proxy.
## JavaScript (Node.js)
### Prerequisites
```bash
npm install cloakbrowser proxy-chain
npx cloakbrowser install
```
* `cloakbrowser`: Node.js browser automation library built on Chromium with 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 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 testProxy() {
// Launch the 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 Proxy IP:', content)
await browser.close()
}
testProxy().catch(console.error)
```
**Use Case:** Baseline proxy connectivity check and 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 runStickySession() {
const browser = await launch({
headless: true,
proxy: {
server: 'http://proxy.mrscraper.com:10000',
// 30-minute Canadian static session
username: 'user-country-ca-sessid-session1-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()
}
runStickySession().catch(console.error)
```
**Use Case:** Executing multi-page JavaScript workflows that need a consistent IP across navigations.
### 3. Parallel 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(`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 its own browser instance 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 safeScrape(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()
}
}
}
safeScrape('https://example.com')
```
**Use Case:** Deploying Node.js scrapers that handle timeouts and site exceptions safely.
***
## Python
### Prerequisites
```bash
pip install cloakbrowser
python -m cloakbrowser install
```
* `cloakbrowser`: Python package for Chromium browser automation.
* 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 Request
Demonstrates launching CloakBrowser using its Python API to route automated browser requests through a residential proxy.
```python
from cloakbrowser import launch
def test_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 Proxy IP:", page.text_content("body"))
browser.close()
if __name__ == "__main__":
test_proxy()
```
**Use Case:** Quick proxy verification script in Python.
### 2. Sticky Session Navigation
Maintains a static Python 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 workflows that require session IP continuity.
### 3. Geotargeting
Demonstrates routing Python CloakBrowser traffic through a German residential proxy.
```python
from cloakbrowser import launch
def geotargeted_session():
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("Browser Headers:\n", page.text_content("body"))
browser.close()
if __name__ == "__main__":
geotargeted_session()
```
**Use Case:** Retrieving the version of an international website served to a specific country.
### 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_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_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 the browser 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 from a specific region.
## 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">
Chromium 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")`).
# 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 195+ 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 workspace for running on-demand, proxy-powered scraping requests. It shares the same interface layout as the [Scraper API](/docs/getting-started/scraper-api) 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.
Each proxy scrape includes a fixed 4MB cost for the browser session and request handling, in addition to the page content itself.
## 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 itself. This guide walks you through a structured process to isolate the cause and resolve it.
## Why requests to a target website fail
Even with residential proxy IPs, a request can still fail if:
* **The website restricts automated access** through its terms of service or access controls.
* **The content depends on JavaScript** and the request is made without browser rendering.
* **The content is region-specific** and the selected proxy country doesn't match.
* **Rate limiting** rejects IPs that send too many requests in a short period.
* **The website is slow or unavailable** and the request times out.
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 issue is in your own script or integration. | 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 not returning the page. | Go to [When the target website fails](#when-the-target-website-fails). |
| ❌ 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 reject requests that lack a `User-Agent` header. Make sure your client sends one.
* Include standard headers like `Accept`, `Accept-Language`, and `Accept-Encoding`.
### 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.
## When the target website fails
If Proxy Scraper can reach google.com but fails on your target URL, try the following 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
### Adjust timeout and retries
Increase the **Timeout** beyond the default 90 seconds, and set **Max retries** to 5 or higher. Some 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 failing, the proxy is the easiest thing to blame. But in most cases the target website has changed how it handles automated requests, 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 differently from a normal visit. 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 fail 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 Chromium-based 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 fails, retry with CloakBrowser
[CloakBrowser](/docs/residential-proxy/examples/cloakbrowser) is an open source Chromium-based browser. Comparing it with regular Chrome tells you whether the result depends on the browser rather than the IP.
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. The difference is in how your scraper sends requests, such as its headers or 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. |
| ❌ Fails in Chrome, ✅ works in CloakBrowser | The IPs are fine. The result depends on the browser, not the IP. | See the [CloakBrowser examples](/docs/residential-proxy/examples/cloakbrowser). |
| ❌ Fails 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. |
| ❌ Fails in both, and the site also fails 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 configuration can reject a healthy residential IP when the request doesn't match a normal browsing session. Running this test before escalating saves you from swapping proxies that were never the problem.
# Get Brand
Read a brand you already scraped with [Scrape Brand](/docs/api/scraper-api/scrape-brand/scrape-brand), or download one of its files.
* Use the Scraper API Server (`https://api.mrscraper.com`) host when calling this endpoint.
* Pass the job ID from `data.job_id` as `id`. You can also find it in the **Result** tab of the Scraper API.
* Omit `output` to return the brand job as JSON. Set `output` to `html`, `bundle`, `screenshot`, or `screenshot_full` to download a file.
* A job scraped with `bundle=none` only has the HTML to download. Jobs scraped with `bundle=clean` or `bundle=full` have all four files.
# Scrape Brand
Scrape the brand of a page. The request waits until the job settles, then returns the brand in `data.brand` and the job ID in `data.job_id`.
* Use the Scraper API Server (`https://api.mrscraper.com`) host when calling this endpoint.
* Set `bundle` to `none` for the brand JSON only, `clean` to add the HTML, screenshots, and a ZIP of the page without scripts, or `full` to keep the page scripts in the ZIP.
* `none` usually answers in a few seconds. `clean` and `full` can take about a minute, so set a generous client timeout.
* Use the job ID with [Get Brand](/docs/api/scraper-api/scrape-brand/get-brand) to read the brand again or download its files.
* See [Scrape Brand](/docs/getting-started/scraper-api/scrape-brand) in the Scraper API guide for the bundle contents and code examples.
# 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 Platform API Server (`https://api.app.mrscraper.com`) host when calling this endpoint.
# 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) |
# Web Fetching
This endpoint scrapes a target URL with the Web Fetching feature that supports browser rendering, geo-targeting via proxy, and waiting for specific DOM selectors before extracting content.
* Use the Scraper API Server (`https://api.mrscraper.com`) host when calling this endpoint.
* This is the same endpoint as `Scrape HTML` in Scraper API.
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
# 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 Scraper API 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 workflow.
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 Scraper API 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. Open the [**New AI Scraper**](https://app.mrscraper.com/scrapers/form) page.
2. Select the **Listing Scraper** option.
3. 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`.
4. 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. workflow 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 [Scraper API](/docs/getting-started/scraper-api), 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 [Scraper API Token Cap](/docs/getting-started/api-token#scraper-api-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/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/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/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/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. Open the [**New AI Scraper**](https://app.mrscraper.com/scrapers/form) page.
2. Select the **Listing Scraper** option.
3. In the **URL** field, enter the URL of the Michigan property listings page: `https://www.redfin.com/state/Michigan`.
4. 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. Open the [**New AI Scraper**](https://app.mrscraper.com/scrapers/form) page.
2. 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`.
3. 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. Open the [**New AI Scraper**](https://app.mrscraper.com/scrapers/form) page.
2. Select the **Listing Scraper** option.
3. 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
```
4. 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.
# 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 open the [**New AI Scraper**](https://app.mrscraper.com/scrapers/form) page
AI Scrapers are created from their own page. The **Create Workflow** button on the Workflow page opens the manual workflow builder instead.
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 **Workflow** 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, static websites. |
| **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 reliable on complex websites. |
Start with **Cheap Mode** for testing. Switch to **Super Mode** if requests fail or you 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 fails during the initial run. Some websites serve different content depending on the visitor's region.
Changing the proxy country lets you retrieve region-specific content.
## Workflow API Access
Once your first scraping session is set up, Workflow API Access 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 open the [**New AI Scraper**](https://app.mrscraper.com/scrapers/form) page
AI Scrapers are created from their own page. The **Create Workflow** button on the Workflow page opens the manual workflow builder instead.
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.
# 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 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 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. */}
# Workflow
import { Step, Steps } from 'fumadocs-ui/components/steps';
import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';
A **Workflow** in MrScraper lets you build a custom scraping sequence 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 a Workflow
Use a Workflow 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.
## Workflow Features
### Step Types
Below are the available step types you can add in the **Steps** panel when building a workflow:
| 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 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/workflow-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/workflow-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 a Workflow and inject a small custom JavaScript snippet.
Follow the steps below:
Log in to **MrScraper**, then click **Workflow** in the left sidebar.
Click **+ Create Workflow** at the top to open the **New Workflow** page.
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.
Select **Save & Run** to save the workflow and run it immediately, or **Save** to store it without running.
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 Workflow to automate the steps.
Follow the steps below:
Log in to **MrScraper**, then click **Workflow** in the left sidebar.
Click **+ Create Workflow** at the top to open the **New Workflow** page.
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;
})()
```
Select **Save & Run** to save the workflow and run it immediately, or **Save** to store it without running.
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 **Workflow** builder.
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 Workflow 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 workflow still fails, open the **Scraper API**, turn on **Super** mode, and add your Workflow steps as Scraper API automation steps. Super mode routes the request through a real browser environment.
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/workflow-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 workflow keeps running but returns empty or partial data. **Self-Healing** uses AI to automatically generate, repair, and extend 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 workflow 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 workflow 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 workflow"
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 workflow you want to repair (found in the scraper URL or API Access modal) |
See [Self-Heal a Manual Scraper](/docs/api/v3/scraper/manual/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 do not load reliably through standard routing. By default, a workflow accesses pages through our cloud infrastructure. Super mode routes your request through a real device instead, which can improve success rates on complex websites.
## How to Use Super Mode
Super mode is not a toggle inside the scraper builder. To run a workflow in Super mode, follow these steps :
Open the workflow 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 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';
Workflows combine low-code 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 Workflow.
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 Workflow **Listen Network** step.
### Setup Steps
Open the target URL in a Workflow.
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 Workflow.
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/workflow-scraper#troubleshooting) on the Workflow page.
# Get Screenshot
## Overview
Selecting **Get Screenshot** in the Scraper API Use Case panel pre-configures the Scraper API environment specifically for visual page capture. When this preset is active, the Scraper API 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 cookie banners, error pages, 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 :
# Scraper API
import { Play, Code2, FileJson, Wand2 } from 'lucide-react';
import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';
The [**Scraper API**](https://app.mrscraper.com/scraper-api) 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.
## Scraper API Overview
The Scraper API 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. | Complex websites or pages with 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 Scraper API. It applies to Web Fetching and Workflow 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 [Scraper API Token Cap](/docs/getting-started/api-token#scraper-api-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 and geo-targeting.
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 a website's colors, typography, logos, and metadata as brand JSON, with optional page bundles.
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.
Some websites do not load reliably with default settings. Work through these steps in order:
1. Go to **Basic Settings** and turn on **Super** mode. This routes the request through a real browser environment.
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 Scraper API 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/scraper-api/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 Brand
## Overview
Selecting **Scrape Brand** in the Scraper API Use Case panel extracts the brand identity of a website from a single URL. The result is a brand JSON that describes how the site looks and who is behind it: the color palette, button styles, CSS variables, fonts and heading styles, logos and icons, social profiles, contact details, organization data, and Open Graph and Twitter metadata.
The only input is the target URL. You choose how much of the page to keep alongside the brand JSON with the **Page bundle** option.
### Practical Applications
* **Design System Bootstrapping**: Pull a site's colors, fonts, and button styles to seed a theme, design tokens, or a style guide.
* **Brand-Aware AI Generation**: Give AI agents and generators the exact palette, typography, and logo of a brand so their output matches it.
* **Lead Enrichment & CRM**: Enrich company records with logos, favicons, social profiles, and descriptions from a domain.
* **Competitor Brand Monitoring**: Track changes to a competitor's palette, typography, or messaging over time.
* **Page Archiving & Offline Review**: Save a self-contained copy of a page with its assets and screenshots for audits or design review.
## Page Bundle
| Option | Returns | Typical duration |
| --------- | ------------------------------------------------------------------------------ | ---------------- |
| **None** | Brand JSON only. The fastest option. | A few seconds |
| **Clean** | Brand JSON, plus the HTML, screenshots, and a ZIP of the page without scripts. | About a minute |
| **Full** | Same as **Clean**, with the page scripts kept in the ZIP. | About a minute |
Set the option with the `bundle` query parameter: `bundle=none`, `bundle=clean`, or `bundle=full`.
Every brand scrape returns a job ID. You can find it in the **Result** tab of the Scraper API and in `data.job_id` of the API response. Use it to read the brand again or download its files later without scraping the page again.
## Default Parameters
| Parameter | Description |
| --------------------- | ---------------------------------------------------------------------- |
| action=brand-scraping | Used by this use case to extract the brand of the page. |
| bundle | Page bundle to return: `none`, `clean`, or `full`. (Default to `none`) |
| url | The URL-encoded target URL. |
## Example
### Request
Scrape the brand of `https://mrscraper.com/` with **Page bundle** set to `None`.
```sh title="Request"
curl -X POST 'https://api.mrscraper.com/?action=brand-scraping&bundle=none&url=https%3A%2F%2Fmrscraper.com%2F' \
-H 'x-api-token: {MRSCRAPER_API_TOKEN}' \
-H 'content-type: application/json' \
-d '{"url":"https://mrscraper.com/"}'
```
To return the page bundle as well, change `bundle=none` to `bundle=clean` or `bundle=full`.
### Response
The request waits until the job settles, then returns:
| Field | Description |
| --------------------- | --------------------------------------------------------------- |
| `job_id` | Job ID, used to read the brand again or download its files. |
| `status` | Job status, such as `succeeded`. |
| `url` | The URL you requested. |
| `final_url` | The URL the page ended on, after redirects. |
| `brand` | The brand JSON. |
| `error` | Error message, if the job failed. |
| `html_url` | Path to download the page HTML. |
| `bundle_url` | Path to download the ZIP bundle. `null` for **None**. |
| `screenshot_url` | Path to download the viewport screenshot. `null` for **None**. |
| `full_screenshot_url` | Path to download the full-page screenshot. `null` for **None**. |
```json title="Response"
{
"data": {
"job_id": "",
"status": "succeeded",
"url": "https://mrscraper.com/",
"final_url": "https://mrscraper.com/",
"brand": {
"colors": {
"background": "#050606",
"button": {
"background": "#00b7ff",
"border_color": "#020617",
"border_radius": "12px",
"color": "#020617",
"font_family": "Poppins, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\", sans-serif",
"font_weight": "600",
"padding": "12px",
"text": "Accept all",
"text_transform": "none"
},
"color_scheme": "normal",
"css_variables": {
"--color-accent": {
"hex": "#06b6d4",
"value": "#06b6d4"
},
"--color-black": {
"hex": "#000000",
"value": "#000"
},
"--color-cyan-100": {
"hex": "#cffafe",
"value": "#cffafe"
},
"--color-cyan-200": {
"hex": "#a5f3fc",
"value": "#a5f3fc"
},
"--color-cyan-300": {
"hex": "#67e8f9",
"value": "#67e8f9"
},
"--color-cyan-400": {
"hex": "#22d3ee",
"value": "#22d3ee"
},
"--color-cyan-50": {
"hex": "#ecfeff",
"value": "#ecfeff"
},
"--color-cyan-500": {
"hex": "#00b7ff",
"value": "#00b7ff"
},
"--color-cyan-600": {
"hex": "#0891b2",
"value": "#0891b2"
},
"--color-cyan-700": {
"hex": "#0e7490",
"value": "#0e7490"
},
"--color-cyan-800": {
"hex": "#155e75",
"value": "#155e75"
},
"--color-cyan-900": {
"hex": "#164e63",
"value": "#164e63"
},
"--color-footer-from": {
"hex": "#15212d",
"value": "#15212d"
},
"--color-footer-to": {
"hex": "#082e36",
"value": "#082e36"
},
"--color-gray-100": {
"hex": "#f3f4f6",
"value": "#f3f4f6"
},
"--color-gray-200": {
"hex": "#e5e7eb",
"value": "#e5e7eb"
},
"--color-gray-300": {
"hex": "#d1d5db",
"value": "#d1d5db"
},
"--color-gray-400": {
"hex": "#9ca3af",
"value": "#9ca3af"
},
"--color-gray-500": {
"hex": "#6b7280",
"value": "#6b7280"
},
"--color-gray-600": {
"hex": "#4b5563",
"value": "#4b5563"
},
"--color-gray-700": {
"hex": "#374151",
"value": "#374151"
},
"--color-gray-800": {
"hex": "#1f2937",
"value": "#1f2937"
},
"--color-gray-900": {
"hex": "#111827",
"value": "#111827"
},
"--color-gray-950": {
"hex": "#030712",
"value": "#030712"
},
"--color-ink": {
"hex": "#0d1625",
"value": "#0d1625"
},
"--color-page": {
"hex": "#050606",
"value": "#050606"
},
"--color-panel": {
"hex": "#0d1117",
"value": "#0d1117"
},
"--color-primary-300": {
"hex": "#67e8f9",
"value": "#67e8f9"
},
"--color-primary-400": {
"hex": "#22d3ee",
"value": "#22d3ee"
},
"--color-primary-500": {
"hex": "#00b7ff",
"value": "#00b7ff"
},
"--color-primary-600": {
"hex": "#0891b2",
"value": "#0891b2"
},
"--color-primary-700": {
"hex": "#0e7490",
"value": "#0e7490"
},
"--color-slate-100": {
"hex": "#f1f5f9",
"value": "#f1f5f9"
},
"--color-slate-200": {
"hex": "#e2e8f0",
"value": "#e2e8f0"
},
"--color-slate-300": {
"hex": "#cbd5e1",
"value": "#cbd5e1"
},
"--color-slate-400": {
"hex": "#94a3b8",
"value": "#94a3b8"
},
"--color-slate-50": {
"hex": "#f8fafc",
"value": "#f8fafc"
},
"--color-slate-600": {
"hex": "#475569",
"value": "#475569"
},
"--color-slate-700": {
"hex": "#334155",
"value": "#334155"
},
"--color-slate-800": {
"hex": "#1e293b",
"value": "#1e293b"
},
"--color-slate-900": {
"hex": "#0f172a",
"value": "#0f172a"
},
"--color-slate-950": {
"hex": "#020617",
"value": "#020617"
},
"--color-surface": {
"hex": "#0e1219",
"value": "#0e1219"
},
"--color-tile": {
"hex": "#171e28",
"value": "#171e28"
},
"--color-white": {
"hex": "#ffffff",
"value": "#fff"
},
"--tw-ring-offset-color": {
"hex": "#ffffff",
"value": "#fff"
}
},
"link": "#f1f5f9",
"palette": [
{
"hex": "#050606",
"roles": [
"background",
"text"
],
"share": 0.953
},
{
"hex": "#9ca3af",
"roles": [
"text"
],
"share": 0.011
},
{
"hex": "#171e28",
"roles": [
"background"
],
"share": 0.01
},
{
"hex": "#ffffff",
"roles": [
"text",
"border",
"background"
],
"share": 0.01
},
{
"hex": "#0d1625",
"roles": [
"text",
"background"
],
"share": 0.007
},
{
"hex": "#f1f5f9",
"roles": [
"text",
"background"
],
"share": 0.004
},
{
"hex": "#0a0a0f",
"roles": [
"background"
],
"share": 0.001
},
{
"hex": "#00b7ff",
"roles": [
"background",
"text"
],
"share": 0.001
},
{
"hex": "#cbd5e1",
"roles": [
"text"
],
"share": 0.001
},
{
"hex": "#1f2937",
"roles": [
"border"
],
"share": 0
},
{
"hex": "#e5e7eb",
"roles": [
"text"
],
"share": 0
},
{
"hex": "#1e2d37",
"roles": [
"background"
],
"share": 0
},
{
"hex": "#22d3ee",
"roles": [
"text"
],
"share": 0
},
{
"hex": "#06b6d4",
"roles": [
"text"
],
"share": 0
},
{
"hex": "#000000",
"roles": [
"text"
],
"share": 0
},
{
"hex": "#020617",
"roles": [
"text"
],
"share": 0
}
],
"text": "#000000",
"theme": null,
"tile": null
},
"contact": {
"emails": [],
"phones": []
},
"description": "Turn any website into structured JSON with plain-English prompts or a visual recorder. Schedule jobs, send data to your database. Start free, 1,000 tokens.",
"icons": {
"all": [
{
"color": null,
"rel": "apple-touch-icon",
"sizes": "180x180",
"type": null,
"url": "https://mrscraper.com/apple-touch-icon.png"
},
{
"color": null,
"rel": "icon",
"sizes": "32x32",
"type": "image/png",
"url": "https://mrscraper.com/favicon-32x32.png"
},
{
"color": null,
"rel": "icon",
"sizes": "16x16",
"type": "image/png",
"url": "https://mrscraper.com/favicon-16x16.png"
},
{
"color": null,
"rel": "shortcut icon",
"sizes": null,
"type": null,
"url": "https://mrscraper.com/favicon-32x32.png"
},
{
"color": "#0d1625",
"rel": "mask-icon",
"sizes": null,
"type": null,
"url": "https://mrscraper.com/safari-pinned-tab.svg"
},
{
"color": null,
"rel": "manifest",
"sizes": "192x192",
"type": "image/png",
"url": "https://mrscraper.com/android-chrome-192x192.png"
},
{
"color": null,
"rel": "manifest",
"sizes": "512x512",
"type": "image/png",
"url": "https://mrscraper.com/android-chrome-512x512.png"
}
],
"apple_touch_icon": "https://mrscraper.com/apple-touch-icon.png",
"favicon": "https://mrscraper.com/favicon-32x32.png",
"mask_icon": {
"color": "#0d1625",
"rel": "mask-icon",
"sizes": null,
"type": null,
"url": "https://mrscraper.com/safari-pinned-tab.svg"
}
},
"language": "en",
"logo": {
"source": "json-ld",
"url": "https://mrscraper.com/images/logo-blue.png"
},
"logos": [
{
"source": "json-ld",
"url": "https://mrscraper.com/images/logo-blue.png"
},
{
"alt": null,
"height": 24,
"source": "header-home-link",
"url": "data:image/svg+xml;charset=utf-8,%3Csvg%20class%3D%22w-auto%20h-5%20sm%3Ah-6%22%20viewBox%3D%220%200%20875%20153%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%20%3Cpath%20d%3D%22M0%200%20C4.38502646%203.27945662%208.21896254%207.05250177%2012%2011%20C12.61359375%2011.6290625%2013.2271875%2012.258125%2013.859375%2012.90625%20C24.77288348%2024.83235205%2030.17152578%2040.77890526%2030.09765625%2056.80859375%20C30.09443359%2058.04931641%2030.09121094%2059.29003906%2030.08789062%2060.56835938%20C30.07951172%2061.84517578%2030.07113281%2063.12199219%2030.0625%2064.4375%20C30.05798828%2065.74138672%2030.05347656%2067.04527344%2030.04882812%2068.38867188%20C30.03709261%2071.59246777%2030.0191587%2074.7962399%2030%2078%20C25.38%2078%2020.76%2078%2016%2078%20C15.98582031%2076.00839844%2015.97164063%2074.01679687%2015.95703125%2071.96484375%20C15.68613819%2053.60431441%2015.26197714%2037.93778995%203%2023%20C2.23816406%2022.01386719%201.47632812%2021.02773438%200.69140625%2020.01171875%20C-1.96829292%2016.84385751%20-5.07318294%2014.56231859%20-8.5625%2012.375%20C-9.1716626%2011.98892578%20-9.7808252%2011.60285156%20-10.40844727%2011.20507812%20C-17.94741788%206.59341649%20-26.14779892%203.66809065%20-35%203%20C-35.63679688%202.9484375%20-36.27359375%202.896875%20-36.9296875%202.84375%20C-51.05533352%202.22284248%20-64.68079579%207.12401356%20-75.3125%2016.3125%20C-89.72788375%2030.15034434%20-94.16418243%2044.3960524%20-94.625%2064%20C-94.66325652%2065.36069998%20-94.70231248%2066.72137774%20-94.7421875%2068.08203125%20C-94.83596839%2071.38780764%20-94.9190513%2074.6938845%20-95%2078%20C-99.62%2078%20-104.24%2078%20-109%2078%20C-109.50727766%2051.95974688%20-108.28323842%2028.89473524%20-89.4375%208.875%20C-65.19654394%20-14.15757003%20-28.35228637%20-18.2831141%200%200%20Z%20%22%20fill%3D%22%231BD0EF%22%20transform%3D%22translate(109%2C11)%22%20class%3D%22fill-%5B%231BD0EF%5D%22%3E%3C%2Fpath%3E%20%3Cpath%20d%3D%22M0%200%20C4.95%200%209.9%200%2015%200%20C15.4125%201.258125%2015.825%202.51625%2016.25%203.8125%20C17.55846117%207.28944377%2018.58720872%209.2418954%2022%2011%20C25.26098083%2012.02144175%2028.28447006%2012.13756286%2031.69140625%2012.17578125%20C32.80193359%2012.19962891%2033.91246094%2012.22347656%2035.05664062%2012.24804688%20C37.36635754%2012.29050964%2039.67630548%2012.32203057%2041.98632812%2012.34179688%20C51.55857695%2012.57876101%2060.039235%2014.04520664%2067.375%2020.5625%20C71.88499263%2025.49936436%2076%2032.16869391%2076%2039%20C72.04%2040.32%2068.08%2041.64%2064%2043%20C63.443125%2042.071875%2062.88625%2041.14375%2062.3125%2040.1875%20C59.20347249%2035.9020837%2056.12749992%2034.01499999%2051%2033%20C49.00845072%2032.8874122%2047.01398299%2032.82233134%2045.01953125%2032.7890625%20C43.85486328%2032.76070312%2042.69019531%2032.73234375%2041.49023438%2032.703125%20C39.05808854%2032.65145966%2036.62577622%2032.60706785%2034.19335938%2032.5703125%20C26.34723028%2032.36303996%2019.03385726%2032.05317883%2012.58984375%2027.17578125%20C12.04457031%2026.56089844%2011.49929687%2025.94601563%2010.9375%2025.3125%20C10.36902344%2024.68988281%209.80054687%2024.06726563%209.21484375%2023.42578125%20C8.81394531%2022.95527344%208.41304688%2022.48476562%208%2022%20C7.34644531%2022.59748047%207.34644531%2022.59748047%206.6796875%2023.20703125%20C-0.08412178%2029.22418626%20-5.90494025%2032.07925524%20-14.98046875%2032.17578125%20C-16.14513672%2032.19962891%20-17.30980469%2032.22347656%20-18.50976562%2032.24804688%20C-20.94188457%2032.29067031%20-23.37422791%2032.32210654%20-25.80664062%2032.34179688%20C-32.83388851%2032.50809938%20-39.03313179%2032.97866699%20-45%2037%20C-46.74338617%2038.93792328%20-47.78006956%2040.66622003%20-49%2043%20C-52.96%2041.68%20-56.92%2040.36%20-61%2039%20C-59.61559367%2030.69356205%20-55.92403034%2023.50199821%20-49.04760742%2018.34936523%20C-41.05788248%2013.08416793%20-33.17232578%2012.4428638%20-23.8125%2012.4375%20C-13.48289286%2012.54586808%20-13.48289286%2012.54586808%20-4%209%20C-1.63433042%205.92462955%20-0.95327374%203.81309495%200%200%20Z%20%22%20fill%3D%22%231BD0EF%22%20transform%3D%22translate(62%2C85)%22%20class%3D%22fill-%5B%231BD0EF%5D%22%3E%3C%2Fpath%3E%20%3Cpath%20d%3D%22M0%200%20C14.78669703%20-0.58561176%2025.43363984%200.39597013%2037.4375%209.9375%20C39%2012%2039%2012%2038.9375%2014.375%20C37.8587282%2017.39556105%2036.51190999%2020.17338567%2035%2023%20C31.619024%2022.56374503%2029.00950376%2021.54154424%2026%2020.03125%20C20.71150664%2017.64410892%2015.67840529%2017.13352603%209.9375%2016.75%20C8.97650391%2016.67265625%208.01550781%2016.5953125%207.02539062%2016.515625%20C4.68469904%2016.32930129%202.34246042%2016.16258173%200%2016%20C0%2010.72%200%205.44%200%200%20Z%20%22%20fill%3D%22%231BD0EF%22%20transform%3D%22translate(77%2C54)%22%20class%3D%22fill-%5B%231BD0EF%5D%22%3E%3C%2Fpath%3E%20%3Cpath%20d%3D%22M0%200%20C2.93541736%202.21946191%203.80586845%203.75551459%204.37109375%207.37890625%20C4.57248865%2011.47393588%204.31647412%2014.32577253%202.5625%2018.0625%20C-1.10202646%2020.83323952%20-4.45566287%2021.29213596%20-9%2021%20C-12.670261%2019.43818681%20-13.7727373%2018.34089404%20-16%2015%20C-16.70764306%2010.14523949%20-16.709087%206.19811251%20-14.1875%201.9375%20C-9.87585601%20-1.88138467%20-5.29701283%20-1.34815669%200%200%20Z%20%22%20fill%3D%22%231BD0EF%22%20transform%3D%22translate(46%2C53)%22%20class%3D%22fill-%5B%231BD0EF%5D%22%3E%3C%2Fpath%3E%20%3Cpath%20d%3D%22M211.052%20118.813L187.102%2040.8361H186.545C186.638%2042.6927%20186.777%2045.4776%20186.963%2049.1907C187.148%2052.9039%20187.334%2056.8956%20187.519%2061.1657C187.705%2065.3431%20187.798%2069.1491%20187.798%2072.5838V118.813H169V19.3924H197.684L221.217%2095.4199H221.634L246.559%2019.3924H275.243V118.813H255.61V71.7483C255.61%2068.5921%20255.656%2064.9718%20255.749%2060.8873C255.935%2056.8028%20256.074%2052.9503%20256.167%2049.33C256.353%2045.6168%20256.492%2042.8319%20256.585%2040.9753H256.028L230.407%20118.813H211.052Z%22%20class%3D%22fill-%5B%23FFFFFF%5D%22%3E%3C%2Fpath%3E%20%3Cpath%20d%3D%22M341.156%2041.393C342.177%2041.393%20343.384%2041.4395%20344.776%2041.5323C346.169%2041.6251%20347.283%2041.7644%20348.118%2041.95L346.587%2061.4442C345.937%2061.2586%20344.962%2061.1193%20343.662%2061.0265C342.456%2060.8408%20341.388%2060.748%20340.46%2060.748C337.768%2060.748%20335.169%2061.1193%20332.662%2061.862C330.156%2062.5118%20327.881%2063.5793%20325.839%2065.0646C323.89%2066.5499%20322.312%2068.5457%20321.105%2071.0521C319.991%2073.4657%20319.434%2076.4826%20319.434%2080.103V118.813H298.687V42.7855H314.421L317.485%2055.596H318.459C319.945%2052.9967%20321.801%2050.6296%20324.029%2048.4945C326.257%2046.3594%20328.81%2044.6421%20331.687%2043.3425C334.658%2042.0429%20337.814%2041.393%20341.156%2041.393Z%22%20class%3D%22fill-%5B%23FFFFFF%5D%22%3E%3C%2Fpath%3E%20%3Cpath%20d%3D%22M422.21%2091.2425C422.21%2097.0908%20420.772%20102.196%20417.894%20106.559C415.016%20110.922%20410.839%20114.311%20405.362%20116.724C399.978%20119.045%20393.387%20120.205%20385.589%20120.205C382.154%20120.205%20378.766%20119.973%20375.424%20119.509C372.175%20119.045%20369.019%20118.395%20365.956%20117.56C362.985%20116.631%20360.154%20115.517%20357.462%20114.218V94.5844C362.196%2096.6266%20367.07%2098.5297%20372.082%20100.293C377.188%20101.964%20382.247%20102.8%20387.26%20102.8C390.695%20102.8%20393.433%20102.336%20395.476%20101.407C397.611%20100.479%20399.142%2099.2259%20400.071%2097.6478C401.092%2096.0697%20401.602%2094.2595%20401.602%2092.2172C401.602%2089.7108%20400.72%2087.5758%20398.957%2085.812C397.286%2084.0482%20395.011%2082.4237%20392.134%2080.9384C389.256%2079.3603%20385.96%2077.6894%20382.247%2075.9256C379.927%2074.8117%20377.42%2073.5121%20374.728%2072.0268C372.036%2070.4487%20369.437%2068.5457%20366.93%2066.3178C364.517%2063.997%20362.521%2061.2122%20360.943%2057.9631C359.365%2054.7141%20358.576%2050.8153%20358.576%2046.2666C358.576%2040.3255%20359.922%2035.2663%20362.614%2031.089C365.399%2026.8188%20369.298%2023.5698%20374.31%2021.3419C379.416%2019.114%20385.403%2018%20392.273%2018C397.471%2018%20402.391%2018.6034%20407.033%2019.8102C411.767%2021.017%20416.687%2022.7343%20421.793%2024.9622L414.97%2041.393C410.421%2039.5365%20406.337%2038.0976%20402.716%2037.0765C399.096%2036.0553%20395.383%2035.5448%20391.577%2035.5448C388.977%2035.5448%20386.75%2035.9625%20384.893%2036.798C383.036%2037.6335%20381.597%2038.7938%20380.576%2040.2791C379.648%2041.7644%20379.184%2043.5281%20379.184%2045.5704C379.184%2047.8911%20379.88%2049.887%20381.273%2051.5579C382.665%2053.136%20384.754%2054.6677%20387.539%2056.153C390.323%2057.6382%20393.805%2059.402%20397.982%2061.4442C403.088%2063.8578%20407.404%2066.3642%20410.932%2068.9634C414.552%2071.5627%20417.337%2074.626%20419.286%2078.1536C421.236%2081.6811%20422.21%2086.0441%20422.21%2091.2425Z%22%20class%3D%22fill-%5B%23FFFFFF%5D%22%3E%3C%2Fpath%3E%20%3Cpath%20d%3D%22M469.523%20120.205C462.004%20120.205%20455.599%20118.859%20450.307%20116.167C445.016%20113.382%20440.978%20109.112%20438.193%20103.357C435.408%2097.6014%20434.016%2090.2214%20434.016%2081.2169C434.016%2071.934%20435.594%2064.3684%20438.75%2058.5201C441.906%2052.6718%20446.269%2048.3553%20451.839%2045.5704C457.502%2042.7855%20464%2041.393%20471.333%2041.393C476.532%2041.393%20481.034%2041.9036%20484.84%2042.9247C488.739%2043.9459%20492.127%2045.1526%20495.005%2046.5451L488.878%2062.5582C485.629%2061.2586%20482.566%2060.191%20479.688%2059.3556C476.903%2058.5201%20474.118%2058.1024%20471.333%2058.1024C467.713%2058.1024%20464.696%2058.9843%20462.282%2060.748C459.869%2062.4189%20458.059%2064.9718%20456.852%2068.4065C455.738%2071.7483%20455.181%2075.9721%20455.181%2081.0777C455.181%2086.0905%20455.784%2090.2678%20456.991%2093.6097C458.291%2096.8587%20460.147%2099.3187%20462.561%20100.99C464.974%20102.568%20467.899%20103.357%20471.333%20103.357C475.696%20103.357%20479.549%20102.8%20482.89%20101.686C486.232%20100.479%20489.481%2098.8546%20492.638%2096.8123V114.496C489.481%20116.539%20486.14%20117.977%20482.612%20118.813C479.177%20119.741%20474.814%20120.205%20469.523%20120.205Z%22%20class%3D%22fill-%5B%23FFFFFF%5D%22%3E%3C%2Fpath%3E%20%3Cpath%20d%3D%22M552.606%2041.393C553.627%2041.393%20554.834%2041.4395%20556.227%2041.5323C557.619%2041.6251%20558.733%2041.7644%20559.568%2041.95L558.037%2061.4442C557.387%2061.2586%20556.412%2061.1193%20555.113%2061.0265C553.906%2060.8408%20552.838%2060.748%20551.91%2060.748C549.218%2060.748%20546.619%2061.1193%20544.112%2061.862C541.606%2062.5118%20539.332%2063.5793%20537.289%2065.0646C535.34%2066.5499%20533.762%2068.5457%20532.555%2071.0521C531.441%2073.4657%20530.884%2076.4826%20530.884%2080.103V118.813H510.137V42.7855H525.871L528.935%2055.596H529.909C531.395%2052.9967%20533.251%2050.6296%20535.479%2048.4945C537.707%2046.3594%20540.26%2044.6421%20543.138%2043.3425C546.108%2042.0429%20549.264%2041.393%20552.606%2041.393Z%22%20class%3D%22fill-%5B%23FFFFFF%5D%22%3E%3C%2Fpath%3E%20%3Cpath%20d%3D%22M601.839%2041.2538C612.05%2041.2538%20619.848%2043.4817%20625.232%2047.9375C630.709%2052.3005%20633.447%2059.0307%20633.447%2068.128V118.813H618.966L614.928%20108.509H614.371C612.236%20111.201%20610.008%20113.429%20607.687%20115.193C605.459%20116.956%20602.86%20118.21%20599.889%20118.952C597.012%20119.788%20593.438%20120.205%20589.168%20120.205C584.712%20120.205%20580.674%20119.37%20577.053%20117.699C573.526%20115.935%20570.741%20113.29%20568.699%20109.762C566.656%20106.142%20565.635%20101.593%20565.635%2096.1161C565.635%2088.0399%20568.467%2082.0988%20574.129%2078.2928C579.792%2074.394%20588.286%2072.2589%20599.611%2071.8876L612.839%2071.4698V68.128C612.839%2064.1363%20611.772%2061.2122%20609.637%2059.3556C607.594%2057.499%20604.717%2056.5707%20601.003%2056.5707C597.29%2056.5707%20593.67%2057.1277%20590.142%2058.2416C586.615%2059.2627%20583.087%2060.5624%20579.56%2062.1405L572.737%2048.0768C576.821%2045.9417%20581.324%2044.2708%20586.244%2043.064C591.256%2041.8572%20596.455%2041.2538%20601.839%2041.2538ZM604.763%2083.8626C598.079%2084.0482%20593.438%2085.255%20590.839%2087.4829C588.239%2089.7108%20586.94%2092.635%20586.94%2096.2553C586.94%2099.4115%20587.868%20101.686%20589.725%20103.078C591.581%20104.378%20593.995%20105.028%20596.965%20105.028C601.421%20105.028%20605.181%20103.728%20608.244%20101.129C611.308%2098.4368%20612.839%2094.6772%20612.839%2089.8501V83.5841L604.763%2083.8626Z%22%20class%3D%22fill-%5B%23FFFFFF%5D%22%3E%3C%2Fpath%3E%20%3Cpath%20d%3D%22M697.015%2041.393C705.555%2041.393%20712.471%2044.7349%20717.762%2051.4186C723.053%2058.0095%20725.699%2067.7566%20725.699%2080.66C725.699%2089.2931%20724.446%2096.5802%20721.939%20102.521C719.433%20108.37%20715.998%20112.779%20711.635%20115.75C707.272%20118.72%20702.213%20120.205%20696.458%20120.205C692.837%20120.205%20689.681%20119.741%20686.989%20118.813C684.39%20117.885%20682.162%20116.678%20680.305%20115.193C678.449%20113.707%20676.824%20112.129%20675.432%20110.458H674.318C674.689%20112.222%20674.968%20114.079%20675.153%20116.028C675.339%20117.885%20675.432%20119.741%20675.432%20121.598V152.232H654.684V42.7855H671.533L674.457%2052.6718H675.432C676.824%2050.6296%20678.495%2048.773%20680.445%2047.1021C682.394%2045.3383%20684.715%2043.9459%20687.407%2042.9247C690.192%2041.9036%20693.394%2041.393%20697.015%2041.393ZM690.331%2057.9631C686.71%2057.9631%20683.833%2058.7058%20681.698%2060.191C679.563%2061.6763%20677.985%2063.9506%20676.963%2067.014C676.035%2069.9846%20675.525%2073.7442%20675.432%2078.2928V80.5207C675.432%2085.4407%20675.896%2089.618%20676.824%2093.0527C677.752%2096.3946%20679.331%2098.9474%20681.558%20100.711C683.786%20102.475%20686.803%20103.357%20690.609%20103.357C693.766%20103.357%20696.365%20102.475%20698.407%20100.711C700.449%2098.9474%20701.981%2096.3482%20703.002%2092.9135C704.023%2089.4788%20704.534%2085.3014%20704.534%2080.3815C704.534%2072.9551%20703.373%2067.3853%20701.053%2063.6721C698.825%2059.8661%20695.251%2057.9631%20690.331%2057.9631Z%22%20class%3D%22fill-%5B%23FFFFFF%5D%22%3E%3C%2Fpath%3E%20%3Cpath%20d%3D%22M774.13%2041.393C781.185%2041.393%20787.219%2042.7391%20792.232%2045.4311C797.337%2048.1232%20801.283%2052.022%20804.067%2057.1277C806.852%2062.2333%20808.245%2068.4993%20808.245%2075.9256V85.9512H759.231C759.416%2091.7995%20761.134%2096.3946%20764.383%2099.7364C767.725%20103.078%20772.32%20104.749%20778.168%20104.749C783.088%20104.749%20787.544%20104.285%20791.535%20103.357C795.527%20102.336%20799.658%20100.804%20803.928%2098.7617V114.775C800.215%20116.631%20796.27%20117.977%20792.092%20118.813C788.008%20119.741%20783.041%20120.205%20777.193%20120.205C769.581%20120.205%20762.851%20118.813%20757.003%20116.028C751.155%20113.15%20746.559%20108.834%20743.218%20103.078C739.876%2097.3229%20738.205%2090.0822%20738.205%2081.3562C738.205%2072.4445%20739.69%2065.0646%20742.661%2059.2163C745.724%2053.2752%20749.948%2048.8194%20755.332%2045.8489C760.716%2042.8783%20766.982%2041.393%20774.13%2041.393ZM774.269%2056.153C770.277%2056.153%20766.936%2057.4526%20764.243%2060.0518C761.644%2062.651%20760.113%2066.6891%20759.648%2072.1661H788.751C788.751%2069.1027%20788.194%2066.3642%20787.08%2063.9506C786.058%2061.5371%20784.48%2059.6341%20782.345%2058.2416C780.21%2056.8492%20777.518%2056.153%20774.269%2056.153Z%22%20class%3D%22fill-%5B%23FFFFFF%5D%22%3E%3C%2Fpath%3E%20%3Cpath%20d%3D%22M867.538%2041.393C868.559%2041.393%20869.766%2041.4395%20871.158%2041.5323C872.551%2041.6251%20873.665%2041.7644%20874.5%2041.95L872.968%2061.4442C872.318%2061.2586%20871.344%2061.1193%20870.044%2061.0265C868.837%2060.8408%20867.77%2060.748%20866.842%2060.748C864.15%2060.748%20861.55%2061.1193%20859.044%2061.862C856.537%2062.5118%20854.263%2063.5793%20852.221%2065.0646C850.271%2066.5499%20848.693%2068.5457%20847.487%2071.0521C846.373%2073.4657%20845.816%2076.4826%20845.816%2080.103V118.813H825.068V42.7855H840.803L843.866%2055.596H844.841C846.326%2052.9967%20848.183%2050.6296%20850.411%2048.4945C852.639%2046.3594%20855.191%2044.6421%20858.069%2043.3425C861.04%2042.0429%20864.196%2041.393%20867.538%2041.393Z%22%20class%3D%22fill-%5B%23FFFFFF%5D%22%3E%3C%2Fpath%3E%20%3C%2Fsvg%3E",
"width": 137
},
{
"source": "og:image",
"url": "https://mrscraper.com/og.png"
}
],
"manifest": {
"background_color": "#0d1625",
"display": "standalone",
"name": "MrScraper",
"short_name": "MrScraper",
"theme_color": "#0d1625",
"url": "https://mrscraper.com/site.webmanifest"
},
"meta": {
"og": {
"og:description": "Turn any website into structured JSON with plain-English prompts or a visual recorder. Schedule jobs, send data to your database. Start free, 1,000 tokens.",
"og:image": "https://mrscraper.com/og.png",
"og:image:alt": "MrScraper: Web Scraping API for Structured Data",
"og:image:height": "837",
"og:image:secure_url": "https://mrscraper.com/og.png",
"og:image:width": "1489",
"og:locale": "en",
"og:site_name": "MrScraper",
"og:title": "MrScraper: Web Scraping API for Structured Data",
"og:type": "website",
"og:url": "https://mrscraper.com"
},
"twitter": {
"twitter:card": "summary_large_image",
"twitter:creator": "@MrScraper_",
"twitter:description": "Turn any website into structured JSON with plain-English prompts or a visual recorder. Schedule jobs, send data to your database. Start free, 1,000 tokens.",
"twitter:domain": "https://mrscraper.com",
"twitter:image": "https://mrscraper.com/og.png",
"twitter:image:alt": "MrScraper: Web Scraping API for Structured Data",
"twitter:image:height": "837",
"twitter:image:width": "1489",
"twitter:site": "@MrScraper_",
"twitter:title": "MrScraper: Web Scraping API for Structured Data"
}
},
"name": "MrScraper",
"organization": {
"address": null,
"alternate_names": [
"MrScraper"
],
"contact_point": null,
"legal_name": null,
"logo": "https://mrscraper.com/images/logo-blue.png",
"name": "MrScraper",
"same_as": [],
"url": "https://mrscraper.com"
},
"social": {
"x": "https://twitter.com/MrScraper_"
},
"title": "MrScraper: Web Scraping API for Structured Data",
"typography": {
"body": {
"background": "#050606",
"border_radius": "0px",
"color": "#000000",
"font_family": "Poppins, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\", sans-serif",
"font_size": "16px",
"font_weight": "400",
"letter_spacing": "normal",
"line_height": "24px",
"selector": "body",
"text_transform": "none"
},
"button": {
"font_family": "Poppins, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\", sans-serif",
"font_weight": "600",
"text_transform": "none"
},
"fonts": [
{
"family": "Poppins",
"loaded": true,
"sources": [
"https://mrscraper.com/_astro/poppins-devanagari-400-normal.CJDn6rn8.woff2",
"https://mrscraper.com/_astro/poppins-devanagari-400-normal.CqVvlrh5.woff",
"https://mrscraper.com/_astro/poppins-latin-ext-400-normal.by3JarPu.woff2",
"https://mrscraper.com/_astro/poppins-latin-ext-400-normal.DaBSavcJ.woff",
"https://mrscraper.com/_astro/poppins-latin-400-normal.cpxAROuN.woff2",
"https://mrscraper.com/_astro/poppins-latin-400-normal.BOb3E3N0.woff",
"https://mrscraper.com/_astro/poppins-devanagari-500-normal.BIdkeU1p.woff2",
"https://mrscraper.com/_astro/poppins-devanagari-500-normal.DMPDjHtT.woff"
],
"styles": [
"normal"
],
"weights": [
"400",
"500",
"600",
"700"
]
}
],
"headings": [
{
"background": null,
"border_radius": "0px",
"color": "#ffffff",
"font_family": "Poppins, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\", sans-serif",
"font_size": "48px",
"font_weight": "300",
"letter_spacing": "normal",
"line_height": "60px",
"selector": "h1",
"text_transform": "none"
},
{
"background": null,
"border_radius": "0px",
"color": "#000000",
"font_family": "Poppins, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\", sans-serif",
"font_size": "16px",
"font_weight": "400",
"letter_spacing": "normal",
"line_height": "24px",
"selector": "h2",
"text_transform": "none"
},
{
"background": null,
"border_radius": "0px",
"color": "#ffffff",
"font_family": "Poppins, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\", sans-serif",
"font_size": "20px",
"font_weight": "600",
"letter_spacing": "normal",
"line_height": "28px",
"selector": "h3",
"text_transform": "none"
}
],
"providers": []
},
"url": "https://mrscraper.com/"
},
"error": null,
"html_url": "/brand?id=&output=html",
"bundle_url": null,
"screenshot_url": null,
"full_screenshot_url": null
},
"message": "brand job settled"
}
```
## Read the Brand Again
Use the job ID to fetch a brand you already scraped:
```sh title="Request"
curl 'https://api.mrscraper.com/neo/brand?id=' \
-H 'x-api-token: {MRSCRAPER_API_TOKEN}'
```
The response has the same shape as the scrape response, with `"message": "brand found"`.
## Download Files
Add the `output` parameter to download a file from the job:
| Output | File |
| ----------------- | ------------------------------------- |
| `html` | The page HTML. |
| `bundle` | The ZIP bundle of the page. |
| `screenshot` | A screenshot of the visible viewport. |
| `screenshot_full` | A screenshot of the full page. |
In the Scraper API, the same four files are available to download as **ZIP Bundle**, **HTML**, **Screenshot**, and **Full Page Screenshot**.
A job scraped with **None** only has the HTML to download. Jobs scraped with **Clean** or **Full** have all four files.
```sh title="Download the screenshot"
curl 'https://api.mrscraper.com/neo/brand?id=&output=screenshot' \
-H 'x-api-token: {MRSCRAPER_API_TOKEN}' \
-o screenshot.jpg
```
```sh title="Download the ZIP bundle"
curl 'https://api.mrscraper.com/neo/brand?id=&output=bundle' \
-H 'x-api-token: {MRSCRAPER_API_TOKEN}' \
-o brand.zip
```
Screenshot of `https://mrscraper.com/` :
### ZIP Bundle Contents
The ZIP is a self-contained copy of the page that you can open offline:
```txt title="brand-mrscraper.com.zip"
brand-mrscraper.com/
├── index.html # The page, rewritten to load local assets
├── brand.json # The brand JSON
├── manifest.json # Each saved asset with its original URL, MIME type, and size
├── screenshot.jpg # Viewport screenshot
├── screenshot-full.jpg # Full-page screenshot
└── assets/ # Stylesheets, fonts, images, and videos (plus scripts with Full)
```
With `bundle=clean`, the page's script files are left out. With `bundle=full`, they are saved as `.js` files in `assets/`.
## Code Examples
The examples below scrape the brand of `https://mrscraper.com/`, print it, and download the page HTML with the job ID.
Python
JavaScript
```python
import requests
response = requests.post(
"https://api.mrscraper.com/?action=brand-scraping&bundle=none&url=https%3A%2F%2Fmrscraper.com%2F",
headers={"x-api-token": "{MRSCRAPER_API_TOKEN}"},
json={"url": "https://mrscraper.com/"},
timeout=300,
)
result = response.json()["data"]
print(result["brand"])
html = requests.get(
"https://api.mrscraper.com/neo/brand",
params={"id": result["job_id"], "output": "html"},
headers={"x-api-token": "{MRSCRAPER_API_TOKEN}"},
)
```
```js
const response = await fetch("https://api.mrscraper.com/?action=brand-scraping&bundle=none&url=https%3A%2F%2Fmrscraper.com%2F", {
method: "POST",
headers: { "x-api-token": "{MRSCRAPER_API_TOKEN}", "content-type": "application/json" },
body: JSON.stringify({ url: "https://mrscraper.com/" }),
})
const { data } = JSON.parse((await response.text()).trim())
console.log(data.brand)
const html = await fetch(
`https://api.mrscraper.com/neo/brand?id=${data.job_id}&output=html`,
{ headers: { "x-api-token": "{MRSCRAPER_API_TOKEN}" } },
)
```
Set a generous timeout. **None** usually answers in a few seconds, but **Clean** and **Full** can take about a minute.
# Scrape HTML
## Overview
Selecting **Scrape HTML** in the Scraper API Use Case panel optimizes the Scraper API 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.
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 Scraper API.
### Practical Applications
* **Custom Parser Integration**: Feed clean 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.
* **Proxy & Browser Offloading**: Fetch pages without managing residential proxies or headless browsers 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 Scraper API 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 Scraper API 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/scraper-api/listing-page) Use Case preset in the Scraper API.
## 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 Scraper API Use Case panel optimizes the Scraper API environment for clean text conversion. When this preset is selected, the Scraper API 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 Scraper API 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 Scraper API 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"
}
```
# 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 real-time web 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/workflow) (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 the web | 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/`.
Search the web to retrieve real-time search results, including relevant website URLs, titles, and descriptions. Results are returned as JSON or HTML through the synchronous MrScraper web search API.
**Best for:** Keyword monitoring, competitor tracking, seeding a workflow with search results.
**Parameters:**
| Parameter | Required | Default | Description |
| ----------------- | -------- | ------- | ---------------------------------------------------------- |
| Search Query | Yes | — | 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` | 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 browser, with JavaScript execution 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 |
| ----------------- | -------------------- | ------------------------------------------------------------------------------------ |
| 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 |
| 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` |
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 web search 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 web search 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.
# 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 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 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.
# Agentic Market
Use MrScraper's HTTP APIs from an AI agent or application and pay per request in USDC on Base through x402. Payments are settled by the Coinbase CDP facilitator, and the endpoints are cataloged in the x402 Bazaar so agents on Agentic.market can discover them. Buyers do not need a MrScraper API key or session cookie.
The integration exposes two services:
* **scraperAPI** retrieves a public page as rendered HTML, Markdown, a screenshot, or a combination of these outputs.
* **webSearch**: Search the web to retrieve real-time search results, including relevant website URLs, titles, and descriptions.
## Endpoints and pricing
Base URL: `https://api.mrscraper.com/agentic-market`
| Service | Method and path | Price per request |
| ---------- | -------------------------------- | ----------------- |
| scraperAPI | `POST /api/mrscraper/scraperAPI` | **0.001 USDC** |
| webSearch | `POST /api/mrscraper/webSearch` | **0.001 USDC** |
Both endpoints accept and return `application/json`.
The live `PAYMENT-REQUIRED` challenge supplies the payable amount, accepted network, asset, and recipient. Check these requirements before authorizing a payment.
## OpenAPI specification
[Open the OpenAPI 3.1 JSON specification](/x402/agentic-market/openapi.json)
The document covers **only these two paid endpoints**, including required and optional request fields, response schemas, output examples, error responses, and the x402 payment headers. Each operation includes these custom OpenAPI extensions:
| Extension | Value | Meaning |
| -------------------- | --------- | ----------------------- |
| `x-price-usdc` | `"0.001"` | USDC price per request. |
| `x-payment-protocol` | `"x402"` | Payment protocol. |
| `x-x402-version` | `2` | x402 protocol version. |
The specification's `servers` URL is `https://api.mrscraper.com`, and each operation path already starts with `/agentic-market`, for example `/agentic-market/api/mrscraper/scraperAPI`.
## Payment setup and flow
Use any x402 v2 buyer client that can pay the **exact** USDC scheme on **Base**, and a wallet with enough USDC on Base to cover each request. The Coinbase CDP facilitator verifies and settles the payment; buyers do not need a Coinbase or MrScraper account to call the endpoints.
For each API call:
1. Send a JSON `POST` request to either endpoint.
2. A valid unpaid request returns HTTP `402` with a `PAYMENT-REQUIRED` header.
3. Your buyer client reads the challenge, selects a supported payment option, and signs the payment authorization.
4. The client repeats the same method, URL, and JSON body with `PAYMENT-SIGNATURE` attached.
5. The Coinbase CDP facilitator verifies the payment, MrScraper runs the service, and the payment is settled when the gateway returns a successful response.
| Header | Direction | Purpose |
| ------------------- | --------- | ------------------------------------------------------------------------ |
| `PAYMENT-REQUIRED` | Response | Base64-encoded x402 v2 requirements on the initial unpaid challenge. |
| `PAYMENT-SIGNATURE` | Request | Base64-encoded payment payload generated by the buyer client. |
| `PAYMENT-RESPONSE` | Response | Base64-encoded settlement result, present after a successful settlement. |
The requests below show the JSON inputs and return HTTP `402` when sent without payment. Use your x402 buyer client to sign and complete the paid request.
Invalid service inputs are rejected with HTTP `400` before payment is requested. Unknown request fields are ignored. Use the field names documented here, including camelCase options such as `proxyCountry` and `numResults`.
## scraperAPI
Retrieve public webpage content, including pages rendered with JavaScript. Use the returned content for research, public product and price monitoring, article collection, or retrieval workflows. Availability depends on the target website.
```bash
curl -i 'https://api.mrscraper.com/agentic-market/api/mrscraper/scraperAPI' \
-H 'Content-Type: application/json' \
--data '{
"url": "https://example.com",
"html": true,
"markdown": true,
"screenshot": false
}'
```
### Request fields
| Field | Type | Required | Default / accepted values |
| ------------------ | ------- | -------- | ---------------------------------------------------------------------------------------------------- |
| `url` | string | Yes | Public HTTP(S) URL without embedded credentials. Private/local hosts and IPv6 literals are rejected. |
| `html` | boolean | No | `true`. The renderer currently returns `html` even when set to `false`. |
| `markdown` | boolean | No | Include Markdown in the `markdown` field. |
| `screenshot` | boolean | No | Include a base64 JPEG in the `screenshot` field. Can substantially increase response size. |
| `proxyCountry` | string | No | `"us"`. Two-letter proxy country code. Also used as `geoCode` when `geoCode` is omitted. |
| `geoCode` | string | No | Two-letter upstream geo code. Defaults to `proxyCountry`. |
| `browserRendering` | boolean | No | `true`. Set to `false` to fetch the page without JavaScript rendering. |
| `timeout` | integer | No | `1`–`300` seconds for upstream page retrieval. |
| `maxRetries` | integer | No | `1`–`10` upstream retries. `0` is not accepted. |
| `tokenCap` | integer | No | `1`–`10000` upstream plan tokens for retries. Separate from the USDC price. |
| `waitUntil` | string | No | `"domcontentloaded"`, `"load"`, or `"networkidle"`. |
| `waitForSelector` | string | No | CSS selector, up to 1,000 characters. |
| `blockResources` | boolean | No | Forward the renderer's resource-blocking option. |
| `warmStart` | boolean | No | Visit the site's root before retrieving the target page. |
| `returnCookie` | boolean | No | Request upstream cookie information when supported. |
| `super` | boolean | No | Forward the real-device routing option. |
Fields without a documented default are forwarded only when supplied; otherwise, the upstream service chooses its default.
### Response
The response body is the renderer result itself, without an `ok`/`service`/`data` wrapper. Illustrative successful response:
```json
{
"html": "Example Domain
",
"markdown": "# Example Domain",
"screenshot": null,
"runtime": 4.2,
"retry_count": 0,
"error": null
}
```
| Field | Type | Meaning |
| ------------- | -------------- | ----------------------------------------------------------------------------- |
| `html` | string | Rendered HTML; can be empty when disabled. |
| `markdown` | string | Markdown; can be empty when disabled. |
| `screenshot` | string or null | Base64 JPEG image bytes, without a `data:` prefix; can be null when disabled. |
| `runtime` | number | Upstream renderer runtime in seconds. |
| `retry_count` | integer | Retries reported by the renderer. |
| `error` | string or null | Upstream page-rendering error, if any. |
Disabled outputs can remain present with empty or null values. Allow enough time in your client for rendering and response transfer. The request's `timeout` field is separate from your client's HTTP deadline.
## webSearch
Search the web to retrieve real-time search results, including relevant website URLs, titles, and descriptions. Use `region` to compare results across countries.
```bash
curl -i 'https://api.mrscraper.com/agentic-market/api/mrscraper/webSearch' \
-H 'Content-Type: application/json' \
--data '{
"query": "web scraping",
"region": "us",
"numResults": 10
}'
```
### Request fields
| Field | Type | Required | Default / accepted values |
| ------------ | ------- | -------- | -------------------------------------------------------------- |
| `query` | string | Yes | Search text, 1–1,000 characters after trimming whitespace. |
| `region` | string | No | `"us"`. Two-letter country code for the results. |
| `numResults` | integer | No | `10`. Accepts `10`–`100`. The search can return fewer results. |
### Response
The response has `success`, `message`, and `data` at the top level, without an `ok`/`service` wrapper. `data` is the list of ranked results. Illustrative response, with the list shortened:
```json
{
"success": true,
"message": "Search completed",
"data": [
{
"rank": 1,
"title": "Web scraping",
"url": "https://en.wikipedia.org/wiki/Web_scraping",
"description": "Web scraping, web harvesting, or web data extraction is data scraping used for extracting data from websites.",
"source": "Wikipedia"
},
{
"rank": 2,
"title": "What is Web Scraping? The Complete Guide",
"url": "https://www.scraperapi.com/web-scraping/",
"description": "Web scraping, or web data extraction, is the process of extracting publicly available web data using automated tools.",
"source": "ScraperAPI"
}
]
}
```
| Field | Type | Meaning |
| -------------------- | ------- | ------------------------------------------------------------- |
| `success` | boolean | Whether the upstream search service succeeded. |
| `message` | string | Upstream status message. |
| `data` | array | Ranked results, at most `numResults`. Can be empty. |
| `data[].rank` | integer | One-based position in the results. |
| `data[].title` | string | Result title. |
| `data[].url` | string | Destination page URL. |
| `data[].description` | string | Result snippet, when available. |
| `data[].source` | string | Site or publisher name shown with the result, when available. |
Upstream `tokenUsage` is omitted. When `success` is `false`, the shape of `data` varies by failure and can be `null`.
## Errors
| HTTP status | Meaning |
| ----------- | --------------------------------------------------------------------------------------------------------------- |
| `200` | Upstream request completed. Inspect `error` for scraperAPI or `success` for webSearch. |
| `400` | Invalid service inputs, rejected before payment. |
| `402` | Payment required or rejected. Read the payment headers and any error details. |
| `500` | Unexpected gateway or payment-processing error. The payment is not settled. |
| `502` | Upstream connection, HTTP status, or response-size error, or a facilitator failure. The payment is not settled. |
| `504` | Upstream HTTP request timed out. The payment is not settled. |
Gateway validation and upstream errors use an `ok: false` envelope:
```json
{
"ok": false,
"error": {
"code": "INVALID_REQUEST",
"message": "Request validation failed",
"issues": [
{
"path": ["url"],
"message": "URL must target a public host"
}
]
}
}
```
This is an illustrative validation error; issue messages vary. Other error codes include `UPSTREAM_TIMEOUT`, `UPSTREAM_HTTP_ERROR`, `UPSTREAM_TOO_LARGE`, `UPSTREAM_UNAVAILABLE`, and `INTERNAL_ERROR`. Payment middleware errors use a different shape: a string `error` with optional `reason` or `message`; a facilitator failure on `502` can also use this shape. The initial unpaid `402` body is `{}`; its requirements are in `PAYMENT-REQUIRED`.
The payment is verified before the upstream service runs and settled only when the gateway returns a successful response. Requests that end in an HTTP error status (`400`, `402`, `500`, `502`, or `504`) are not settled. A `200` response whose upstream fields report an error, such as webSearch `success: false`, is still settled, so a retry is a new paid request.
# Circle Gateway
Use MrScraper's HTTP APIs from an AI agent or application and pay per request in USDC through [Circle Gateway](https://developers.circle.com/gateway-nanopayments). Buyers do not need a MrScraper API key or session cookie.
The integration exposes two services:
* **scraperAPI** retrieves a public page as rendered HTML, Markdown, a screenshot, or a combination of these outputs.
* **webSearch**: Search the web to retrieve real-time search results, including relevant website URLs, titles, and descriptions.
## Endpoints and pricing
Base URL: `https://api.mrscraper.com/circle`
| Service | Method and path | Price per request |
| ---------- | -------------------------------- | ----------------- |
| scraperAPI | `POST /api/mrscraper/scraperAPI` | **0.01 USDC** |
| webSearch | `POST /api/mrscraper/webSearch` | **0.01 USDC** |
Both endpoints accept and return `application/json`.
The live `PAYMENT-REQUIRED` challenge supplies the payable amount, accepted network, asset, and recipient. Check these requirements before authorizing a payment.
## OpenAPI specification
[Open the OpenAPI 3.1 JSON specification](/x402/circle/openapi.json)
The document covers **only these two paid endpoints**, including required and optional request fields, response schemas, output examples, error responses, and the x402 payment headers. Each operation includes these custom OpenAPI extensions:
| Extension | Value | Meaning |
| -------------------- | -------- | ----------------------- |
| `x-price-usdc` | `"0.01"` | USDC price per request. |
| `x-payment-protocol` | `"x402"` | Payment protocol. |
| `x-x402-version` | `2` | x402 protocol version. |
The specification's `servers` URL is `https://api.mrscraper.com`, and each operation path already starts with `/circle`, for example `/circle/api/mrscraper/scraperAPI`.
## Payment setup and flow
Use a buyer client that supports **Circle Gateway batched x402 payments** and an EOA wallet with an available USDC balance in Gateway. Follow Circle's [buyer quickstart](https://developers.circle.com/gateway-nanopayments/quickstarts/buyer) to set up the wallet and initial deposit. Existing x402 clients can follow [Circle's buyer integration guide](https://developers.circle.com/gateway-nanopayments/howtos/x402-buyer).
For each API call:
1. Send a JSON `POST` request to either endpoint.
2. A valid unpaid request returns HTTP `402` with a `PAYMENT-REQUIRED` header.
3. Your buyer client reads the challenge, selects a supported payment option, and signs the payment authorization.
4. The client repeats the same method, URL, and JSON body with `PAYMENT-SIGNATURE` attached.
5. Gateway settles the payment, then MrScraper runs the service and returns its result.
| Header | Direction | Purpose |
| ------------------- | --------- | -------------------------------------------------------------------------------------------------------------- |
| `PAYMENT-REQUIRED` | Response | Base64-encoded x402 v2 requirements on the initial unpaid challenge. |
| `PAYMENT-SIGNATURE` | Request | Base64-encoded payment payload generated by the buyer client. |
| `PAYMENT-RESPONSE` | Response | Base64-encoded settlement result. Can also appear on a later upstream error, because settlement happens first. |
The requests below show the JSON inputs and return HTTP `402` when sent without payment. Use your Circle Gateway-compatible buyer client to sign and complete the paid request.
Invalid service inputs are rejected with HTTP `400` before payment is requested. Unknown request fields are ignored. Use the field names documented here, including camelCase options such as `proxyCountry` and `numResults`.
## scraperAPI
Retrieve public webpage content, including pages rendered with JavaScript. Use the returned content for research, public product and price monitoring, article collection, or retrieval workflows. Availability depends on the target website.
```bash
curl -i 'https://api.mrscraper.com/circle/api/mrscraper/scraperAPI' \
-H 'Content-Type: application/json' \
--data '{
"url": "https://example.com",
"html": true,
"markdown": true,
"screenshot": false
}'
```
### Request fields
| Field | Type | Required | Default / accepted values |
| ------------------ | ------- | -------- | ---------------------------------------------------------------------------------------------------- |
| `url` | string | Yes | Public HTTP(S) URL without embedded credentials. Private/local hosts and IPv6 literals are rejected. |
| `html` | boolean | No | `true`. The renderer currently returns `html` even when set to `false`. |
| `markdown` | boolean | No | Include Markdown in the `markdown` field. |
| `screenshot` | boolean | No | Include a base64 JPEG in the `screenshot` field. Can substantially increase response size. |
| `proxyCountry` | string | No | `"us"`. Two-letter proxy country code. Also used as `geoCode` when `geoCode` is omitted. |
| `geoCode` | string | No | Two-letter upstream geo code. Defaults to `proxyCountry`. |
| `browserRendering` | boolean | No | `true`. Set to `false` to fetch the page without JavaScript rendering. |
| `timeout` | integer | No | `1`–`300` seconds for upstream page retrieval. |
| `maxRetries` | integer | No | `1`–`10` upstream retries. `0` is not accepted. |
| `tokenCap` | integer | No | `1`–`10000` upstream plan tokens for retries. Separate from the USDC price. |
| `waitUntil` | string | No | `"domcontentloaded"`, `"load"`, or `"networkidle"`. |
| `waitForSelector` | string | No | CSS selector, up to 1,000 characters. |
| `blockResources` | boolean | No | Forward the renderer's resource-blocking option. |
| `warmStart` | boolean | No | Visit the site's root before retrieving the target page. |
| `returnCookie` | boolean | No | Request upstream cookie information when supported. |
| `super` | boolean | No | Forward the real-device routing option. |
Fields without a documented default are forwarded only when supplied; otherwise, the upstream service chooses its default.
### Response
The response body is the renderer result itself, without an `ok`/`service`/`data` wrapper. Illustrative successful response:
```json
{
"html": "Example Domain
",
"markdown": "# Example Domain",
"screenshot": null,
"runtime": 4.2,
"retry_count": 0,
"error": null
}
```
| Field | Type | Meaning |
| ------------- | -------------- | ----------------------------------------------------------------------------- |
| `html` | string | Rendered HTML; can be empty when disabled. |
| `markdown` | string | Markdown; can be empty when disabled. |
| `screenshot` | string or null | Base64 JPEG image bytes, without a `data:` prefix; can be null when disabled. |
| `runtime` | number | Upstream renderer runtime in seconds. |
| `retry_count` | integer | Retries reported by the renderer. |
| `error` | string or null | Upstream page-rendering error, if any. |
Disabled outputs can remain present with empty or null values. Allow enough time in your client for rendering and response transfer. The request's `timeout` field is separate from your client's HTTP deadline.
## webSearch
Search the web to retrieve real-time search results, including relevant website URLs, titles, and descriptions. Use `region` to compare results across countries.
```bash
curl -i 'https://api.mrscraper.com/circle/api/mrscraper/webSearch' \
-H 'Content-Type: application/json' \
--data '{
"query": "web scraping",
"region": "us",
"numResults": 10
}'
```
### Request fields
| Field | Type | Required | Default / accepted values |
| ------------ | ------- | -------- | -------------------------------------------------------------- |
| `query` | string | Yes | Search text, 1–1,000 characters after trimming whitespace. |
| `region` | string | No | `"us"`. Two-letter country code for the results. |
| `numResults` | integer | No | `10`. Accepts `10`–`100`. The search can return fewer results. |
### Response
The response has `success`, `message`, and `data` at the top level, without an `ok`/`service` wrapper. `data` is the list of ranked results. Illustrative response, with the list shortened:
```json
{
"success": true,
"message": "Search completed",
"data": [
{
"rank": 1,
"title": "Web scraping",
"url": "https://en.wikipedia.org/wiki/Web_scraping",
"description": "Web scraping, web harvesting, or web data extraction is data scraping used for extracting data from websites.",
"source": "Wikipedia"
},
{
"rank": 2,
"title": "What is Web Scraping? The Complete Guide",
"url": "https://www.scraperapi.com/web-scraping/",
"description": "Web scraping, or web data extraction, is the process of extracting publicly available web data using automated tools.",
"source": "ScraperAPI"
}
]
}
```
| Field | Type | Meaning |
| -------------------- | ------- | ------------------------------------------------------------- |
| `success` | boolean | Whether the upstream search service succeeded. |
| `message` | string | Upstream status message. |
| `data` | array | Ranked results, at most `numResults`. Can be empty. |
| `data[].rank` | integer | One-based position in the results. |
| `data[].title` | string | Result title. |
| `data[].url` | string | Destination page URL. |
| `data[].description` | string | Result snippet, when available. |
| `data[].source` | string | Site or publisher name shown with the result, when available. |
Upstream `tokenUsage` is omitted. When `success` is `false`, the shape of `data` varies by failure and can be `null`.
## Errors
| HTTP status | Meaning |
| ----------- | -------------------------------------------------------------------------------------- |
| `200` | Upstream request completed. Inspect `error` for scraperAPI or `success` for webSearch. |
| `400` | Invalid service inputs, or malformed/unsupported payment requirements. |
| `402` | Payment required or rejected. Read the payment headers and any error details. |
| `500` | Unexpected gateway or payment-processing error. |
| `502` | Upstream connection, HTTP status, or response-size error. |
| `503` | No payment networks available from the payment middleware. |
| `504` | Upstream HTTP request timed out. |
Gateway validation and upstream errors use an `ok: false` envelope:
```json
{
"ok": false,
"error": {
"code": "INVALID_REQUEST",
"message": "Request validation failed",
"issues": [
{
"path": ["url"],
"message": "URL must target a public host"
}
]
}
}
```
This is an illustrative validation error; issue messages vary. Other error codes include `UPSTREAM_TIMEOUT`, `UPSTREAM_HTTP_ERROR`, `UPSTREAM_TOO_LARGE`, `UPSTREAM_UNAVAILABLE`, and `INTERNAL_ERROR`. Payment middleware errors use a different shape: a string `error` with optional `reason` or `message`. The initial unpaid `402` body is `{}`; its requirements are in `PAYMENT-REQUIRED`.
Circle Gateway settles the payment before the upstream service runs. An upstream failure does not trigger an automatic retry or refund, and `PAYMENT-RESPONSE` can appear on a `500`, `502`, or `504` response after payment was settled. A new paid request can incur another charge; account for that before retrying.
# x402
MrScraper offers two pay-per-request HTTP APIs for AI agents, paid in USDC over [x402](https://www.x402.org/) v2. Buyers do not need a MrScraper API key or session cookie.
* **scraperAPI** retrieves a public page as rendered HTML, Markdown, a screenshot, or a combination of these outputs.
* **webSearch**: Search the web to retrieve real-time search results, including relevant website URLs, titles, and descriptions.
## Payment providers
The same services are available through three payment providers. Request and response bodies are identical; the route prefix, price, and how payments are settled differ.
| Provider | Base URL | Price per request | Settlement | OpenAPI |
| -------------------------------------------------------- | ------------------------------------------ | ----------------- | ---------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
| [Circle Gateway](/docs/integrations/x402/circle) | `https://api.mrscraper.com/circle` | **0.01 USDC** | Circle Gateway batched payments. Settled before the service runs. | [`openapi.json`](/x402/circle/openapi.json) |
| [Agentic Market](/docs/integrations/x402/agentic-market) | `https://api.mrscraper.com/agentic-market` | **0.001 USDC** | USDC on Base through the Coinbase CDP facilitator. Settled only on a successful response. | [`openapi.json`](/x402/agentic-market/openapi.json) |
| [Inflowpay](/docs/integrations/x402/inflowpay) | `https://api.mrscraper.com/inflowpay` | **0.001 USDC** | InFlow facilitator, including payment from an InFlow balance. Settled only on a successful response. | [`openapi.json`](/x402/inflowpay/openapi.json) |
Each provider exposes the same two paths under its base URL:
| Service | Method and path |
| ---------- | -------------------------------- |
| scraperAPI | `POST /api/mrscraper/scraperAPI` |
| webSearch | `POST /api/mrscraper/webSearch` |
# Inflowpay
Use MrScraper's HTTP APIs from an AI agent or application and pay per request in USDC through x402. Payments are settled by the InFlow facilitator, and InFlow buyers can pay from their InFlow balance. Buyers do not need a MrScraper API key or session cookie.
The integration exposes two services:
* **scraperAPI** retrieves a public page as rendered HTML, Markdown, a screenshot, or a combination of these outputs.
* **webSearch**: Search the web to retrieve real-time search results, including relevant website URLs, titles, and descriptions.
## Endpoints and pricing
Base URL: `https://api.mrscraper.com/inflowpay`
| Service | Method and path | Price per request |
| ---------- | -------------------------------- | ----------------- |
| scraperAPI | `POST /api/mrscraper/scraperAPI` | **0.001 USDC** |
| webSearch | `POST /api/mrscraper/webSearch` | **0.001 USDC** |
Both endpoints accept and return `application/json`.
The live `PAYMENT-REQUIRED` challenge supplies the payable amount, accepted network, asset, and recipient. Check these requirements before authorizing a payment.
## OpenAPI specification
[Open the OpenAPI 3.1 JSON specification](/x402/inflowpay/openapi.json)
The document covers **only these two paid endpoints**, including required and optional request fields, response schemas, output examples, error responses, and the x402 payment headers. Each operation includes these custom OpenAPI extensions:
| Extension | Value | Meaning |
| -------------------- | --------- | ----------------------- |
| `x-price-usdc` | `"0.001"` | USDC price per request. |
| `x-payment-protocol` | `"x402"` | Payment protocol. |
| `x-x402-version` | `2` | x402 protocol version. |
The specification's `servers` URL is `https://api.mrscraper.com`, and each operation path already starts with `/inflowpay`, for example `/inflowpay/api/mrscraper/scraperAPI`.
## Payment setup and flow
Use an x402 v2 buyer client and either an InFlow balance or a wallet holding USDC on one of the accepted on-chain networks. The live `PAYMENT-REQUIRED` challenge lists the networks InFlow currently accepts, so read it instead of hard-coding a network.
For each API call:
1. Send a JSON `POST` request to either endpoint.
2. A valid unpaid request returns HTTP `402` with a `PAYMENT-REQUIRED` header.
3. Your buyer client reads the challenge, selects a supported payment option, and signs the payment authorization.
4. The client repeats the same method, URL, and JSON body with `PAYMENT-SIGNATURE` attached.
5. The InFlow facilitator verifies the payment, MrScraper runs the service, and the payment is settled when the gateway returns a successful response.
| Header | Direction | Purpose |
| ------------------- | --------- | ------------------------------------------------------------------------ |
| `PAYMENT-REQUIRED` | Response | Base64-encoded x402 v2 requirements on the initial unpaid challenge. |
| `PAYMENT-SIGNATURE` | Request | Base64-encoded payment payload generated by the buyer client. |
| `PAYMENT-RESPONSE` | Response | Base64-encoded settlement result, present after a successful settlement. |
The requests below show the JSON inputs and return HTTP `402` when sent without payment. Use your x402 buyer client to sign and complete the paid request.
Invalid service inputs are rejected with HTTP `400` before payment is requested. Unknown request fields are ignored. Use the field names documented here, including camelCase options such as `proxyCountry` and `numResults`.
## scraperAPI
Retrieve public webpage content, including pages rendered with JavaScript. Use the returned content for research, public product and price monitoring, article collection, or retrieval workflows. Availability depends on the target website.
```bash
curl -i 'https://api.mrscraper.com/inflowpay/api/mrscraper/scraperAPI' \
-H 'Content-Type: application/json' \
--data '{
"url": "https://example.com",
"html": true,
"markdown": true,
"screenshot": false
}'
```
### Request fields
| Field | Type | Required | Default / accepted values |
| ------------------ | ------- | -------- | ---------------------------------------------------------------------------------------------------- |
| `url` | string | Yes | Public HTTP(S) URL without embedded credentials. Private/local hosts and IPv6 literals are rejected. |
| `html` | boolean | No | `true`. The renderer currently returns `html` even when set to `false`. |
| `markdown` | boolean | No | Include Markdown in the `markdown` field. |
| `screenshot` | boolean | No | Include a base64 JPEG in the `screenshot` field. Can substantially increase response size. |
| `proxyCountry` | string | No | `"us"`. Two-letter proxy country code. Also used as `geoCode` when `geoCode` is omitted. |
| `geoCode` | string | No | Two-letter upstream geo code. Defaults to `proxyCountry`. |
| `browserRendering` | boolean | No | `true`. Set to `false` to fetch the page without JavaScript rendering. |
| `timeout` | integer | No | `1`–`300` seconds for upstream page retrieval. |
| `maxRetries` | integer | No | `1`–`10` upstream retries. `0` is not accepted. |
| `tokenCap` | integer | No | `1`–`10000` upstream plan tokens for retries. Separate from the USDC price. |
| `waitUntil` | string | No | `"domcontentloaded"`, `"load"`, or `"networkidle"`. |
| `waitForSelector` | string | No | CSS selector, up to 1,000 characters. |
| `blockResources` | boolean | No | Forward the renderer's resource-blocking option. |
| `warmStart` | boolean | No | Visit the site's root before retrieving the target page. |
| `returnCookie` | boolean | No | Request upstream cookie information when supported. |
| `super` | boolean | No | Forward the real-device routing option. |
Fields without a documented default are forwarded only when supplied; otherwise, the upstream service chooses its default.
### Response
The response body is the renderer result itself, without an `ok`/`service`/`data` wrapper. Illustrative successful response:
```json
{
"html": "Example Domain
",
"markdown": "# Example Domain",
"screenshot": null,
"runtime": 4.2,
"retry_count": 0,
"error": null
}
```
| Field | Type | Meaning |
| ------------- | -------------- | ----------------------------------------------------------------------------- |
| `html` | string | Rendered HTML; can be empty when disabled. |
| `markdown` | string | Markdown; can be empty when disabled. |
| `screenshot` | string or null | Base64 JPEG image bytes, without a `data:` prefix; can be null when disabled. |
| `runtime` | number | Upstream renderer runtime in seconds. |
| `retry_count` | integer | Retries reported by the renderer. |
| `error` | string or null | Upstream page-rendering error, if any. |
Disabled outputs can remain present with empty or null values. Allow enough time in your client for rendering and response transfer. The request's `timeout` field is separate from your client's HTTP deadline.
## webSearch
Search the web to retrieve real-time search results, including relevant website URLs, titles, and descriptions. Use `region` to compare results across countries.
```bash
curl -i 'https://api.mrscraper.com/inflowpay/api/mrscraper/webSearch' \
-H 'Content-Type: application/json' \
--data '{
"query": "web scraping",
"region": "us",
"numResults": 10
}'
```
### Request fields
| Field | Type | Required | Default / accepted values |
| ------------ | ------- | -------- | -------------------------------------------------------------- |
| `query` | string | Yes | Search text, 1–1,000 characters after trimming whitespace. |
| `region` | string | No | `"us"`. Two-letter country code for the results. |
| `numResults` | integer | No | `10`. Accepts `10`–`100`. The search can return fewer results. |
### Response
The response has `success`, `message`, and `data` at the top level, without an `ok`/`service` wrapper. `data` is the list of ranked results. Illustrative response, with the list shortened:
```json
{
"success": true,
"message": "Search completed",
"data": [
{
"rank": 1,
"title": "Web scraping",
"url": "https://en.wikipedia.org/wiki/Web_scraping",
"description": "Web scraping, web harvesting, or web data extraction is data scraping used for extracting data from websites.",
"source": "Wikipedia"
},
{
"rank": 2,
"title": "What is Web Scraping? The Complete Guide",
"url": "https://www.scraperapi.com/web-scraping/",
"description": "Web scraping, or web data extraction, is the process of extracting publicly available web data using automated tools.",
"source": "ScraperAPI"
}
]
}
```
| Field | Type | Meaning |
| -------------------- | ------- | ------------------------------------------------------------- |
| `success` | boolean | Whether the upstream search service succeeded. |
| `message` | string | Upstream status message. |
| `data` | array | Ranked results, at most `numResults`. Can be empty. |
| `data[].rank` | integer | One-based position in the results. |
| `data[].title` | string | Result title. |
| `data[].url` | string | Destination page URL. |
| `data[].description` | string | Result snippet, when available. |
| `data[].source` | string | Site or publisher name shown with the result, when available. |
Upstream `tokenUsage` is omitted. When `success` is `false`, the shape of `data` varies by failure and can be `null`.
## Errors
| HTTP status | Meaning |
| ----------- | --------------------------------------------------------------------------------------------------------------- |
| `200` | Upstream request completed. Inspect `error` for scraperAPI or `success` for webSearch. |
| `400` | Invalid service inputs, rejected before payment. |
| `402` | Payment required or rejected. Read the payment headers and any error details. |
| `500` | Unexpected gateway or payment-processing error. The payment is not settled. |
| `502` | Upstream connection, HTTP status, or response-size error, or a facilitator failure. The payment is not settled. |
| `504` | Upstream HTTP request timed out. The payment is not settled. |
Gateway validation and upstream errors use an `ok: false` envelope:
```json
{
"ok": false,
"error": {
"code": "INVALID_REQUEST",
"message": "Request validation failed",
"issues": [
{
"path": ["url"],
"message": "URL must target a public host"
}
]
}
}
```
This is an illustrative validation error; issue messages vary. Other error codes include `UPSTREAM_TIMEOUT`, `UPSTREAM_HTTP_ERROR`, `UPSTREAM_TOO_LARGE`, `UPSTREAM_UNAVAILABLE`, and `INTERNAL_ERROR`. Payment middleware errors use a different shape: a string `error` with optional `reason` or `message`; a facilitator failure on `502` can also use this shape. The initial unpaid `402` body is `{}`; its requirements are in `PAYMENT-REQUIRED`.
The payment is verified before the upstream service runs and settled only when the gateway returns a successful response. Requests that end in an HTTP error status (`400`, `402`, `500`, `502`, or `504`) are not settled. A `200` response whose upstream fields report an error, such as webSearch `success: false`, is still settled, so a retry is a new paid request.
# 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 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 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 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`
# 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 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/workflow-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 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 Platform API Server (`https://api.app.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 overloading target websites
* **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 requests fail consistently, 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.
# Cancel One Bulk Result 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 Platform API Server (`https://api.app.mrscraper.com`) host when calling this endpoint.
# Cancel All Bulk Results 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 Platform API Server (`https://api.app.mrscraper.com`) host when calling this endpoint.