---
title: "Your Search Console rows, by day"
method: GET
path: "/v1/gsc/daily"
tags: ["Search Console"]
---

# Your Search Console rows, by day

`GET /v1/gsc/daily`

## Request

- Base URL: `https://api.placementapi.com`
- URL: `https://api.placementapi.com/v1/gsc/daily`
- Auth: HTTP bearer

Your own retained Search Console rows for one selected property, aggregated by `date` × `page` (or `date` × `page` × `query` with `dimensions=page,query,date`). Rows always carry `date`, never `day`. Read-only and additive: no Google request, no pull, no write. Every row is filtered to your account and the exact property. Aggregation uses the real page × query grain only (`page` and `query` non-empty, all-device, all-country): `clicks` and `impressions` are summed, `ctr` is `sum(clicks)/sum(impressions)` (0 with no impressions) and `position` is the impression-weighted `sum(position*impressions)/sum(impressions)` (null with no impressions) — CTRs and positions are never averaged unweighted. An empty `rows` array means no retained rows for the window, never zero-filled days. Coverage is honest, not complete: Google returns only its top rows per request and the pull stops after four pages per chunk, so anonymized queries and capped rows are absent. `pulled_through` is the last day actually pulled; `last_pulled_at` is the most recent recorded pull attempt for the property, which may itself have failed, so neither claims the window is complete. These are observed search metrics; they do not show that any link or placement caused a change. Read with a customer key (`read` scope) or a dashboard session; the operator token is refused, and any Authorization header (even empty or whitespace) is answered by key authentication rather than a session. Errors and successes are private and no-store, and private URLs, queries and rows are never logged.

## Query parameters

- `property` string, required
- `from` string, date, required
- `to` string, date, required
- `page` string[]
- `dimensions` 'page,date' | 'page,query,date'
- `cursor` string

## Response `200`

OK

- object
  - `property` string
  - `from` string, date
  - `to` string, date
  - `dimensions` string[]
  - `last_pulled_at` string, date-time, nullable: RFC 3339 timestamp of the most recent recorded pull attempt for this property, or null if never. It may record a failed attempt, so it does not prove the window is complete; it is not reported as zero. The raw database timestamp text is never exposed.
  - `pulled_through` string, date, nullable: Last day actually pulled for this property, or null.
  - `count` integer: Rows in this response (not the total matching rows).
  - `rows` object[]: At most 50,000 rows. The 3,000,000-byte response cap may produce a shorter page with a continuation cursor.
    - `date` string, date, required: Google's stored day (YYYY-MM-DD), with no timezone conversion.
    - `page` string, required: Exact page URL, as stored.
    - `query` string: Present only in the page,query,date dimension.
    - `clicks` integer, required
    - `impressions` integer, required
    - `ctr` number, required: sum(clicks)/sum(impressions); 0 when there were no impressions.
    - `position` number, nullable, required: Impression-weighted average position; null when there were no impressions.
  - `next_cursor` string, nullable: Pass back as `cursor` for the next page. Null when the window is exhausted. Returned when either the row or serialized-byte bound was reached; the serialized body (envelope and cursor included) stays under the byte cap, and boundaries never skip a row. Changing source data between requests is not a fixed snapshot.
  - `note` string: Coverage and interpretation note: what the rows are not (a complete Google total) and that they show no causality.

## Other responses

- `400`: `bad_date`, `range_too_long`, `bad_cursor`, `bad_request` (including unknown dimensions or an invalid page URL), `duplicate_parameter`, or `unknown_parameter`.
- `401`: Missing, malformed or revoked Bearer credential: `{ error: "unauthorized" }`.
- `403`: `insufficient_scope` when the key lacks the `read` scope; `customer_key_required` for the operator token; `property_not_selected` when the property is missing, unselected or not visible to this connection.
- `404`: `not_connected`: no Google connection for this account, or the connection was revoked.
- `500`: `response_too_large` when a single aggregated row cannot fit the response byte cap (the row is never silently skipped).
- `503`: `server_misconfigured` when the store is not configured; `upstream_unfunded` when the measurement provider's prepaid balance is exhausted (fresh profiles, gap maps and SERPs pause; cached results and catalogue are unaffected); `upstream_unavailable` on a provider error; `payments_unavailable` when card payments are not configured.

---

[API](https://skmtc.dev/placementapi/apis/placement-api.md) · [All operations](https://skmtc.dev/placementapi/apis/placement-api/llms.txt) · [OpenAPI document](https://skmtc.dev/placementapi/apis/placement-api/revisions/fc4e7866eaf7?raw)
