Tutorial

How to Build a Search Fallback After Google CSE Free Tier Ends

Build a drop-in search fallback before Google Custom Search Engine free tier shuts down in Jan 2027. Migrate to Scavio with one function swap.

Google Custom Search Engine free tier is limited to 50 domains and shuts down entirely in January 2027. If your app relies on Google CSE for free search, you need a migration plan now. This tutorial builds a fallback layer that tries your existing Google CSE first, then routes to Scavio when Google returns errors or when you exceed limits. The final step drops Google entirely. Scavio costs $0.005 per query with the free tier covering 250 credits per month.

Prerequisites

  • Python 3.9+ or Node.js 18+
  • An existing Google CSE integration
  • A Scavio API key from scavio.dev
  • requests library (Python) or fetch (Node.js)

Walkthrough

Step 1: Audit your current Google CSE usage

Before migrating, measure how many queries you send and which parameters you use. This determines cost and helps map Google CSE fields to Scavio fields.

Python
import os

# Your existing Google CSE config
GOOGLE_CSE_KEY = os.environ.get('GOOGLE_CSE_KEY', '')
GOOGLE_CSE_CX = os.environ.get('GOOGLE_CSE_CX', '')

# Typical Google CSE call for reference
# GET https://www.googleapis.com/customsearch/v1
#   ?key=KEY&cx=CX&q=QUERY&num=10
#
# Returns: items[].title, items[].link, items[].snippet

# Map Google CSE fields to Scavio fields:
field_map = {
    'items[].title': 'organic_results[].title',
    'items[].link': 'organic_results[].link',
    'items[].snippet': 'organic_results[].snippet',
    'items[].pagemap': 'not available (use scrape instead)',
    'searchInformation.totalResults': 'not available',
}

for google_field, scavio_field in field_map.items():
    print(f'  {google_field:40s} -> {scavio_field}')

Step 2: Build the dual-provider search function

Create a search function that tries Google CSE first and falls back to Scavio on any error, rate limit, or empty result.

Python
import requests, os, time

GOOGLE_KEY = os.environ.get('GOOGLE_CSE_KEY', '')
GOOGLE_CX = os.environ.get('GOOGLE_CSE_CX', '')
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']

def search_google_cse(query: str, num: int = 10) -> list:
    if not GOOGLE_KEY or not GOOGLE_CX:
        return []
    resp = requests.get('https://www.googleapis.com/customsearch/v1',
        params={'key': GOOGLE_KEY, 'cx': GOOGLE_CX, 'q': query, 'num': num},
        timeout=10)
    if resp.status_code != 200:
        print(f'Google CSE error: {resp.status_code}')
        return []
    items = resp.json().get('items', [])
    return [{'title': r['title'], 'link': r['link'],
             'snippet': r.get('snippet', '')} for r in items]

def search_scavio(query: str, num: int = 10) -> list:
    resp = requests.post('https://api.scavio.dev/api/v1/search',
        headers={'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'},
        json={'query': query, 'country_code': 'us', 'num_results': num})
    resp.raise_for_status()
    return [{'title': r['title'], 'link': r['link'],
             'snippet': r.get('snippet', '')} for r in resp.json().get('organic_results', [])]

def search(query: str, num: int = 10) -> dict:
    start = time.time()
    results = search_google_cse(query, num)
    if results:
        return {'results': results, 'provider': 'google_cse',
                'latency_ms': int((time.time() - start) * 1000), 'cost': 0}
    results = search_scavio(query, num)
    return {'results': results, 'provider': 'scavio',
            'latency_ms': int((time.time() - start) * 1000), 'cost': 0.005}

Step 3: Test both providers side by side

Run the same queries through both providers to verify Scavio returns equivalent results before cutting over.

Python
test_queries = [
    'best CRM software 2026',
    'python web scraping tutorial',
    'react server components explained',
]

for query in test_queries:
    google_results = search_google_cse(query, 5)
    scavio_results = search_scavio(query, 5)
    print(f'Query: {query}')
    print(f'  Google CSE: {len(google_results)} results')
    print(f'  Scavio:     {len(scavio_results)} results')
    if scavio_results:
        print(f'  Top Scavio: {scavio_results[0]["title"][:60]}')
    print()

Step 4: Drop-in replacement: remove Google CSE entirely

Once validated, replace your search function with Scavio only. This is your post-migration state -- no Google dependency.

Python
import requests, os

SCAVIO_KEY = os.environ['SCAVIO_API_KEY']

def search(query: str, num: int = 10) -> list:
    """Drop-in replacement for Google CSE. Same return format."""
    resp = requests.post('https://api.scavio.dev/api/v1/search',
        headers={'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'},
        json={'query': query, 'country_code': 'us', 'num_results': num})
    resp.raise_for_status()
    return [{'title': r['title'], 'link': r['link'],
             'snippet': r.get('snippet', '')} for r in resp.json().get('organic_results', [])]

# Usage is identical to before:
results = search('best CRM software 2026')
for r in results:
    print(f'{r["title"]}: {r["link"]}')
print(f'Cost: $0.005 per query, 250 free/month')

Python Example

Python
import requests, os

SCAVIO_KEY = os.environ['SCAVIO_API_KEY']

def search(query, num=10):
    resp = requests.post('https://api.scavio.dev/api/v1/search',
        headers={'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'},
        json={'query': query, 'country_code': 'us', 'num_results': num})
    resp.raise_for_status()
    return [{'title': r['title'], 'link': r['link'], 'snippet': r.get('snippet', '')}
            for r in resp.json().get('organic_results', [])]

results = search('best CRM software 2026')
for r in results:
    print(f'{r["title"]}: {r["link"]}')

JavaScript Example

JavaScript
const SCAVIO_KEY = process.env.SCAVIO_API_KEY;

async function search(query, num = 10) {
  const resp = await fetch('https://api.scavio.dev/api/v1/search', {
    method: 'POST',
    headers: { 'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json' },
    body: JSON.stringify({ query, country_code: 'us', num_results: num })
  });
  const data = await resp.json();
  return (data.organic_results || []).map(r => ({
    title: r.title, link: r.link, snippet: r.snippet || ''
  }));
}

search('best CRM software 2026').then(results =>
  results.forEach(r => console.log(`${r.title}: ${r.link}`)));

Expected Output

JSON
Query: best CRM software 2026
  Google CSE: 0 results
  Scavio:     10 results
  Top Scavio: Best CRM Software of 2026 - Forbes Advisor

Cost: $0.005 per query, 250 free/month

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.

Python 3.9+ or Node.js 18+. An existing Google CSE integration. A Scavio API key from scavio.dev. requests library (Python) or fetch (Node.js). 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

Build a drop-in search fallback before Google Custom Search Engine free tier shuts down in Jan 2027. Migrate to Scavio with one function swap.