AlterLabAlterLab
PricingComparePlaygroundBlogDocsChangelog
    AlterLabAlterLab
    PricingComparePlaygroundBlogDocsChangelog
    IntroductionQuickstartInstallationYour First Request
    REST APICrawl APIMap APISearch APISERP APINewExtract APIAIJob PollingAPI KeysSessions APINewEnterprise APIEnterprise
    AccountAutoAlertsAutoAuthAutoBillingAutoCrawlAutoExtractAutoIntegrationsAutoKeysAutoMapAutoMonitorsAutoOrganizationsAutoSchedulesAutoScrapeAutoSearchAutoSessionsAutoUser WebhooksAutoV1 EndpointsAutoWebhooksAuto
    OverviewPythonNode.js
    JavaScript RenderingOutput FormatsPDF & OCRCachingWebhooksJSON Schema FilteringWebSocket Real-TimeBring Your Own ProxyProSticky SessionsProAuthenticated ScrapingNewHTTP Methods & BodiesNewStructured ExtractionAIWeb SearchSite MappingWeb CrawlingBatch ScrapingSchedulerChange DetectionCloud Storage ExportSpend LimitsOrganizations & TeamsAlerts & NotificationsExtraction ProfilesAIBYOK ExtractionAIOAuth2 Machine-to-MachineSupport & TicketsUnsupported Targets
    Structured ExtractionAIE-commerce ScrapingNews MonitoringPrice MonitoringMulti-Page CrawlingMonitoring DashboardAI Agent / MCPMCPAI Research AgentAISite CrawlingData Pipeline to Cloud
    E-commerceLead GenerationChange MonitoringRAG & AI PipelinesAIResearch
    PricingRate LimitsError CodesChangelogVersioning
    From FirecrawlFrom ApifyFrom ScrapingBee / ScraperAPIFrom Crawl4AIFrom SpiderFirecrawl v0 API ReferenceLegacy
    OverviewMCP ServerAIn8n NodeLangChainAICrewAIAILlamaIndexAISupabaseChrome ExtensionSoon
    PlaygroundPricingStatus

    5,000 free requests · No credit card

    API Reference
    New

    SERP API

    Scrape Google and Bing search engine results pages with full ad extraction, organic results, rich snippets, and structured data. Browser-rendered for complete ad visibility.

    Ad Intelligence Endpoint

    The SERP API uses browser-tier rendering (Tier 4) to capture ads that are invisible to traditional HTTP-based scrapers. Unlike the /v1/search endpoint (lightweight keyword search at $0.001/query), this endpoint renders the full SERP page to extract paid ads, shopping results, and rich SERP features.

    Overview

    1

    Query

    POST a search query to /api/v1/serp. Specify engine, geo, device, and ad extraction options.

    2

    Render

    A real browser loads the SERP page with stealth fingerprinting, ensuring ads render exactly as they would for a human user.

    3

    Extract

    Structured data is extracted: organic results, paid ads (with placement, advertiser, extensions), featured snippets, knowledge panels, and more.

    Feature/v1/search/api/v1/serp
    Organic resultsYesYes
    Paid ad extractionNoYes
    Shopping adsNoYes
    Brand classificationNoYes
    Session persistenceNoYes
    CAPTCHA solvingNoYes
    Rich results (PAA, KP)LimitedFull
    Cost per query$0.001$0.004

    Quick Start

    Get your first SERP result in seconds. This example queries Google for "crm software" with ad extraction enabled.

    Bash
    curl -X POST https://api.alterlab.io/api/v1/serp \
      -H "X-API-Key: YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "query": "crm software",
        "include_ads": true,
        "country": "US"
      }'

    POST /api/v1/serp

    POST
    /api/v1/serp

    Execute a SERP scrape with browser rendering. Returns organic results, paid ads, and rich result data. Supports inline wait (up to 30s) or async polling.

    Parameters

    NameTypeRequiredDescription
    querystring
    Required
    Search query (1-500 characters). The search term to look up on the target engine.
    search_engine"google" | "bing"OptionalTarget search engine. Google is the primary target for ad extraction.Default: google
    device"desktop" | "mobile"OptionalDevice type to emulate. Affects SERP layout and ad placements. Desktop typically shows more ads.Default: desktop
    countrystringOptionalISO 3166-1 alpha-2 country code for geo-targeted results (e.g. "US", "GB", "DE"). Routes through a proxy in the specified country.
    citystringOptionalCity name for local ad targeting (e.g. "London", "New York"). Used with country for precise geo-targeting.
    languagestringOptionalLanguage code for results and browser locale (e.g. "en", "de", "fr").
    num_resultsintegerOptionalNumber of organic results to request (1-100). Google typically serves 10 per page.Default: 10
    pageintegerOptionalResult page number (1-10). Page 2 = results 11-20.Default: 1
    include_adsbooleanOptionalExtract ad data from the SERP. When false, only organic results are returned (faster). The primary use case for this endpoint.Default: true
    brand_domainstringOptionalBrand domain for ad classification (e.g. "wayfair.com"). Each ad gets is_brand_ad: true/false based on whether its display domain matches.
    resolve_redirectsbooleanOptionalFollow ad click-through redirect chains to resolve final landing URLs. Adds ~200-500ms per ad.Default: false
    session_idstringOptionalReuse a long-lived browser session for sticky IP and fingerprint continuity across queries.
    solve_captchasbooleanOptionalAutomatically solve CAPTCHAs when Google presents a challenge. Adds latency but avoids errors.Default: true

    Response Schema

    The response contains structured data extracted from the rendered SERP page. All fields are populated based on what the search engine returns.

    JSON
    {
      "serp_id": "serp_abc123def456",
      "query": "crm software",
      "search_engine": "google",
      "device": "desktop",
      "country": "US",
      "language": "en",
      "session_id": null,
      "organic_results": [
        {
          "position": 1,
          "url": "https://www.salesforce.com/crm/",
          "title": "CRM Software from Salesforce - Customer Relationship Management",
          "snippet": "Salesforce CRM helps businesses of all sizes manage customer relationships...",
          "displayed_url": "salesforce.com/crm",
          "date_published": null,
          "sitelinks": [
            { "title": "Pricing", "url": "https://www.salesforce.com/crm/pricing/" },
            { "title": "Free Trial", "url": "https://www.salesforce.com/form/signup/" }
          ]
        }
      ],
      "organic_count": 10,
      "ads": [
        {
          "position": 1,
          "placement": "top",
          "ad_type": "text",
          "headline": "HubSpot CRM - Free CRM Software",
          "headline_2": "Start Growing Better Today",
          "headline_3": null,
          "description": "Get started with free CRM tools for your whole team. No credit card required.",
          "description_2": null,
          "display_url": "hubspot.com/crm/free",
          "landing_url": null,
          "tracking_url": "https://www.google.com/aclk?sa=l&ai=...",
          "advertiser_name": "HubSpot",
          "extensions": [
            { "type": "sitelink", "text": "Free Tools", "url": "https://hubspot.com/free" },
            { "type": "callout", "text": "No Credit Card Required", "url": null }
          ],
          "is_brand_ad": false,
          "is_sponsored": true,
          "price": null,
          "merchant": null,
          "image_url": null,
          "rating": null,
          "review_count": null
        }
      ],
      "ads_count": 4,
      "ads_by_placement": { "top": 3, "bottom": 1, "sidebar": 0, "shopping": 0 },
      "featured_snippet": {
        "content": "CRM software helps businesses manage customer interactions and data...",
        "source_url": "https://example.com/what-is-crm",
        "source_title": "What is CRM? - Complete Guide",
        "snippet_type": "text"
      },
      "knowledge_panel": null,
      "people_also_ask": [
        {
          "question": "What is the best CRM software for small businesses?",
          "answer": "Popular CRM options for small businesses include HubSpot CRM (free tier)...",
          "source_url": "https://example.com/best-crm"
        }
      ],
      "related_searches": [
        "best crm software 2026",
        "free crm software",
        "crm software for small business"
      ],
      "did_you_mean": null,
      "local_results": [],
      "video_results": [],
      "news_results": [],
      "image_results": [],
      "shopping_results": [],
      "estimated_total_results": 2340000000,
      "cost_breakdown": {
        "base_cost_microcents": 4000,
        "ad_extraction_cost_microcents": 0,
        "captcha_solve_cost_microcents": 0,
        "total_cost_microcents": 4000,
        "tier_used": "4"
      },
      "captcha_stats": null
    }

    Ad Result Schema

    Each ad in the ads array contains the full ad creative with positioning, text, URLs, and extensions.

    FieldTypeDescription
    positionintegerAd position within its placement group (1-indexed)
    placement"top" | "bottom" | "sidebar" | "shopping"Where the ad appears on the SERP page
    ad_type"text" | "shopping" | "local" | "video" | "app"Ad format type
    headlinestringPrimary ad headline text
    headline_2, headline_3string | nullAdditional headlines if present
    descriptionstring | nullAd description / body text
    display_urlstringURL displayed in the ad (breadcrumb-style)
    landing_urlstring | nullFinal landing URL after redirect resolution (requires resolve_redirects: true)
    tracking_urlstring | nullRaw click-through URL from Google's tracking redirect
    advertiser_namestring | nullVerified advertiser name shown by Google
    extensionsarraySitelinks, callouts, phone numbers, and other extensions
    is_brand_adboolean | nullWhether the ad's display domain matches the brand_domain. Null when brand_domain not provided.
    pricestring | nullProduct price — shopping ads only
    merchantstring | nullMerchant name — shopping ads only

    Organic Result Schema

    FieldTypeDescription
    positioninteger1-indexed position on the page
    urlstringResult URL
    titlestringResult title
    snippetstring | nullResult snippet/description
    displayed_urlstring | nullURL as displayed in SERP (breadcrumb-style)
    date_publishedstring | nullDate shown next to the result
    sitelinksarraySitelinks under this result (title + url)

    Rich Results

    The response includes all rich SERP features when present on the page.

    FieldTypeDescription
    featured_snippetobject | nullFeatured snippet / answer box (content, source_url, snippet_type)
    knowledge_panelobject | nullKnowledge panel (title, entity_type, description, facts)
    people_also_askarrayPAA questions (question, answer, source_url)
    related_searchesarray of stringsRelated search suggestions
    local_resultsarrayLocal pack results (name, address, rating, phone)
    video_resultsarrayVideo carousel (title, url, source, duration)
    news_resultsarrayNews carousel (title, url, source, date)
    shopping_resultsarrayOrganic shopping carousel (title, price, merchant)

    Cost Breakdown

    Every response includes a cost_breakdown object showing exactly what was charged.

    FieldTypeDescription
    base_cost_microcentsintegerBase cost including browser rendering (4000 = $0.004)
    ad_extraction_cost_microcentsintegerAdditional cost for redirect resolution
    captcha_solve_cost_microcentsintegerCAPTCHA solving cost (non-zero when a challenge was solved)
    total_cost_microcentsintegerTotal cost for this request
    tier_usedstringScraping tier used (always "4" for SERP)

    Async Polling

    If the SERP scrape takes longer than 30 seconds (e.g., due to CAPTCHA solving), the response includes a serp_id with status "processing". Poll for results using the status endpoint.

    GET
    /api/v1/serp/{serp_id}

    Poll for async SERP results. Returns the full SerpResponse when status is 'completed'.

    Parameters

    NameTypeRequiredDescription
    serp_idstring
    Required
    The serp_id from the initial POST /api/v1/serp response.
    Python
    import time
    import requests
    
    # Initial request
    resp = requests.post(
        "https://api.alterlab.io/api/v1/serp",
        headers={"X-API-Key": "YOUR_API_KEY"},
        json={"query": "insurance quotes", "solve_captchas": True},
    )
    data = resp.json()
    
    # If processing, poll for results
    if data.get("status") == "processing":
        serp_id = data["serp_id"]
        while True:
            time.sleep(2)
            status = requests.get(
                f"https://api.alterlab.io/api/v1/serp/{serp_id}",
                headers={"X-API-Key": "YOUR_API_KEY"},
            ).json()
            if status["status"] == "completed":
                data = status["result"]
                break
            elif status["status"] == "failed":
                raise Exception(f"SERP scrape failed: {status.get('error')}")

    Batch SERP

    Submit up to 50 SERP queries for parallel processing. Ideal for monitoring multiple keywords or comparing results across markets.

    Batch Request

    POST
    /api/v1/serp/batch

    Submit a batch of SERP queries for async parallel processing. Each query can override batch-level defaults.

    Parameters

    NameTypeRequiredDescription
    queriesarray
    Required
    Array of query objects (1-50 items). Each item has: query (required), device, country, city, language, include_ads, brand_domain.
    search_engine"google" | "bing"OptionalDefault search engine for all queries.Default: google
    device"desktop" | "mobile"OptionalDefault device type for all queries.Default: desktop
    countrystringOptionalDefault country for all queries.
    include_adsbooleanOptionalDefault ad extraction setting.Default: true
    brand_domainstringOptionalDefault brand domain for classification.
    session_idstringOptionalReuse a session for all queries in this batch.
    webhook_urlstringOptionalWebhook URL for result delivery. Results are POSTed as each query completes.
    Python
    import requests
    
    resp = requests.post(
        "https://api.alterlab.io/api/v1/serp/batch",
        headers={"X-API-Key": "YOUR_API_KEY"},
        json={
            "queries": [
                {"query": "crm software", "country": "US"},
                {"query": "crm software", "country": "GB"},
                {"query": "crm software", "country": "DE"},
            ],
            "include_ads": True,
            "brand_domain": "salesforce.com",
        },
    )
    
    batch = resp.json()
    print(f"Batch ID: {batch['batch_id']}")
    cost = batch['estimated_cost_microcents'] / 1_000_000
    print(f"Estimated cost: {cost:.4f}")

    Poll Batch Status

    GET
    /api/v1/serp/batch/{batch_id}

    Poll for batch progress and results. Returns per-query status and results as they complete.

    Parameters

    NameTypeRequiredDescription
    batch_idstring
    Required
    Batch ID from the POST /api/v1/serp/batch response.
    JSON
    {
      "batch_id": "batch_xyz789",
      "status": "completed",
      "total_queries": 3,
      "completed": 3,
      "failed": 0,
      "total_cost_microcents": 12000,
      "items": [
        {
          "index": 0,
          "query": "crm software",
          "status": "completed",
          "result": { "...full SerpResponse..." },
          "error": null
        }
      ]
    }

    Configuration Guide

    Engine Selection

    The SERP API supports Google and Bing. Google is the primary target with full ad extraction support.

    EngineAd ExtractionShopping AdsRich ResultsGeo-Targeting
    GoogleFull (top, bottom, sidebar)YesFull (PAA, KP, snippets, local, video, news)Country + city
    BingTop + sidebarLimitedBasic (snippets, PAA)Country only

    Geo-Targeting

    Control where your search originates from using country and city parameters. The request is routed through a proxy in the specified location.

    Python
    # Compare ads across markets
    markets = [
        {"country": "US", "language": "en"},
        {"country": "GB", "language": "en"},
        {"country": "DE", "language": "de"},
        {"country": "FR", "language": "fr"},
    ]
    
    for market in markets:
        resp = requests.post(
            "https://api.alterlab.io/api/v1/serp",
            headers={"X-API-Key": "YOUR_API_KEY"},
            json={"query": "project management software", **market, "include_ads": True},
        )
        data = resp.json()
        print(f"{market['country']}: {data['ads_count']} ads found")

    City requires Country

    The city parameter only works when country is also provided. Without a country, city targeting is ignored.

    Ad Extraction

    When include_ads: true (default), the SERP API extracts all paid ad placements. Use brand_domain to automatically classify ads as brand vs. competitor.

    Python
    # Monitor who's bidding on your brand keywords
    resp = requests.post(
        "https://api.alterlab.io/api/v1/serp",
        headers={"X-API-Key": "YOUR_API_KEY"},
        json={
            "query": "salesforce crm",
            "brand_domain": "salesforce.com",
            "include_ads": True,
            "resolve_redirects": True,  # Get actual landing URLs
        },
    )
    
    data = resp.json()
    
    brand_ads = [ad for ad in data["ads"] if ad["is_brand_ad"] is True]
    competitor_ads = [ad for ad in data["ads"] if ad["is_brand_ad"] is False]
    
    print(f"Brand ads: {len(brand_ads)}")
    print(f"Competitor ads: {len(competitor_ads)}")
    for ad in competitor_ads:
        print(f"  - {ad['advertiser_name'] or ad['display_url']}: {ad['headline']}")

    Ad Placement Types

    • top — Above organic results (highest visibility, highest CPC)
    • bottom — Below organic results
    • sidebar — Right-side panel (desktop only)
    • shopping — Shopping carousel (product listings with images/prices)

    Session Management

    Use session_id to maintain a persistent browser session across multiple queries. The same IP, cookies, and browser fingerprint are reused — essential for pagination and consistent results.

    Python
    # Paginate through results on the same session
    session_id = "my-research-session-001"
    
    all_results = []
    for page in range(1, 4):  # Pages 1-3
        resp = requests.post(
            "https://api.alterlab.io/api/v1/serp",
            headers={"X-API-Key": "YOUR_API_KEY"},
            json={
                "query": "best project management tools",
                "session_id": session_id,
                "page": page,
                "include_ads": True,
            },
        )
        data = resp.json()
        all_results.extend(data["organic_results"])
        print(f"Page {page}: {len(data['organic_results'])} results, {data['ads_count']} ads")
    
    print(f"Total organic results collected: {len(all_results)}")

    Session Lifespan

    Sessions persist as long as they are actively used. A session expires after 10 minutes of inactivity. Reusing an expired session_id transparently creates a new session.

    CAPTCHA Handling

    Google may present reCAPTCHA challenges for automated queries. With solve_captchas: true (default), challenges are solved transparently. The response includes captcha_stats when a solve occurred.

    JSON
    {
      "captcha_stats": {
        "captcha_encountered": true,
        "captcha_solved": true,
        "solve_time_ms": 4200,
        "solver_provider": "capsolver"
      }
    }

    Use Cases

    Basic SERP Scraping

    Get organic results for a keyword with full metadata.

    Python
    resp = requests.post(
        "https://api.alterlab.io/api/v1/serp",
        headers={"X-API-Key": "YOUR_API_KEY"},
        json={"query": "best laptops 2026", "include_ads": False},
    )
    
    for result in resp.json()["organic_results"]:
        print(f"{result['position']}. {result['title']}")
        print(f"   {result['url']}")
        print(f"   {result['snippet']}")
        print()

    Ad Intelligence

    Extract all advertisers bidding on a keyword with placement data.

    Python
    resp = requests.post(
        "https://api.alterlab.io/api/v1/serp",
        headers={"X-API-Key": "YOUR_API_KEY"},
        json={
            "query": "project management software",
            "include_ads": True,
            "resolve_redirects": True,
        },
    )
    
    data = resp.json()
    print(f"Ads by placement: {data['ads_by_placement']}")
    for ad in data["ads"]:
        print(f"[{ad['placement']}#{ad['position']}] {ad['headline']}")
        print(f"  Advertiser: {ad['advertiser_name']}")
        print(f"  Display: {ad['display_url']}")
        print(f"  Landing: {ad['landing_url']}")
        print(f"  Extensions: {len(ad['extensions'])}")
        print()

    Brand vs. Competitor Monitoring

    Detect who is advertising on your brand keywords and classify brand vs. competitor placements.

    Python
    keywords = ["wayfair furniture", "wayfair couches", "wayfair sale"]
    competitor_data = []
    
    for kw in keywords:
        resp = requests.post(
            "https://api.alterlab.io/api/v1/serp",
            headers={"X-API-Key": "YOUR_API_KEY"},
            json={
                "query": kw,
                "brand_domain": "wayfair.com",
                "include_ads": True,
            },
        )
        data = resp.json()
        competitors = [ad for ad in data["ads"] if ad["is_brand_ad"] is False]
        competitor_data.append({"keyword": kw, "competitors": competitors})
    
    # Report on competitor activity
    for item in competitor_data:
        print(f"\nKeyword: {item['keyword']}")
        for ad in item["competitors"]:
            print(f"  Competitor: {ad['display_url']} - {ad['headline']}")

    Geo-Targeted Comparison

    Compare SERP results and ad landscape across different markets.

    Python
    import requests
    
    markets = ["US", "GB", "DE", "JP", "BR"]
    query = "cloud computing services"
    
    for country in markets:
        resp = requests.post(
            "https://api.alterlab.io/api/v1/serp",
            headers={"X-API-Key": "YOUR_API_KEY"},
            json={"query": query, "country": country, "include_ads": True},
        )
        data = resp.json()
        top_organic = data["organic_results"][0]["title"] if data["organic_results"] else "N/A"
        print(f"{country}: {data['organic_count']} organic, {data['ads_count']} ads")
        print(f"  Top result: {top_organic}")
        print(f"  Ads breakdown: {data['ads_by_placement']}")

    Pricing

    ComponentCostNotes
    Base SERP scrape$0.004 / queryIncludes browser rendering (Tier 4), ad extraction, all SERP features
    CAPTCHA solvingBundledIncluded in base cost when solve_captchas is enabled
    Redirect resolutionBundledIncluded when resolve_redirects is enabled
    Batch (up to 50 queries)$0.004 x NSame per-query pricing, parallel execution

    Cost Transparency

    Every response includes a cost_breakdown object showing the exact cost charged. Monitor your spend in real-time via the total_cost_microcents field (1,000,000 microcents = $1).

    Example cost calculations

    • 1,000 SERP queries/day = $4.00/day = $120/month
    • 10,000 SERP queries/day = $40.00/day = $1,200/month
    • 100,000 SERP queries/day = $400.00/day = $12,000/month

    Error Codes

    CodeMeaningResolution
    400Invalid request parametersCheck query length, country code format, parameter types
    401Invalid or missing API keyVerify X-API-Key header is present and valid
    402Insufficient balanceAdd funds to your account. Each SERP query costs $0.004.
    422Validation errorCheck the error detail — often an unsupported country code or invalid query
    429Rate limitedBack off and retry. Use batch endpoint for high-volume queries.
    500Internal errorRetry after a few seconds. If persistent, check status page.
    503SERP scrape failed (blocked/timeout)The target search engine blocked the request. Retry — a different proxy/fingerprint will be used.
    Last updated: June 2026

    On this page