Tutorial

How to Switch from Brave Search Free Tier to a Scalable API

Migrate from Brave Search API free tier with its 2K queries/mo cap to a scalable search API. Step-by-step code migration with Python and JS examples.

Switching from the Brave Search API free tier to Scavio takes about 15 minutes of code changes and removes the 2,000 queries/month cap that blocks most production workloads. This tutorial walks you through the migration step by step: mapping Brave response fields to Scavio equivalents, updating your HTTP calls, adjusting error handling, and validating that your downstream logic works with the new response format.

Prerequisites

  • Existing Brave Search API integration you want to migrate
  • Scavio API key (free 250 credits/mo at scavio.dev)
  • Python 3.9+ or Node.js 18+

Walkthrough

Step 1: Audit your current Brave Search usage

Before migrating, audit how you currently call the Brave API. Note the endpoint, headers, query parameters, and which response fields your code actually uses. Most integrations only use title, url, and description from the web search results, which makes migration straightforward.

Python
# Typical Brave Search API call you are replacing
import requests

BRAVE_API_KEY = 'your_brave_key'
resp = requests.get(
    'https://api.search.brave.com/res/v1/web/search',
    headers={'X-Subscription-Token': BRAVE_API_KEY},
    params={'q': 'best crm for startups 2026', 'count': 10}
)
data = resp.json()
for result in data.get('web', {}).get('results', []):
    print(result['title'], result['url'], result.get('description', ''))

Step 2: Map Brave response fields to Scavio equivalents

Scavio returns results under an organic array instead of web.results. The field names differ slightly: Brave uses description while Scavio uses snippet. Create a mapping so you can update all references in one pass.

Python
# Field mapping: Brave -> Scavio
# data.web.results         -> data.organic
# result.title              -> item.title       (same)
# result.url                -> item.url         (same)
# result.description        -> item.snippet
# result.extra_snippets     -> (not applicable)
# params.q                  -> json body: query
# params.count              -> json body: num
# header X-Subscription-Token -> header x-api-key

Step 3: Replace the API call

Swap the Brave GET request for a Scavio POST request. The Scavio API uses a JSON body instead of query parameters, and an x-api-key header instead of X-Subscription-Token.

Python
import requests

SCAVIO_API_KEY = 'your_scavio_api_key'

def search(query, num=10):
    resp = requests.post(
        'https://api.scavio.dev/api/v1/search',
        headers={'x-api-key': SCAVIO_API_KEY},
        json={'query': query, 'num': num}
    )
    resp.raise_for_status()
    data = resp.json()
    return [
        {
            'title': item.get('title', ''),
            'url': item.get('url', ''),
            'description': item.get('snippet', ''),
        }
        for item in data.get('organic', [])
    ]

Step 4: Update error handling and rate limits

Brave returns 429 when you hit the free tier cap. Scavio returns standard HTTP error codes and includes rate limit headers. Update your retry logic to read the x-ratelimit-remaining header and back off before hitting the limit rather than after.

Python
import time

def search_with_retry(query, num=10, max_retries=3):
    for attempt in range(max_retries):
        resp = requests.post(
            'https://api.scavio.dev/api/v1/search',
            headers={'x-api-key': SCAVIO_API_KEY},
            json={'query': query, 'num': num}
        )
        if resp.status_code == 200:
            return resp.json()
        if resp.status_code == 429:
            wait = 2 ** attempt
            print(f'Rate limited, waiting {wait}s...')
            time.sleep(wait)
            continue
        resp.raise_for_status()
    raise Exception('Max retries exceeded')

Step 5: Validate output parity

Run both APIs side by side on a sample of queries and compare the results to verify your downstream logic works correctly. Check that titles, URLs, and descriptions are populated and that your parsing code handles the new format without errors.

Python
test_queries = [
    'best crm for startups 2026',
    'python web scraping tutorial',
    'saas pricing page examples',
]

for q in test_queries:
    results = search(q, num=5)
    print(f'Query: {q}')
    print(f'  Results: {len(results)}')
    for r in results:
        assert r['title'], 'Missing title'
        assert r['url'], 'Missing url'
        print(f'  - {r["title"][:60]}')
    print()

Python Example

Python
import requests
import time

SCAVIO_API_KEY = 'your_scavio_api_key'

def search(query, num=10, max_retries=3):
    for attempt in range(max_retries):
        resp = requests.post(
            'https://api.scavio.dev/api/v1/search',
            headers={'x-api-key': SCAVIO_API_KEY},
            json={'query': query, 'num': num}
        )
        if resp.status_code == 200:
            data = resp.json()
            return [
                {
                    'title': item.get('title', ''),
                    'url': item.get('url', ''),
                    'description': item.get('snippet', ''),
                }
                for item in data.get('organic', [])
            ]
        if resp.status_code == 429:
            time.sleep(2 ** attempt)
            continue
        resp.raise_for_status()
    raise Exception('Max retries exceeded')

# Validate migration
test_queries = [
    'best crm for startups 2026',
    'python web scraping tutorial',
    'saas pricing page examples',
]

for q in test_queries:
    results = search(q, num=5)
    print(f'Query: {q} -> {len(results)} results')
    for r in results:
        print(f'  {r["title"][:60]}')

JavaScript Example

JavaScript
const SCAVIO_API_KEY = 'your_scavio_api_key';

async function search(query, num = 10, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const resp = await fetch('https://api.scavio.dev/api/v1/search', {
      method: 'POST',
      headers: { 'x-api-key': SCAVIO_API_KEY, 'Content-Type': 'application/json' },
      body: JSON.stringify({ query, num }),
    });
    if (resp.ok) {
      const data = await resp.json();
      return (data.organic || []).map(item => ({
        title: item.title || '',
        url: item.url || '',
        description: item.snippet || '',
      }));
    }
    if (resp.status === 429) {
      await new Promise(r => setTimeout(r, 2 ** attempt * 1000));
      continue;
    }
    throw new Error(`API error: ${resp.status}`);
  }
  throw new Error('Max retries exceeded');
}

async function main() {
  const testQueries = [
    'best crm for startups 2026',
    'python web scraping tutorial',
    'saas pricing page examples',
  ];

  for (const q of testQueries) {
    const results = await search(q, 5);
    console.log(`Query: ${q} -> ${results.length} results`);
    for (const r of results) {
      console.log(`  ${r.title.slice(0, 60)}`);
    }
  }
}

main();

Expected Output

JSON
Query: best crm for startups 2026 -> 5 results
  The 10 Best CRMs for Startups in 2026 - Detailed Comparison
  ...
Query: python web scraping tutorial -> 5 results
  ...
Query: saas pricing page examples -> 5 results
  ...

Related Tutorials

Frequently Asked Questions

Most developers complete this tutorial in 15 to 30 minutes. You will need a Scavio API key (free tier works) and a working Python or JavaScript environment.

Existing Brave Search API integration you want to migrate. Scavio API key (free 250 credits/mo at scavio.dev). Python 3.9+ or Node.js 18+. A Scavio API key gives you 250 free credits per month.

Yes. The free tier includes 250 credits per month, which is more than enough to complete this tutorial and prototype a working solution.

Scavio has a native LangChain package (langchain-scavio), an MCP server, and a plain REST API that works with any HTTP client. This tutorial uses the raw REST API, but you can adapt to your framework of choice.

Start Building

Migrate from Brave Search API free tier with its 2K queries/mo cap to a scalable search API. Step-by-step code migration with Python and JS examples.