> ## Documentation Index
> Fetch the complete documentation index at: https://docs.clickbase.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Search Console

> Read organic Google Search keyword stats — clicks (as visitors), impressions, CTR, average position, and estimated revenue — for a site's connected Google Search Console property.

Read organic Google Search keyword stats — clicks (as `visitors`), impressions, CTR, average position, and estimated revenue — for a site's connected Google Search Console property. A site is addressed by `{siteKey}` (UUID or domain). Requires `Authorization: Bearer {token}`. See [Conventions](/api/conventions) for the base URL, headers, date-range, and filter conventions shared by every endpoint.

There is no API endpoint to connect Search Console — that OAuth flow is web-only (the team connects a property from the dashboard). This endpoint only reads keyword stats for a property that is already connected.

### Search keywords

```http theme={null}
GET /api/sites/{siteKey}/stats/search-keywords
```

Route name: `api.sites.stats.search-keywords`.

**Path parameters**

| Parameter | Type   | Required | Description          |
| --------- | ------ | -------- | -------------------- |
| `siteKey` | string | Yes      | Site UUID or domain. |

**Query parameters**

| Parameter | Type   | Required | Description                                                                                         |
| --------- | ------ | -------- | --------------------------------------------------------------------------------------------------- |
| `range`   | string | No       | Preset date range (see [Date ranges](/api/conventions#date-ranges)). Default `today`.               |
| `from`    | string | No       | Custom range start, `Y-m-d`. Requires `to`.                                                         |
| `to`      | string | No       | Custom range end, `Y-m-d`. Requires `from`.                                                         |
| `limit`   | int    | No       | Rows per Search Console fetch, 1–500. Default 10.                                                   |
| `page`    | int    | No       | Zero-based page offset into the Search Console result set, 0–100. Default 0.                        |
| `search`  | string | No       | Case-insensitive substring match against the keyword label, applied after the fetch. Max 255 chars. |

Plus the shared dashboard filters as query parameters — see [Filters](/api/conventions#filters).

**Response** — a flat object:

| Field   | Type   | Description                                                                      |
| ------- | ------ | -------------------------------------------------------------------------------- |
| `rows`  | array  | Keyword rows (see below). Empty when the site has no data or is not connected.   |
| `error` | string | Present only when `rows` is empty for a reason other than "no data" — see below. |

Each row in `rows`:

| Field         | Type   | Description                                                                                                                      |
| ------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------- |
| `label`       | string | The search query/keyword.                                                                                                        |
| `visitors`    | int    | Clicks from this keyword (Search Console's `clicks` metric).                                                                     |
| `impressions` | int    | Impressions.                                                                                                                     |
| `ctr`         | float  | Click-through rate, as a percentage (e.g. `4.2` for 4.2%).                                                                       |
| `position`    | float  | Average result position.                                                                                                         |
| `revenue`     | int    | Estimated revenue attributed to the keyword, in minor units (cents), derived from the site's organic-Google revenue per visitor. |

Status: `200 OK` — **always**, even when Search Console is not connected. This endpoint never returns a `500` for a disconnected or misconfigured property; it returns the clean shape below instead.

| `error` value                 | Meaning                                                                                                                       |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `not_connected`               | The site has no Google Search Console connection.                                                                             |
| `property_not_configured`     | The connection exists but no property has been selected.                                                                      |
| `period_too_recent`           | Search Console returned no rows and the range starts within the last 72 hours (GSC data lags).                                |
| *(client/auth error message)* | The Search Console API call failed (token refresh or transport error) — the raw error message is surfaced, `rows` stays `[]`. |

**Rate limit** — this endpoint has its **own throttle bucket**, `throttle:60,1,search-keywords` (60 requests/minute, isolated from the general `60,1` bucket shared by the rest of the authenticated API), so Search Console reads and Google's own API quota can't be starved by other API traffic.

<CodeGroup>
  ```bash title="curl" theme={null}
  curl "https://clickbase.so/api/sites/example.com/stats/search-keywords?range=last_30_days&limit=25" \
    -H "Authorization: Bearer {token}" \
    -H "Accept: application/json"
  ```

  ```javascript title="JavaScript" theme={null}
  const params = new URLSearchParams({ range: 'last_30_days', limit: '25' });
  await fetch(`https://clickbase.so/api/sites/example.com/stats/search-keywords?${params}`, { headers: { Authorization: `Bearer ${token}`, Accept: 'application/json' } })
  ```

  ```python title="Python" theme={null}
  requests.get(
      'https://clickbase.so/api/sites/example.com/stats/search-keywords',
      params={'range': 'last_30_days', 'limit': 25},
      headers={'Authorization': f'Bearer {token}', 'Accept': 'application/json'},
  )
  ```
</CodeGroup>

```json theme={null}
{
    "rows": [
        {
            "label": "web analytics tool",
            "visitors": 142,
            "impressions": 3210,
            "ctr": 4.4,
            "position": 8.2,
            "revenue": 4200
        }
    ]
}
```

Not-connected response:

```json theme={null}
{
    "rows": [],
    "error": "not_connected"
}
```
