# Google Search

`GET https://api.serpwiz.com/v1/google/search`

Returns one page of live Google web results — organic results, ads, top stories, the knowledge panel, People Also Ask and related searches — as JSON. **Costs 1 query** when successful; failed requests are free.

```bash
curl "https://api.serpwiz.com/v1/google/search?q=best+crm+for+startups&gl=us&hl=en" \
  -H "X-API-Key: $SERPWIZ_API_KEY"
```

## Parameters

| Parameter | Required | Description |
|---|---|---|
| `q` | **yes** | Search terms, up to 2,048 characters, at least one letter. Alias: `query`. Supports Google operators such as `site:`, `"exact phrase"`, `-exclude`. |
| `gl` | no | Country to search from, as a 2-letter code: `us`, `ca`, `gb`, `de`… Sets which country's results you get. |
| `hl` | no | Interface language: `en`, `es`, `fr`, `de`… Affects result snippets and labels. |
| `page` | no | Results page, starting at `1` (default). 10 results per page; max `100`. |
| `lr` | no | Only return pages in a language: `lang_en`, `lang_fr`… |
| `cr` | no | Only return pages from a country: `countryUS`, `countryCA`… (case-sensitive) |
| `tbs` | no | Time and verbatim filters — see below. |

### Time filters (`tbs`)

| Value | Meaning |
|---|---|
| `qdr:h` | Past hour |
| `qdr:d` | Past 24 hours |
| `qdr:w` | Past week |
| `qdr:m` | Past month |
| `qdr:y` | Past year |
| `cdr:1,cd_min:1/1/2026,cd_max:10/1/2026` | Custom date range (M/D/YYYY) |
| `li:1` | Verbatim — match your exact words |

Remember to URL-encode: `tbs=cdr%3A1%2Ccd_min%3A1%2F1%2F2026%2Ccd_max%3A10%2F1%2F2026`.

## Response

```json
{
  "search_term": "best crm for startups",
  "results": [
    {
      "position": 1,
      "url": "https://www.reddit.com/r/CRM/comments/…",
      "title": "What's the best CRM for an early stage, bootstrapped startup",
      "description": "Sep 9, 2025 · …",
      "date": "Sep 9, 2025"
    },
    {
      "position": 2,
      "url": "https://www.salesforce.com/crm/startup-crm/",
      "title": "Best CRM For Startups: The All-In-One Guide - Salesforce",
      "description": "Find out how the right CRM for startups can help boost revenue…"
    }
  ],
  "ads": [],
  "top_stories": [],
  "knowledge_panel": {
    "name": "", "label": "",
    "description": { "text": "", "url": "", "site": "" },
    "image": { "url": "", "width": "", "height": "", "page_url": "" },
    "info": []
  },
  "related_keywords": {
    "spelling_suggestion": null,
    "keywords": [
      { "position": 1, "keyword": "Best crm for startups free" },
      { "position": 2, "keyword": "Best crm for startups reddit" }
    ]
  },
  "next_page": 2,
  "next_start": 10
}
```

### Fields

| Field | Type | Description |
|---|---|---|
| `search_term` | string | The query as Google understood it. |
| `results[]` | array | Organic results in page order. |
| `results[].position` | integer | 1-based rank on this page. |
| `results[].title` | string | Result title. |
| `results[].url` | string | Destination URL. |
| `results[].description` | string | Snippet text. |
| `results[].date` | string | Publication date when Google shows one. Optional. |
| `ads[]` | array | Paid results, when present. |
| `top_stories[]` | array | News carousel items, when present. |
| `knowledge_panel` | object | Entity panel. Fields are empty strings when the page has no panel. |
| `related_keywords.keywords[]` | array | "Related searches" suggestions and "People Also Ask" questions (question text only). |
| `related_keywords.spelling_suggestion` | string \| null | "Did you mean" correction. |
| `next_page` | integer | Value to pass as `page` for the next page. Absent on the last page. |

Groups that Google didn't show come back empty (`[]` or empty strings). Don't rely on any field except `results` being non-empty, and ignore fields you don't recognise — we add new ones without a version bump.

## Paginating

```python
page = 1
while page and page <= 5:
    data = get("/v1/google/search", q="serp api", page=page)
    handle(data["results"])
    page = data.get("next_page")
```

Each page is a separate query and costs 1.

## Notes

- Results are live. Identical requests within about an hour may be served from a short-lived cache, which is still billed as a query.
- Location targeting is by country (`gl`). City-level targeting isn't available yet.
- See [Errors](/docs/errors) for failure handling. Validation errors return `400 invalid_request` and are free.
