> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tallyscrape.com/llms.txt
> Use this file to discover all available pages before exploring further.

# POST /scrape

> Scrape a URL and return structured JSON.

Scrape a single URL and return structured JSON. Billing is prepaid: the cost depends on
the `engine` and `proxy_type` you pick (see [Pricing](/pricing)). You are debited **only
on a real success** (`success: true` and `blocked: false`) — failed or blocked requests
are not billed.

```
POST https://api.tallyscrape.com/scrape
```

## Request

### Headers

<ParamField header="X-API-Key" type="string" required>
  Your API key (starts with `spy_`). See [Authentication](/authentication).
</ParamField>

<ParamField header="Content-Type" type="string" required>
  Must be `application/json`.
</ParamField>

### Body

<ParamField body="url" type="string" required>
  The target URL to scrape. Must be a valid `http` or `https` URL.
</ParamField>

<ParamField body="engine" type="string" default="static">
  Rendering engine. `static` uses a fast HTTP fetch. `js` runs the page in a real headless
  browser (for client-side rendered content) and costs more credits.

  Allowed values: `static`, `js`.
</ParamField>

<ParamField body="selectors" type="object">
  Optional map of `name → CSS selector` for targeted extraction. Each result is returned
  under `extracted[name]`. Example: `{ "price": ".price", "title": "h1" }`.
</ParamField>

<ParamField body="respect_robots" type="boolean" default={true}>
  Respect the target's `robots.txt`. Defaults to `true` (the safe choice). Set to `false`
  to ignore it.
</ParamField>

<ParamField body="timeout" type="number" default={20}>
  Request timeout in seconds. Must be greater than `0` and at most `120`.
</ParamField>

<ParamField body="proxy_type" type="string" default="none">
  Proxy tier. `none` connects directly. `datacenter` and `residential` route through the
  server-owned proxy pools (you never provide proxy credentials). Residential may require
  unlocking — see [Errors](/errors) (403).

  Allowed values: `none`, `datacenter`, `residential`.
</ParamField>

## Response

<ResponseField name="url" type="string">The requested URL.</ResponseField>
<ResponseField name="final_url" type="string">The URL after any redirects.</ResponseField>
<ResponseField name="status_code" type="integer">HTTP status returned by the target.</ResponseField>

<ResponseField name="success" type="boolean">
  Whether the fetch succeeded. Only a `true` success (with `blocked: false`) is billed.
</ResponseField>

<ResponseField name="engine" type="string">The engine used (`static` or `js`).</ResponseField>
<ResponseField name="elapsed_ms" type="integer">Request time in milliseconds (the billing basis).</ResponseField>
<ResponseField name="error" type="string | null">Error message when `success` is `false`, otherwise `null`.</ResponseField>

<ResponseField name="blocked" type="boolean">
  `true` when an anti-bot page is detected. Blocked requests are **not** billed.
</ResponseField>

<ResponseField name="proxy_used" type="boolean">
  Whether a proxy was actually used for the returned request. May differ from the
  requested `proxy_type`: if the pool is unavailable, it falls back to a direct
  connection (billed at the `none` rate).
</ResponseField>

<ResponseField name="title" type="string | null">The page title.</ResponseField>
<ResponseField name="meta" type="object">Meta tags (e.g. `description`), as `name → content`.</ResponseField>
<ResponseField name="headings" type="object">Headings grouped by level, e.g. `{ "h1": [...], "h2": [...] }`.</ResponseField>
<ResponseField name="links" type="array">Links as `{ "text": ..., "href": ... }`, with absolute URLs.</ResponseField>
<ResponseField name="images" type="array">Absolute image URLs.</ResponseField>
<ResponseField name="text" type="string | null">Visible page text (scripts and styles excluded).</ResponseField>
<ResponseField name="extracted" type="object">Results of your `selectors`, keyed by the names you provided.</ResponseField>

## Examples

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.tallyscrape.com/scrape \
    -H "X-API-Key: spy_your_api_key" \
    -H "Content-Type: application/json" \
    -d '{
      "url": "https://quotes.toscrape.com/js/",
      "engine": "js",
      "proxy_type": "datacenter",
      "selectors": { "quotes": ".quote .text" }
    }'
  ```

  ```python Python theme={null}
  import requests

  resp = requests.post(
      "https://api.tallyscrape.com/scrape",
      headers={"X-API-Key": "spy_your_api_key"},
      json={
          "url": "https://quotes.toscrape.com/js/",
          "engine": "js",
          "proxy_type": "datacenter",
          "selectors": {"quotes": ".quote .text"},
      },
  )
  data = resp.json()
  print(data["extracted"]["quotes"])
  ```

  ```javascript JavaScript theme={null}
  const resp = await fetch("https://api.tallyscrape.com/scrape", {
    method: "POST",
    headers: {
      "X-API-Key": "spy_your_api_key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      url: "https://quotes.toscrape.com/js/",
      engine: "js",
      proxy_type: "datacenter",
      selectors: { quotes: ".quote .text" },
    }),
  });
  const data = await resp.json();
  console.log(data.extracted.quotes);
  ```

  ```java Java theme={null}
  import java.net.URI;
  import java.net.http.*;

  var body = """
      {"url":"https://quotes.toscrape.com/js/","engine":"js","proxy_type":"datacenter","selectors":{"quotes":".quote .text"}}
      """;

  var request = HttpRequest.newBuilder()
      .uri(URI.create("https://api.tallyscrape.com/scrape"))
      .header("X-API-Key", "spy_your_api_key")
      .header("Content-Type", "application/json")
      .POST(HttpRequest.BodyPublishers.ofString(body))
      .build();

  var response = HttpClient.newHttpClient()
      .send(request, HttpResponse.BodyHandlers.ofString());
  System.out.println(response.body());
  ```
</CodeGroup>

### Example response

```json theme={null}
{
  "url": "https://quotes.toscrape.com/js/",
  "final_url": "https://quotes.toscrape.com/js/",
  "status_code": 200,
  "success": true,
  "engine": "js",
  "elapsed_ms": 8734,
  "error": null,
  "blocked": false,
  "proxy_used": true,
  "title": "Quotes to Scrape",
  "meta": {},
  "headings": { "h1": ["Quotes to Scrape"] },
  "links": [{ "text": "Login", "href": "https://quotes.toscrape.com/login" }],
  "images": [],
  "text": "Quotes to Scrape ...",
  "extracted": {
    "quotes": ["“The world as we have created it is a process of our thinking...”"]
  }
}
```
