AlterLabAlterLab
PricingComparePlaygroundBlogDocsChangelog
    AlterLabAlterLab
    PricingComparePlaygroundBlogDocsChangelog
    IntroductionQuickstartInstallationYour First Request
    REST APIJob PollingAPI KeysSessions APINew
    OverviewPythonNode.js
    JavaScript RenderingOutput FormatsPDF & OCRCachingWebhooksJSON Schema FilteringWebSocket Real-TimeBring Your Own ProxyProAuthenticated ScrapingNewWeb CrawlingBatch ScrapingSchedulerChange DetectionCloud Storage ExportSpend LimitsOrganizations & TeamsAlerts & Notifications
    Structured ExtractionAIE-commerce ScrapingNews MonitoringPrice MonitoringMulti-Page CrawlingMonitoring DashboardAI Agent / MCPMCPData Pipeline to Cloud
    PricingRate LimitsError Codes
    From FirecrawlFrom ApifyFrom ScrapingBee / ScraperAPI
    PlaygroundPricingStatus
    API Reference
    New

    Search API

    Find relevant web pages by keyword before scraping. Search returns URLs, titles, and snippets — optionally scraping each result inline.

    Discovery-First Workflow

    Search is designed for cases where you know what you want but not where it lives. Find pages first, then scrape and extract in a single pipeline.

    Overview

    1

    Search

    POST a query to /api/v1/search. Get back URLs, titles, and snippets from Google.

    2

    Scrape (Optional)

    Set scrape_results: true to scrape every result page and get full content back.

    3

    Extract (Optional)

    Pass an extraction_schema to pull structured data from every result in one call.

    POST /v1/search

    POST
    /api/v1/search

    Execute a web search. Returns results synchronously (200) or, when scrape_results is true and there are more than 5 results, returns 202 with a search_id for polling.

    Bash
    curl -X POST https://api.alterlab.io/api/v1/search \
      -H "X-API-Key: your_api_key" \
      -H "Content-Type: application/json" \
      -d '{
        "query": "best headless browsers 2026",
        "num_results": 10
      }'

    Request Body

    ParameterTypeRequiredDescription
    querystringYesSearch terms (1-500 characters)
    domainstringNoRestrict results to a specific domain (applied as site: prefix)
    num_resultsintegerNoNumber of results to return (1-50, default: 10)
    countrystringNoISO 3166-1 alpha-2 country code for geo-targeted results (e.g., US, GB, DE)
    languagestringNoLanguage code for results (e.g., en, fr, de)
    time_rangestringNoFilter by recency: hour, day, week, month, year
    scrape_resultsbooleanNoIf true, scrape each result page and include full content (default: false)
    formatsstring[]NoOutput formats when scrape_results=true: text, json, json_v2, html, markdown
    extraction_schemaobjectNoJSON schema for structured extraction (when scrape_results=true)

    Search-Only Response (200)

    When scrape_results is false (default), results are returned synchronously:

    JSON
    {
      "search_id": "a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
      "query": "best headless browsers 2026",
      "results_count": 10,
      "credits_used": 2000,
      "results": [
        {
          "url": "https://example.com/headless-browsers-guide",
          "title": "Top 10 Headless Browsers in 2026",
          "snippet": "A comprehensive comparison of the best headless browsers for web scraping and automation...",
          "position": 1,
          "content": null
        },
        {
          "url": "https://blog.example.com/playwright-vs-puppeteer",
          "title": "Playwright vs Puppeteer in 2026",
          "snippet": "Which headless browser framework should you choose? We compare performance, features...",
          "position": 2,
          "content": null
        }
      ]
    }

    Search + Scrape Response (202)

    When scrape_results=true and there are more than 5 results, the response is 202 with a polling URL:

    JSON
    {
      "search_id": "a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
      "query": "best headless browsers 2026",
      "status": "scraping",
      "results_count": 10,
      "credits_used": 52000,
      "results": [ ... ],
      "message": "Search complete. 10 results are being scraped. Poll GET /v1/search/a1b2c3d4-... for progress."
    }

    Inline Scraping

    When scrape_results=true and there are 5 or fewer results, the API waits briefly and attempts to return content inline. For larger result sets, use the polling endpoint.

    GET /v1/search/{search_id}

    GET
    /api/v1/search/{search_id}

    Poll for search + scrape progress. Returns the search results with scraped content populated as each job completes.

    Bash
    curl https://api.alterlab.io/api/v1/search/a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d \
      -H "X-API-Key: your_api_key"

    Status Response

    JSON
    {
      "search_id": "a1b2c3d4-...",
      "query": "best headless browsers 2026",
      "status": "completed",
      "results_count": 10,
      "completed": 10,
      "credits_used": 52000,
      "results": [
        {
          "url": "https://example.com/headless-browsers-guide",
          "title": "Top 10 Headless Browsers in 2026",
          "snippet": "A comprehensive comparison...",
          "position": 1,
          "content": {
            "text": "Full article text here...",
            "markdown": "# Top 10 Headless Browsers..."
          }
        }
      ]
    }
    StatusMeaning
    scrapingSome result pages are still being scraped
    completedAll result pages have been scraped

    24-Hour TTL

    Search metadata expires after 24 hours. Poll for results before then.

    Credit Model

    ActionCostNotes
    Search query2 creditsFlat fee per search, regardless of num_results
    Scrape per result1-5 creditsStandard scrape pricing per URL (tier-based)
    ExtractionIncludedNo extra charge when using extraction_schema with scrape_results

    BYOP Discount

    If you have a Bring Your Own Proxy integration, scrape credits are discounted per your plan. The search query cost (2 credits) is not affected.

    Error Codes

    StatusErrorDescription
    402insufficient_creditsNot enough credits for the search or scrape
    404search_not_foundSearch ID not found or expired (polling endpoint)
    502search_provider_errorUpstream search provider returned an error
    503search_unavailableSearch service is not configured
    504search_timeoutSearch provider timed out

    Examples

    Basic Search

    Python
    import requests
    
    response = requests.post(
        "https://api.alterlab.io/api/v1/search",
        headers={"X-API-Key": "YOUR_API_KEY"},
        json={
            "query": "web scraping best practices",
            "num_results": 5
        }
    )
    
    data = response.json()
    for result in data["results"]:
        print(f"{result['position']}. {result['title']}")
        print(f"   {result['url']}")

    Domain-Scoped Search

    Python
    # Search within a specific domain
    response = requests.post(
        "https://api.alterlab.io/api/v1/search",
        headers={"X-API-Key": "YOUR_API_KEY"},
        json={
            "query": "authentication API",
            "domain": "docs.github.com",
            "num_results": 10
        }
    )
    
    # All results will be from docs.github.com
    data = response.json()
    print(f"Found {data['results_count']} pages on docs.github.com")

    Search + Scrape with Extraction

    Python
    import time
    
    # Search and scrape with structured extraction
    response = requests.post(
        "https://api.alterlab.io/api/v1/search",
        headers={"X-API-Key": "YOUR_API_KEY"},
        json={
            "query": "iPhone 16 Pro review",
            "num_results": 5,
            "scrape_results": True,
            "formats": ["text", "markdown"],
            "extraction_schema": {
                "type": "object",
                "properties": {
                    "rating": {"type": "number", "description": "Review rating out of 10"},
                    "pros": {"type": "array", "items": {"type": "string"}},
                    "cons": {"type": "array", "items": {"type": "string"}},
                    "verdict": {"type": "string", "description": "One-line summary"}
                }
            }
        }
    )
    
    data = response.json()
    
    # If 202, poll for results
    if response.status_code == 202:
        search_id = data["search_id"]
        while True:
            status = requests.get(
                f"https://api.alterlab.io/api/v1/search/{search_id}",
                headers={"X-API-Key": "YOUR_API_KEY"}
            ).json()
            if status["status"] == "completed":
                data = status
                break
            time.sleep(2)
    
    # Process extracted data
    for result in data["results"]:
        if result.get("content") and result["content"].get("extraction"):
            ext = result["content"]["extraction"]
            print(f"{result['title']}: {ext.get('rating')}/10")
            print(f"  Verdict: {ext.get('verdict')}")
    ← Previous: REST APINext: Search Guide →
    Last updated: March 2026

    On this page