# Brave Search Scraper - Independent Index Results (`s-r/brave-search-scraper`) Actor

Organic results from Brave Search, which runs its own index rather than reselling Google's or Bing's. Title, URL, host and description per row, with multi-page walks and market selection.

- **URL**: https://apify.com/s-r/brave-search-scraper.md
- **Developed by:** [SR](https://apify.com/s-r) (community)
- **Categories:** SEO tools, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 search results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Brave Search Scraper

Organic results from Brave Search. One row per result with the title, the URL,
the host and the description, across as many pages as you ask for.

Brave runs **its own index** rather than reselling Google's or Bing's, which is
the reason to scrape it: the same query returns a genuinely different set of
pages, and a domain that is invisible on Google sometimes is not here.

### Fast, and paced on purpose

Brave serves its results in the page itself, so each page is a single
request and a keyword comes back in a couple of seconds. Between requests
the actor waits a moment: Brave refuses anyone who asks too quickly, and one
refusal costs more time than all the pauses in a run put together. A run of
a hundred pages finishes in a few minutes at 256 MB.

### When Brave says no

If Brave refuses mid-run the actor carries on from the same page on a fresh
connection, up to **Attempts per run**. When every attempt is refused you get
a `blocked` error and `captchaAttempts` in the summary, so an empty run is
never ambiguous about why.

Results already collected before a refusal are kept, and nothing is fetched
twice.

### Paging

**Pages per keyword** walks deeper. Brave counts its offset in pages from zero,
which this handles for you: page 1 carries no offset, page 2 carries offset 1.

`rank` is assigned after duplicates are removed, so the numbering has no gaps
even when Brave repeats a URL across a page boundary.

### Errors

| Code | Meaning |
|---|---|
| `blocked` | Brave refused every attempt; some pages were not fetched |
| `no_results` | A page loaded and had no results on it |
| `http_error` | Brave answered with a status other than 200 |
| `bad_input` | No keyword was given |

**Only results are billed.** A run that gets nothing but refusals costs you the
run fee and nothing else.

### Related actors

For the other engines see the Google, Bing, Yahoo, DuckDuckGo and Baidu SERP
actors. Running two of them on the same keywords and diffing the domains is the
quickest way to find where an index disagrees.

# Actor input Schema

## `keywords` (type: `array`):

One per line.

## `country` (type: `string`):

Two-letter market code. Brave localises results, so this changes what comes back.

## `pages` (type: `integer`):

How deep to walk each keyword. Each page is one more request.

## `safesearch` (type: `string`):

Brave's own filter level.

## `maxResults` (type: `integer`):

Stop after this many rows. Also the cost ceiling for the run.

## `attempts` (type: `integer`):

How many times to continue on a fresh connection when Brave refuses the current one.

## Actor input object example

```json
{
  "keywords": [
    "best vpn 2026"
  ],
  "country": "nl",
  "pages": 1,
  "safesearch": "moderate",
  "maxResults": 200,
  "attempts": 3
}
```

# Actor output Schema

## `results` (type: `string`):

One row per result.

## `summary` (type: `string`):

Results returned, distinct hosts, pages fetched, and how many attempts Brave refused.

## `errors` (type: `string`):

Keywords that could not be read.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "keywords": [
        "price scraper"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/brave-search-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "keywords": ["price scraper"] }

# Run the Actor and wait for it to finish
run = client.actor("s-r/brave-search-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "keywords": [
    "price scraper"
  ]
}' |
apify call s-r/brave-search-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,s-r/brave-search-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/QCQBidtJfSIzdau8a/builds/T9LVvEmcfMelSeuK0/openapi.json
