# How do I add a fallback to Parallel's Extract API?

Keep Parallel for search and extraction, and send UpRock the URLs Extract couldn't fetch, along with any page you need from a specific country, which Extract can't do. Turn off its cache fallback first, because by default a failed live fetch quietly returns an older cached copy instead of an error.

Updated 24 Oct 2026. Web page: https://uprock.ai/compare/parallel

## On this page

- [What Parallel does well](#what-parallel-does-well)
- [The cache-fallback trap](#the-cache-fallback-trap)
- [Parallel and UpRock side by side](#parallel-and-uprock-side-by-side)
- [The fallback, in TypeScript and Python](#the-fallback-in-typescript-and-python)
- [FAQ](#faq)
- [Other use cases to explore](#explore)
- [Related articles](#related)
- [References](#references)
- [Get started](#get-started)

## What Parallel does well

Parallel builds web search and extraction for AI agents on top of its own index, which it describes as hundreds of billions of pages, including licensed content from paywalled publishers. Its Search API returns results with excerpts chosen for your objective, and Parallel publishes benchmarks where it leads (its own September 2026 runs put Parallel Advanced at 97% on a 100-question SimpleQA sample). Extract turns any public URL into markdown, JavaScript-heavy pages and PDFs included, the Task API runs multi-step research jobs, FindAll turns a description into a verified list of matching entities, and Monitor reruns a query on a schedule and notifies you when the answer changes. There are Python and TypeScript SDKs, a CLI, integrations with LangChain, Vercel, n8n and Zapier, and a Search MCP server anyone can use without a key.

For finding and summarizing information, Parallel is strong. Keep it.

## The cache-fallback trap

Extract can answer from Parallel's cache (fast) or fetch the page live (slower). `fetch_policy` controls that: `max_age_seconds` sets how old a cached copy may be (at least 10 minutes), `timeout_seconds` how long a live fetch may take.

The setting that matters for a backup is `disable_cache_fallback`. Its default is `false`, and Parallel's docs describe what that means: if a live fetch fails, Extract "falls back to older indexed content". So a page that has changed, or that refused Parallel's fetcher today, can come back looking fine, with yesterday's content.

Set it to `true`, and a failed live fetch shows up where you can act on it, in the response's `errors` list:

| What Extract returns | What it means | What to do |
|---|---|---|
| A result with `full_content` | Parallel got the page (live or from cache) | Use it |
| An `errors` entry, `http_status_code` 401, 403, 429 or 5xx | The site refused or failed the live fetch | Send to UpRock |
| An `errors` entry, `error_type` like `fetch_error`, no status | The fetch failed for another reason | Send to UpRock |
| An `errors` entry, `http_status_code` 404 or 410 | The page is gone | Don't retry |
| HTTP 401, 402, 422, 429 or 5xx for the whole request | A bad key, no credit, a bad body, the rate limit or a Parallel error | Send every URL to UpRock (and fix the request if it's a 422) |
| You need the page from one country | Extract has no country option | Send to UpRock |

The HTTP response is 200 even when some URLs failed. `error_type` is a free-form string; Parallel doesn't publish a list of values.

## Parallel and UpRock side by side

Parallel's numbers come from its pricing pages and docs, checked 24 Oct 2026.

| | Parallel | UpRock |
|---|---|---|
| Page extraction, per 1,000 | [$1](https://docs.parallel.ai/getting-started/pricing) per 1,000 URLs, excerpts or full content | $0.50 by card or USDC, $0.40 with UPT |
| Search, per 1,000 | [$1](https://docs.parallel.ai/getting-started/pricing) (`fast`, `turbo`) or $5 (`basic`, `advanced`, the default) for 10 results; $1 per 1,000 extra results | Web research, $1 ($0.80 with UPT), across several search engines. Most results were off-topic in our 24 Oct tests, so use Parallel for search for now |
| Research tasks, entity lists, monitoring | [Task](https://docs.parallel.ai/getting-started/pricing) $5 to $2,400 per 1,000 runs, by processor; FindAll $0.10 to $10 a run plus up to $1 a match; Monitor $3 or $10 per 1,000 runs | None yet |
| Own index | Yes, including licensed content | No. Every call fetches the page |
| Latency | [1 to 3 s cached, 60 to 90 s live](https://parallel.ai/pricing) (Extract) | 13 to 37 s fresh in our tests, about 1 s for a recent repeat |
| Country | Search: [`location`](https://docs.parallel.ai/search/advanced-search-settings), 37 countries. Extract: none | Every request: 63 countries, or a region |
| Where pages are fetched from | Not stated; [user-requested fetches identify as Shap-User](https://parallel.ai/parallel-web-systems-bots) | Devices whose owners opted in |
| Rate limits | [600 requests a minute](https://docs.parallel.ai/getting-started/rate-limits) for Extract and Search | Not published yet |
| MCP server | [Search MCP](https://docs.parallel.ai/integrations/mcp/search-mcp), free without a key; Task MCP with a key | Yes, remote (streamable HTTP) |
| Video | No | Search public video by moment, $1 per 1,000 searches |
| To try it | [Up to 5,000 requests a month](https://parallel.ai/pricing) at no cost on pay-as-you-go, up to $80 at signup and $5 a month | Prepaid credits |

Where Parallel is better: search quality and its own index, excerpts tuned to your objective, fast cached reads, a free MCP server, credits to try it, and three products UpRock has no equivalent for yet: Task, FindAll and Monitor. Where UpRock fits: the live fetches that failed, a page from a chosen country, a lower price per page, and video.

## The fallback, in TypeScript and Python

Every version call Extract with `full_content` and `disable_cache_fallback: true`, keep the pages that came back, skip the ones the site says are gone, and fetch the rest on UpRock in parallel. The SDK's timeout is raised past a minute and its retries are switched off, so a slow live fetch doesn't stall the batch. UpRock gets one `POST /v1/crawl` request with your key in an `Authorization: Bearer` header; the MCP and CLI tabs do the same through UpRock's MCP server (TypeScript) or CLI (Python).

### TypeScript (HTTP)

```ts
// npm i parallel-web   (Node 18+)   env: PARALLEL_API_KEY, UPROCK_API_KEY
import Parallel from "parallel-web";

// A live fetch can take a minute; give the SDK room past its 60 s default and skip its retries.
const parallel = new Parallel({
  apiKey: process.env.PARALLEL_API_KEY,
  timeout: 120_000,
  maxRetries: 0,
});

async function viaUpRock(url: string, country: string) {
  // One call: UpRock loads the page on a real device in that country, tries a fresh device
  // every 7 s (up to 3 tries) and returns markdown. Failed calls aren't billed.
  const res = await fetch("https://edge.uprock.com/v1/crawl", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.UPROCK_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ url, country }),
    signal: AbortSignal.timeout(90_000),
  });
  const page = await res.json();
  if (!res.ok) throw new Error(`UpRock ${res.status} ${page.code}: ${page.error}`);
  return page.markdown ?? "";
}

export async function extract(urls: string[], country = "US") {
  const pages = new Map<string, { via: string; markdown: string }>();
  const gone = new Set<string>();
  try {
    const res = await parallel.extract({
      urls,
      advanced_settings: {
        full_content: true,
        // By default, a failed live fetch quietly falls back to an older cached copy. Turn that
        // off so failures show up in `errors`, where the code below can send them to UpRock.
        fetch_policy: { disable_cache_fallback: true, timeout_seconds: 60 },
      },
    });
    for (const r of res.results) {
      if (r.full_content)
        pages.set(r.url, { via: "parallel", markdown: r.full_content });
    }
    for (const e of res.errors) {
      // The site says the page is gone: a second crawler will see the same.
      if (e.http_status_code === 404 || e.http_status_code === 410) gone.add(e.url);
      console.warn(`Parallel: ${e.url} ${e.error_type} ${e.http_status_code ?? ""}`);
    }
  } catch (err) {
    // 401, 402 (out of credit), 422, 429 or 5xx: the whole request failed.
    console.warn(
      `Parallel failed (${(err as Error).message}); sending every URL to UpRock`,
    );
  }
  // Extract has no country option, so the retry is also how you get a page from one country.
  const retry = urls.filter((u) => !pages.has(u) && !gone.has(u));
  const retried = await Promise.allSettled(retry.map((u) => viaUpRock(u, country)));
  retried.forEach((r, i) => {
    if (r.status === "fulfilled")
      pages.set(retry[i], { via: "uprock", markdown: r.value });
    else console.warn(`UpRock also failed for ${retry[i]}: ${r.reason}`);
  });
  return pages;
}

// node extract.ts DE https://developer.mozilla.org/en-US/docs/Web/HTTP https://example.org
const [country = "US", ...urls] = process.argv.slice(2);
for (const [url, page] of await extract(urls, country)) {
  console.log(page.via.padEnd(8), url, page.markdown.length, "chars");
}
```

### Python (HTTP)

```python
# pip install parallel-web requests   env: PARALLEL_API_KEY, UPROCK_API_KEY
import os
import sys
from concurrent.futures import ThreadPoolExecutor

import requests
from parallel import Parallel

# A live fetch can take a minute; give the SDK room past its 60 s default and skip its retries.
parallel = Parallel(
    api_key=os.environ.get("PARALLEL_API_KEY"), timeout=120, max_retries=0
)


def via_uprock(url: str, country: str) -> str:
    # One call: UpRock loads the page on a real device in that country, tries a fresh device
    # every 7 s (up to 3 tries) and returns markdown. Failed calls aren't billed.
    res = requests.post(
        "https://edge.uprock.com/v1/crawl",
        headers={"Authorization": f"Bearer {os.environ['UPROCK_API_KEY']}"},
        json={"url": url, "country": country},
        timeout=90,
    )
    page = res.json()
    if not res.ok:
        raise RuntimeError(f"UpRock {res.status_code} {page.get('code')}: {page.get('error')}")
    return page.get("markdown", "")


def extract(urls: list[str], country: str = "US") -> dict[str, dict]:
    pages, gone = {}, set()
    try:
        res = parallel.extract(
            urls=urls,
            advanced_settings={
                "full_content": True,
                # By default, a failed live fetch quietly falls back to an older cached copy.
                # Turn that off so failures show up in `errors` and can go to UpRock.
                "fetch_policy": {"disable_cache_fallback": True, "timeout_seconds": 60},
            },
        )
        for r in res.results:
            if r.full_content:
                pages[r.url] = {"via": "parallel", "markdown": r.full_content}
        for e in res.errors:
            if e.http_status_code in (404, 410):
                gone.add(e.url)  # the site says the page is gone
            print(
                f"Parallel: {e.url} {e.error_type} {e.http_status_code or ''}",
                file=sys.stderr,
            )
    except Exception as err:
        # 401, 402 (out of credit), 422, 429 or 5xx: the whole request failed.
        print(f"Parallel failed ({err}); sending every URL to UpRock", file=sys.stderr)

    # Extract has no country option, so the retry is also how you get a page from one country.
    retry = [u for u in urls if u not in pages and u not in gone]
    with ThreadPoolExecutor(max_workers=8) as pool:
        futures = {u: pool.submit(via_uprock, u, country) for u in retry}
    for url, future in futures.items():
        try:
            pages[url] = {"via": "uprock", "markdown": future.result()}
        except Exception as err:
            print(f"UpRock also failed for {url}: {err}", file=sys.stderr)
    return pages


if __name__ == "__main__":
    # python extract.py DE https://developer.mozilla.org/en-US/docs/Web/HTTP https://example.org
    country, *urls = sys.argv[1:] or ["US"]
    for url, page in extract(urls, country).items():
        print(page["via"].ljust(8), url, len(page["markdown"]), "chars")
```

### TypeScript (MCP)

```ts
// npm i parallel-web @modelcontextprotocol/sdk   (Node 18+)   env: PARALLEL_API_KEY, UPROCK_API_KEY
import Parallel from "parallel-web";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

// A live fetch can take a minute; give the SDK room past its 60 s default and skip its retries.
const parallel = new Parallel({
  apiKey: process.env.PARALLEL_API_KEY,
  timeout: 120_000,
  maxRetries: 0,
});
const uprock = new Client({ name: "parallel-fallback", version: "1.0.0" });
await uprock.connect(
  new StreamableHTTPClientTransport(
    new URL("https://mcp.uprock.ai/mcp"),
    { requestInit: { headers: { Authorization: `Bearer ${process.env.UPROCK_API_KEY}` } } },
  ),
);

const textOf = (content: unknown) =>
  (content as { type: string; text?: string }[]).find((c) => c.type === "text")?.text ??
  "";

async function viaUpRock(url: string, country: string) {
  const res = await uprock.callTool(
    { name: "crawl_fetch", arguments: { url, country } },
    undefined,
    { timeout: 300_000 },
  );
  if (res.isError) throw new Error(`UpRock: ${textOf(res.content)}`);
  const uri = JSON.parse(textOf(res.content)).content?.markdown?.resource;
  if (!uri) throw new Error(`UpRock: no markdown for ${url}`);
  return textOf(
    (await uprock.callTool({ name: "resource_fetch", arguments: { uri } })).content,
  );
}

export async function extract(urls: string[], country = "US") {
  const pages = new Map<string, { via: string; markdown: string }>();
  const gone = new Set<string>();
  try {
    const res = await parallel.extract({
      urls,
      advanced_settings: {
        full_content: true,
        // By default, a failed live fetch quietly falls back to an older cached copy. Turn that
        // off so failures show up in `errors`, where the code below can send them to UpRock.
        fetch_policy: { disable_cache_fallback: true, timeout_seconds: 60 },
      },
    });
    for (const r of res.results) {
      if (r.full_content)
        pages.set(r.url, { via: "parallel", markdown: r.full_content });
    }
    for (const e of res.errors) {
      // The site says the page is gone: a second crawler will see the same.
      if (e.http_status_code === 404 || e.http_status_code === 410) gone.add(e.url);
      console.warn(`Parallel: ${e.url} ${e.error_type} ${e.http_status_code ?? ""}`);
    }
  } catch (err) {
    // 401, 402 (out of credit), 422, 429 or 5xx: the whole request failed.
    console.warn(
      `Parallel failed (${(err as Error).message}); sending every URL to UpRock`,
    );
  }
  // Extract has no country option, so the retry is also how you get a page from one country.
  const retry = urls.filter((u) => !pages.has(u) && !gone.has(u));
  const retried = await Promise.allSettled(retry.map((u) => viaUpRock(u, country)));
  retried.forEach((r, i) => {
    if (r.status === "fulfilled")
      pages.set(retry[i], { via: "uprock", markdown: r.value });
    else console.warn(`UpRock also failed for ${retry[i]}: ${r.reason}`);
  });
  return pages;
}

// node extract.ts DE https://developer.mozilla.org/en-US/docs/Web/HTTP https://example.org
const [country = "US", ...urls] = process.argv.slice(2);
try {
  for (const [url, page] of await extract(urls, country)) {
    console.log(page.via.padEnd(8), url, page.markdown.length, "chars");
  }
} finally {
  await uprock.close();
}
```

### Python (CLI)

```python
# pip install parallel-web; npm i -g uprock   env: PARALLEL_API_KEY, UPROCK_API_KEY
import json
import os
import subprocess
import sys
from concurrent.futures import ThreadPoolExecutor

from parallel import Parallel

# A live fetch can take a minute; give the SDK room past its 60 s default and skip its retries.
parallel = Parallel(
    api_key=os.environ.get("PARALLEL_API_KEY"), timeout=120, max_retries=0
)


def via_uprock(url: str, country: str) -> str:
    run = subprocess.run(
        ["uprock", "ai", "crawl", url, "--country", country, "--content"],
        capture_output=True,
        text=True,
        timeout=330,
    )
    if run.returncode != 0:
        raise RuntimeError(f"UpRock: {run.stderr.strip()}")
    return json.loads(run.stdout).get("inlined_markdown", "")


def extract(urls: list[str], country: str = "US") -> dict[str, dict]:
    pages, gone = {}, set()
    try:
        res = parallel.extract(
            urls=urls,
            advanced_settings={
                "full_content": True,
                # By default, a failed live fetch quietly falls back to an older cached copy.
                # Turn that off so failures show up in `errors` and can go to UpRock.
                "fetch_policy": {"disable_cache_fallback": True, "timeout_seconds": 60},
            },
        )
        for r in res.results:
            if r.full_content:
                pages[r.url] = {"via": "parallel", "markdown": r.full_content}
        for e in res.errors:
            if e.http_status_code in (404, 410):
                gone.add(e.url)  # the site says the page is gone
            print(
                f"Parallel: {e.url} {e.error_type} {e.http_status_code or ''}",
                file=sys.stderr,
            )
    except Exception as err:
        # 401, 402 (out of credit), 422, 429 or 5xx: the whole request failed.
        print(f"Parallel failed ({err}); sending every URL to UpRock", file=sys.stderr)

    # Extract has no country option, so the retry is also how you get a page from one country.
    retry = [u for u in urls if u not in pages and u not in gone]
    with ThreadPoolExecutor(max_workers=8) as pool:
        futures = {u: pool.submit(via_uprock, u, country) for u in retry}
    for url, future in futures.items():
        try:
            pages[url] = {"via": "uprock", "markdown": future.result()}
        except Exception as err:
            print(f"UpRock also failed for {url}: {err}", file=sys.stderr)
    return pages


if __name__ == "__main__":
    # python extract.py DE https://developer.mozilla.org/en-US/docs/Web/HTTP https://example.org
    country, *urls = sys.argv[1:] or ["US"]
    for url, page in extract(urls, country).items():
        print(page["via"].ljust(8), url, len(page["markdown"]), "chars")
```

Tested 21 Oct 2026 against the live UpRock API with an invalid Parallel key (a 401, so every URL goes to UpRock). Without a Parallel account, the per-URL `errors` path follows Parallel's docs and SDK types (parallel-web 1.3.6). On 6 Nov 2026 we ran the HTTP and MCP versions again with an UpRock API key in an `Authorization` header: with an invalid Parallel key, each fell back to UpRock and got the page.

## FAQ

### What does disable_cache_fallback do?

It decides what Parallel does when a live fetch fails or times out. With the default (false), Extract falls back to older indexed content and returns that as if it were fine. With true, it returns an error for that URL instead, which is what a fallback needs to see.

### Can Parallel Extract fetch a page from a specific country?

Not according to its docs. Parallel's Search takes a location (37 countries are listed), but Extract's settings cover only the fetch policy, excerpts and full content. Parallel's docs don't say where its fetches come from. UpRock takes a country on every request.

### Is UpRock cheaper than Parallel?

For fetching pages, yes. Extract costs $1 per 1,000 URLs; UpRock costs $0.50 per 1,000 pages by card or USDC, though Parallel's price also covers excerpts chosen for your objective. For search, Parallel's turbo and fast modes cost $1 per 1,000, the same as UpRock's web research at $1. Most of the results UpRock's research returned in our 24 Oct tests were off-topic, so use Parallel for search for now.

### How fast is each?

Parallel's pricing page puts a cached Extract at 1 to 3 seconds and a live one at 60 to 90 seconds. In our tests a fresh UpRock fetch took 13 to 37 seconds end to end, and a recently fetched page came back in about a second.

### Does Parallel have a free MCP server?

Yes. Its Search MCP at search.parallel.ai/mcp works anonymously, with an optional API key for higher limits, and includes a web_fetch tool for up to 20 URLs.

## Other use cases to explore

- [Decide which failed pages are worth retrying](https://uprock.ai/use-cases/agent-gets-403): a diagnosis table from status code to the legitimate fix, and when to stop.
- [See a page as it looks in another country](https://uprock.ai/use-cases/page-from-another-country): one store page from five countries, with five prices, two languages and a cookie banner in one country only.
- [Work out what a browser read really costs](https://uprock.ai/compare/browserbase#what-1000-page-reads-cost): per-minute billing, proxy megabytes and a fetch API, side by side for 1,000 pages.
- [Search public video by moment](https://uprock.ai/video-semantic-search): find the second something is shown or said, across platforms.

## Related articles

- [How do I add a backup crawler to Firecrawl?](https://uprock.ai/compare/firecrawl.md): When to send a page from Firecrawl to UpRock, published prices side by side, and a tested fallback in TypeScript and Python.
- [How do I add a backup for Tavily Extract?](https://uprock.ai/compare/tavily.md): Retry the URLs in Tavily Extract's failed results on a real device, and read pages as they appear in a chosen country. Prices side by side and tested code.
- [How do I add a fallback for Exa contents errors?](https://uprock.ai/compare/exa.md): Read the per-URL statuses in Exa's /contents response and retry the right ones live on a real device. Error tags explained, prices side by side, tested code.
- [How do I add a backup to Jina Reader, and when is it cheaper?](https://uprock.ai/compare/jina-reader.md): Spot a failed read in Reader's JSON (it still answers 200), retry it on a real device, and see what six real pages cost in Reader tokens next to a flat per-page price.
- [How do I add a hosted fallback to Crawl4AI?](https://uprock.ai/compare/crawl4ai.md): Plug UpRock into Crawl4AI's fallback_fetch_function so blocked pages are fetched on a real device in the country you choose, then run through Crawl4AI's own markdown pipeline.
- [How do I add a backup to Bright Data's Web Unlocker?](https://uprock.ai/compare/bright-data.md): Which Web Unlocker errors to retry, which to send to a second network and which to respect, with Bright Data's published prices next to ours and tested fallback code.
- [How do I add a fallback to an Apify or Crawlee crawler?](https://uprock.ai/compare/apify.md): Hand the requests Crawlee gives up on to a second network with failedRequestHandler, see what a fetched page costs on Apify's own Actors, and run the tested code.
- [When should a Browserbase agent read a page without opening a browser?](https://uprock.ai/compare/browserbase.md): What 1,000 page reads cost on Browserbase three ways, when to send a read to UpRock instead (including when every browser is busy), and tested fallback code.
- [How do I cap ScrapingBee's credit cost and send the rest to a backup?](https://uprock.ai/compare/scrapingbee.md): ScrapingBee charges 1 to 75 credits a page depending on the options. Cap it with Auto-Mode and max_cost, watch the country fallback, and send the rest to UpRock with tested code.
- [Spider costs less per page than UpRock. When is a backup still worth it?](https://uprock.ai/compare/spider.md): Spider is cheaper per page, so keep it as your primary. How Spider reports a page it couldn't get (from our own tests), and tested code that sends only those pages to UpRock.
- [How do I add a backup to ZenRows?](https://uprock.ai/compare/zenrows.md): Which ZenRows error codes to send to a second network and which to respect, what a page from one country costs once premium proxies are required, and tested fallback code.
- [How do I retry a ScraperAPI batch's failed jobs on another network?](https://uprock.ai/compare/scraperapi.md): Send the jobs ScraperAPI's async batch gives up on to UpRock, see which countries each ScraperAPI plan can target, and compare credit costs. Tested code for both.
- [How do I add a backup to Oxylabs' new Web API?](https://uprock.ai/compare/oxylabs.md): Which Oxylabs Web API failures to send to a second network and which to respect, what a generic page really costs after its October 2026 pricing change, and tested fallback code.
- [How do I add a backup to Context.dev's scrape API?](https://uprock.ai/compare/context-dev.md): Context.dev reports a failed scrape inside an HTTP 200. Which of its error codes to retry on a second network, what a page costs by plan, and tested fallback code.
- [How do I add a backup to Scrapfly instead of paying for residential?](https://uprock.ai/compare/scrapfly.md): A Scrapfly page costs 1 to 30 credits depending on proxy pool and browser. What that is per 1,000 pages on each plan, which errors to send on, and tested code.
- [How do I keep Crawlbase's site tiers from surprising my bill?](https://uprock.ai/compare/crawlbase.md): Crawlbase bills each site at 1 to 20 times its base rate. What that does to the cost per 1,000 pages, and tested code that moves pricey domains to UpRock.
- [Which unlocker API fits: Bright Data, Oxylabs, Zyte or UpRock?](https://uprock.ai/compare/web-unlocker-apis.md): Bright Data's Web Unlocker, Oxylabs' Web API and Zyte API priced per 1,000 hard pages, with what each bills and when a second network helps.
- [Compare: all articles](https://uprock.ai/compare.md)

## References

1. [Parallel docs, Pricing](https://docs.parallel.ai/getting-started/pricing), checked 24 Oct 2026
2. [Parallel, Extract product page](https://parallel.ai/products/extract), checked 21 Oct 2026
3. [Parallel, Pricing (free credits, latency)](https://parallel.ai/pricing), checked 24 Oct 2026
4. [Parallel docs, Advanced extract settings (fetch policy)](https://docs.parallel.ai/extract/advanced-extract-settings), checked 21 Oct 2026
5. [Parallel docs, Advanced search settings (location)](https://docs.parallel.ai/search/advanced-search-settings), checked 21 Oct 2026
6. [Parallel docs, Rate limits](https://docs.parallel.ai/getting-started/rate-limits), checked 24 Oct 2026
7. [Parallel docs, Search MCP](https://docs.parallel.ai/integrations/mcp/search-mcp), checked 21 Oct 2026
8. [Parallel, Bots and crawlers](https://parallel.ai/parallel-web-systems-bots), checked 21 Oct 2026
9. [UpRock, everything in one file (API, CLI, MCP, pricing)](https://uprock.ai/llms-full.txt), checked 24 Oct 2026

## Get started

Get an API key: https://uprock.ai/app/api-keys

Paste this into your agent:

```text
Set up UpRock for me: read https://uprock.ai/agents.md, connect the UpRock MCP server, and run one test crawl. Tell me what it costs before you spend anything.
```

Setup for every client (MCP, skill, CLI): https://uprock.ai/agents.md
