Tutorial

How to Migrate from Google Custom Search Engine to a Search API in 2026

Step-by-step guide to migrating from Google Custom Search Engine to the Scavio search API before CSE shuts down web-wide search in January 2027.

Google Custom Search Engine closed to new signups and will end its search entire web feature on January 1, 2027. If your application relies on CSE for web search, you need a migration plan now. Scavio provides a drop-in replacement that covers Google, Amazon, YouTube, Walmart, Reddit, and TikTok from a single POST endpoint at $0.005 per request. This tutorial walks through every step: auditing your current CSE usage, mapping CSE parameters to Scavio equivalents, updating your code, and validating results.

Prerequisites

  • An existing Google CSE integration you need to migrate
  • Python 3.9+ or Node.js 18+ installed
  • A Scavio API key from scavio.dev
  • Access to your current CSE API key and search engine ID

Walkthrough

Step 1: Audit your current CSE usage

Before migrating, document every CSE call in your codebase. Record the query parameters you use, the response fields you parse, and your monthly request volume.

Python
# Typical Google CSE call you need to replace
import requests

CSE_KEY = 'your-google-api-key'
CSE_ID = 'your-search-engine-id'

def old_cse_search(query: str) -> list:
    resp = requests.get('https://www.googleapis.com/customsearch/v1', params={
        'key': CSE_KEY, 'cx': CSE_ID, 'q': query, 'num': 10
    })
    items = resp.json().get('items', [])
    return [{'title': i['title'], 'link': i['link'],
             'snippet': i.get('snippet', '')} for i in items]

# Document what you actually use from the response
results = old_cse_search('best python frameworks 2026')
for r in results:
    print(f"{r['title']} -> {r['link']}")

Step 2: Create the Scavio replacement function

Replace the CSE GET request with a Scavio POST request. The response structure maps cleanly: items becomes organic_results, and each result has title, link, and snippet fields.

Python
import os, requests

SCAVIO_KEY = os.environ['SCAVIO_API_KEY']

def scavio_search(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()
    results = resp.json().get('organic_results', [])
    return [{'title': r['title'], 'link': r['link'],
             'snippet': r.get('snippet', '')} for r in results]

results = scavio_search('best python frameworks 2026')
for r in results:
    print(f"{r['title']} -> {r['link']}")

Step 3: Map CSE-specific parameters

If you use CSE features like site restriction, date range, or language filtering, map them to Scavio query parameters or query syntax.

Python
# CSE site restriction -> Scavio query syntax
# Old: params={'siteSearch': 'reddit.com', 'q': query}
# New: prepend site: to query
def search_site(query: str, site: str) -> list:
    return scavio_search(f'site:{site} {query}')

# CSE country -> Scavio country_code
def search_country(query: str, country: str = 'us') -> 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': country, 'num_results': 10})
    return resp.json().get('organic_results', [])

# CSE date restrict -> Scavio query syntax
def search_recent(query: str) -> list:
    return scavio_search(f'{query} after:2026-01-01')

print('Site search:', len(search_site('python tutorial', 'docs.python.org')))
print('Country search:', len(search_country('AI news', 'gb')))
print('Recent search:', len(search_recent('AI frameworks')))

Step 4: Build a compatibility wrapper for zero-downtime swap

Create a wrapper that matches the exact CSE response format so downstream code needs no changes. This lets you swap the backend without touching consumers.

Python
def cse_compatible_search(query: str, **kwargs) -> dict:
    """Drop-in replacement that returns CSE-format response."""
    num = kwargs.get('num', 10)
    results = scavio_search(query, num=num)
    # Return CSE-compatible response shape
    return {
        'searchInformation': {
            'totalResults': str(len(results)),
            'searchTime': 0.3
        },
        'items': [{
            'title': r['title'],
            'link': r['link'],
            'snippet': r['snippet'],
            'displayLink': r['link'].split('/')[2] if '/' in r['link'] else ''
        } for r in results]
    }

# Your existing code works unchanged
response = cse_compatible_search('best python frameworks 2026')
for item in response['items']:
    print(f"{item['title']} ({item['displayLink']})")
print(f"Total: {response['searchInformation']['totalResults']}")

Step 5: Validate results and compare quality

Run both APIs in parallel for a week to verify result quality before cutting over completely. Log any discrepancies.

Python
import json
from datetime import datetime

def compare_search(query: str) -> dict:
    scavio_results = scavio_search(query, num=5)
    scavio_urls = set(r['link'] for r in scavio_results)
    comparison = {
        'query': query,
        'timestamp': datetime.now().isoformat(),
        'scavio_count': len(scavio_results),
        'scavio_top_3': [r['title'] for r in scavio_results[:3]],
    }
    return comparison

test_queries = [
    'best python web framework 2026',
    'how to deploy fastapi production',
    'typescript vs python performance'
]

for q in test_queries:
    result = compare_search(q)
    print(f"Query: {q}")
    print(f"  Scavio: {result['scavio_count']} results")
    print(f"  Top 3: {result['scavio_top_3']}")
    print()

Python Example

Python
import os, requests

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 resp.json().get('organic_results', [])

def cse_compat(query, **kw):
    results = search(query, num=kw.get('num', 10))
    return {'items': [{'title': r['title'], 'link': r['link'],
            'snippet': r.get('snippet', '')} for r in results]}

resp = cse_compat('python frameworks 2026')
for item in resp['items']:
    print(f"{item['title']} -> {item['link']}")
print(f'Total: {len(resp["items"])} results at $0.005')

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 })
  });
  return (await resp.json()).organic_results || [];
}

async function cseCompat(query) {
  const results = await search(query);
  return { items: results.map(r => ({ title: r.title, link: r.link, snippet: r.snippet || '' })) };
}

cseCompat('python frameworks 2026').then(resp => {
  resp.items.forEach(i => console.log(`${i.title} -> ${i.link}`));
  console.log(`Total: ${resp.items.length} results at $0.005`);
});

Expected Output

JSON
best python frameworks 2026 -> https://example.com/...
Django vs FastAPI in 2026: Which Should You Choose?
  -> https://blog.example.com/django-vs-fastapi-2026
Top 10 Python Web Frameworks for Production
  -> https://example.com/top-python-frameworks
Total: 10 results at $0.005

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.

An existing Google CSE integration you need to migrate. Python 3.9+ or Node.js 18+ installed. A Scavio API key from scavio.dev. Access to your current CSE API key and search engine ID. 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

Step-by-step guide to migrating from Google Custom Search Engine to the Scavio search API before CSE shuts down web-wide search in January 2027.