# Gcloud Search Console

> Query Google Search Console (Webmasters) performance data from the CLI using gcloud-issued credentials. Use when the user wants to pull clicks, impressions, CTR, or position data for their sites — e.g. "top queries for example.com", "pages ranking for X", "search performance last week".

- **Type:** Skill
- **Install:** `agentstack add skill-extractumio-extractum-skills-gcloud-search-console`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [extractumio](https://agentstack.voostack.com/s/extractumio)
- **Installs:** 0
- **Category:** [Security](https://agentstack.voostack.com/c/security)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [extractumio](https://github.com/extractumio)
- **Source:** https://github.com/extractumio/extractum-skills/tree/main/domain-specific/gcloud-search-console

## Install

```sh
agentstack add skill-extractumio-extractum-skills-gcloud-search-console
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Google Search Console via gcloud

Pull Search Console (GSC) data from the CLI using the official REST API at `searchconsole.googleapis.com`, authenticated via `gcloud` Application Default Credentials.

## Prerequisites

1. **`gcloud` is installed and a project is set.** If not, run the `gcloud-setup` skill first.
2. **The Google account being used owns or has access to the site in Search Console.** Check at https://search.google.com/search-console — if the site is not listed there, this skill cannot help; the user needs to verify the property first.
3. **The Search Console API is enabled on the project:**
   ```bash
   gcloud services enable searchconsole.googleapis.com
   ```

## Step 1: Authenticate ADC with the Search Console scope

The scope is `https://www.googleapis.com/auth/webmasters.readonly` (read-only) or `https://www.googleapis.com/auth/webmasters` (read/write). Read-only is sufficient for querying performance data.

⚠️ `gcloud auth login --scopes=...` does NOT work. Use `application-default login`:

```bash
SCOPES="openid"
SCOPES="$SCOPES,https://www.googleapis.com/auth/userinfo.email"
SCOPES="$SCOPES,https://www.googleapis.com/auth/cloud-platform"
SCOPES="$SCOPES,https://www.googleapis.com/auth/webmasters.readonly"
gcloud auth application-default login --scopes="$SCOPES"
```

When the browser opens, log in with the Google account that has access to the site, and **check every scope box** on the consent screen (if `cloud-platform` is unchecked the ADC will be unusable).

## Step 2: List accessible sites

```bash
TOKEN=$(gcloud auth application-default print-access-token)
PROJECT=$(gcloud config get-value project)

curl -s \
  -H "Authorization: Bearer $TOKEN" \
  -H "x-goog-user-project: $PROJECT" \
  https://searchconsole.googleapis.com/webmasters/v3/sites | jq
```

Sample output:
```json
{
  "siteEntry": [
    {"siteUrl": "sc-domain:example.com", "permissionLevel": "siteOwner"},
    {"siteUrl": "https://example.com/", "permissionLevel": "siteOwner"}
  ]
}
```

### Site URL formats

- **Domain property** (covers all subdomains + schemes): `sc-domain:example.com` — URL-encode the colon as `%3A` when placing it in a URL path: `sc-domain%3Aexample.com`.
- **URL-prefix property**: the full URL, e.g. `https://example.com/`. URL-encode the whole thing with `jq -rn --arg s "$SITE" '$s|@uri'` or `python -c "import urllib.parse,sys;print(urllib.parse.quote(sys.argv[1],safe=''))" "$SITE"`.

## Step 3: Query search analytics

Endpoint: `POST /webmasters/v3/sites/{siteUrl}/searchAnalytics/query`.

```bash
SITE="sc-domain:example.com"
SITE_ENC=$(python3 -c "import urllib.parse,sys;print(urllib.parse.quote(sys.argv[1],safe=''))" "$SITE")

curl -s -X POST \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "x-goog-user-project: $(gcloud config get-value project)" \
  -H "Content-Type: application/json" \
  "https://searchconsole.googleapis.com/webmasters/v3/sites/${SITE_ENC}/searchAnalytics/query" \
  -d '{
    "startDate": "2026-04-07",
    "endDate":   "2026-04-14",
    "dimensions": ["query"],
    "rowLimit": 25
  }' | jq
```

### Request body fields

| Field | Notes |
|---|---|
| `startDate`, `endDate` | `YYYY-MM-DD`. GSC data has ~2-day lag; yesterday's data may be missing. |
| `dimensions` | Array. Any combination of `query`, `page`, `country`, `device`, `date`, `searchAppearance`. |
| `rowLimit` | Max 25,000 per call. Default 1,000. |
| `startRow` | For pagination. Increment by `rowLimit`. |
| `dimensionFilterGroups` | Filter results. See examples below. |
| `type` | `web` (default), `image`, `video`, `news`, `discover`, `googleNews`. |
| `dataState` | `final` (default) or `all` (includes fresh, unsettled data). |

### Common query recipes

**Top queries, last 7 days:**
```json
{"startDate":"2026-04-07","endDate":"2026-04-14","dimensions":["query"],"rowLimit":25}
```

**Top pages, last 28 days:**
```json
{"startDate":"2026-03-17","endDate":"2026-04-14","dimensions":["page"],"rowLimit":50}
```

**Daily click/impression series:**
```json
{"startDate":"2026-03-17","endDate":"2026-04-14","dimensions":["date"]}
```

**Queries that contain "llm" and rank in top 10:**
```json
{
  "startDate":"2026-03-17","endDate":"2026-04-14",
  "dimensions":["query"],
  "dimensionFilterGroups":[{
    "filters":[
      {"dimension":"query","operator":"contains","expression":"llm"}
    ]
  }],
  "rowLimit":100
}
```

**Performance for a specific page:**
```json
{
  "startDate":"2026-03-17","endDate":"2026-04-14",
  "dimensions":["query"],
  "dimensionFilterGroups":[{
    "filters":[
      {"dimension":"page","operator":"equals","expression":"https://example.com/some-page/"}
    ]
  }],
  "rowLimit":100
}
```

Filter operators: `equals`, `notEquals`, `contains`, `notContains`, `includingRegex`, `excludingRegex`.

## Step 4 (optional): Other Search Console endpoints

| Goal | Method & Path |
|---|---|
| List sitemaps | `GET /webmasters/v3/sites/{site}/sitemaps` |
| Submit a sitemap | `PUT /webmasters/v3/sites/{site}/sitemaps/{feedpath}` (needs `webmasters` scope, not read-only) |
| Inspect a URL | `POST /v1/urlInspection/index:inspect` on `https://searchconsole.googleapis.com` — body: `{"inspectionUrl":"...","siteUrl":"..."}` |

## Step 5 (optional): Bulk export to BigQuery

For large date ranges (API caps at 50k rows per query and samples heavily above that), use Search Console's **native BigQuery bulk export**:

1. In Search Console UI → Settings → Bulk data export → link to your GCP project.
2. Google creates a dataset `searchconsole` in that project and writes daily snapshots.
3. Query with `bq`:
   ```bash
   bq query --use_legacy_sql=false '
     SELECT query, SUM(clicks) AS clicks, SUM(impressions) AS impressions
     FROM `YOUR_PROJECT.searchconsole.searchdata_site_impression`
     WHERE data_date BETWEEN "2026-04-01" AND "2026-04-14"
     GROUP BY query
     ORDER BY clicks DESC
     LIMIT 50
   '
   ```

## One-liner "is this working" check

```bash
curl -s \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "x-goog-user-project: $(gcloud config get-value project)" \
  https://searchconsole.googleapis.com/webmasters/v3/sites | jq -r '.siteEntry[]?.siteUrl'
```

If this lists the user's sites, the skill is fully working.

## Troubleshooting

| Symptom | Cause | Fix |
|---|---|---|
| `accessNotConfigured` / `SERVICE_DISABLED` | API not enabled on quota project | `gcloud services enable searchconsole.googleapis.com` |
| `API requires a quota project` | Missing header | Add `-H "x-goog-user-project: $(gcloud config get-value project)"` |
| `Request had insufficient authentication scopes` | ADC created without `webmasters.readonly` | Re-run Step 1 with the correct scope list |
| `User does not have sufficient permission for site 'X'` | Logged-in Google account lacks GSC access to that property | Log in as the owning account, or have the owner add this account in Search Console → Settings → Users and permissions |
| Empty `rows` in the response | No data for that dimension/date range, OR data lag (GSC is ~2 days behind) | Widen the date range, or set `"dataState":"all"` |
| 400 `invalid filter` | Wrong operator name or malformed body | See the filter operator list above |

---

# Part 2 — Search Console Operator Playbook (2025-2026)

Everything below is for **analysis and action**, not for calling the API. Use it once you can pull data (Part 1) to decide *what* to pull, *why*, and *what to do with it*.

## A. Ranking model — what Google actually weighs

| Signal | How measured | Weight | What to watch |
|---|---|---|---|
| **Relevance** | Neural matching + RankEmbed vectors; BERT/DeepRank re-ranks top 20-30 | Must-pass gate | Query-doc semantic match, entity overlap, intent class |
| **Helpful content / site quality** | Sitewide classifier, folded into core March 2024 | Very high; sitewide demotion possible | Originality, depth, firsthand experience, % unhelpful pages |
| **E-E-A-T** | Rater guidelines + off-site entity signals | High across all topics (not just YMYL) | Named authors + bios + `sameAs`, cited sources, editorial mentions |
| **Navboost (click signals)** | 13-month rolling GoodClicks / BadClicks / LastLongestClicks, per device × country × language | Top-tier (per Pandu Nayak testimony) | SERP CTR vs position, dwell, pogo-stick back-to-SERP |
| **Backlinks** | SpamBrain-filtered graph; topical relevance > DR | Still major but bar raised | Editorial, body-of-page, topically matched links; avoid PBNs/anchor spam |
| **Brand mentions (linked + unlinked)** | Corroboration/co-occurrence | Rising fast; now ~3× links for AI visibility | Ahrefs 75k brands: mentions Spearman 0.664, links 0.218 |
| **Core Web Vitals** | CrUX p75 field data, 28-day window | Tiebreaker; heavier post-Dec 2025 CU | LCP ≤2.5s, INP ≤200ms, CLS ≤0.1 |
| **UX / ad experience** | `clutterScore`, interstitial policy demotions | Can single-handedly tank a site | Ad density, popups, unclosable video, intrusive interstitials |
| **Freshness (QDF)** | Query-deserved-freshness classifier | Query-dependent | Real content diffs, not date-swapping |
| **HTTPS / mobile** | Booleans | Baseline | Valid cert, mobile-usable (mobile-first indexing default) |

Key shift: **ranking is comparative.** Your page is scored against the live competing set for each query — rankings can drop with zero on-site changes.

## B. Core algorithms / systems (2025-2026 state)

- **Helpful Content system** — continuous, sitewide. Integrated into core updates since March 2024. Tanks scaled/fringe/AI-at-scale editorial. Recoveries are slow and land on Core Update cycles.
- **SpamBrain / spam updates** — Aug 2025 + Oct 2025 targeted scaled content abuse and site-reputation abuse (a.k.a. "parasite SEO"). Mostly silent devaluation now; manual actions are the exception.
- **Core updates** — 2025: March, June, December. 2026: Feb Discover-only, March (completed Apr 8, 2026). Unannounced "tremors" run between announced CUs — don't panic-edit mid-rollout.
- **Navboost** — user-interaction re-ranker; domain-level click patterns contribute to site-wide quality signals.
- **Neural matching / RankEmbed / BERT / DeepRank** — semantic retrieval + top-N re-ranking. DeepRank decides positions 1-10.
- **Reviews system** — continuous; rewards firsthand testing, original photos/video, pros/cons, comparisons; tanks aggregator rewrites.
- **AI Mode / AI Overviews** — powered by Gemini 3 Pro (AI Mode since Nov 2025, Gemini 3 Flash default Dec 2025). Query fan-out: one user query decomposes into multiple sub-queries retrieved and synthesized (confirmed Google I/O 2025).
- **Twiddlers** — post-retrieval re-rankers (QualityBoost, freshness, diversity) that can promote/demote after main scoring.

## C. GSC reports — what each exposes and what to do with it

### Performance → Search results (the workhorse)

Metrics and real meaning:

| Metric | Real definition | Watch out for |
|---|---|---|
| **Impressions** | URL appeared in SERP for query, even below fold; AIO citations count | Sept 2025 `num=100` removal + a May-Oct 2025 logging bug inflated/deflated impressions — don't over-read mid-2025 deltas |
| **Clicks** | User left SERP for your URL | Multi-click sessions aggregate to 1 |
| **CTR** | clicks ÷ impressions | Noisy at low volume; SERP features (AIO, snippet, packs) consume clicks |
| **Average position** | Impression-weighted mean of topmost rank per query-page-day-country-device | Max 1 position per scope/day. Adding long-tail can *lower* average while clicks rise. Directional only. |

- Data lag ~2-3 days. "Last 24 hours" view gives provisional same-day.
- UI exports cap at 1,000 rows; API at 50,000 per call. For unsampled data use **BigQuery bulk export**.
- Tabs: Queries / Pages / Countries / Devices / Search appearance / Dates. "Compare" mode is the main diagnostic lens.

**High-ROI query-level recipes:**

| Goal | Filter / view |
|---|---|
| Striking-distance keywords | Queries → `Position 8.0-20.0`, sort by impressions desc |
| High-impression low-CTR | Queries → `Impressions > 500`, sort CTR asc (cross-check for AIO on the SERP) |
| Declining queries | Compare last 3mo vs previous, Queries sort Click-diff asc |
| Rising queries | Compare, sort Click-diff desc — expand coverage |
| Cannibalization | Filter 1 query → switch to Pages tab; multiple URLs with traffic = consolidate |
| Brand vs non-brand | Regex filter on Queries — `Doesn't match` brand regex |

### URL Inspection

- **Indexed view** = what Google has on file (coverage, canonical selection, last crawl, user-declared vs Google-selected canonical). Use for canonical mismatch forensics.
- **Live test** = Googlebot runs now (rendered HTML, screenshot, JS console). **Does not evaluate quality/canonical/duplicate** — only tech.
- **Request indexing** is rate-limited (~10-15/day). Don't use it as a bulk strategy — fix the root cause and update the sitemap.

### Indexing → Pages (why URLs aren't indexed)

| Reason | Action |
|---|---|
| **Crawled - currently not indexed** | Quality signal. If spiking after a CU/HCU or on AI-content-heavy sites: prune thin/derivative pages, consolidate, improve E-E-A-T. Sudden spike on small site = possible hack. |
| **Discovered - currently not indexed** | Crawl-budget / perceived low priority. Improve internal links from authoritative pages, faster server response, include in sitemap. |
| **Duplicate, Google chose different canonical** | Audit canonical signals (hreflang, internal links, redirects, content similarity). |
| **Soft 404** | Return real 404/410 or add real content. Common on empty category/search pages. |
| **Excluded by 'noindex'** | Audit — CMS plugins often add noindex inadvertently. |
| **Page indexed without content** | JS rendering failure. Live-test and move critical content server-side. |
| **5xx server error** | Block-priority fix; audit logs, edge workers, capacity. |

### Sitemaps

- Every URL in sitemap must be 200, canonical, indexable. Remove noindex/redirected URLs — they pollute discovery and dilute the report.
- Split sitemaps per content type (products/articles/categories) so Pages → "All submitted pages" pinpoints which segment fails.
- "Discovered URLs" ≠ indexed. Cross-reference via Pages report.

### Experience → Core Web Vitals

- Source: CrUX field data, p75 per URL group, 28-day window. Lab data (Lighthouse/PSI) is for debugging only.
- A group's status = its **worst** metric. Fix at template level, not per URL.
- Report lag: ~28 days after fix before field data shifts. Use PSI per-URL for instant validation.
- Low-traffic URLs don't appear (insufficient CrUX samples).

### Enhancements (rich results)

What's gone or restricted as of 2025-2026:
- **HowTo** — fully retired Sept 2023.
- **FAQPage rich results** — restricted to authoritative gov/health sites since Aug 2023 for Search display (but still high-value for AI answer engines — see Section E).
- **Mobile Usability** standalone report — retired Dec 2023; mobile signal surfaces only in URL Inspection.
- **June 2025 simplification** — Practice Problems, Nutrition Facts variants, Vehicle Listings nearby offers, TV Season Selector, Local Bikeshare, Today's Doodle phased out. BigQuery export fields for deprecated types return NULL after Oct 1, 2025; report/API support stops Jan 2026.

What invalidates a valid result: missing required field, malformed JSON-LD, markup not matching visible content, content behind unrendered JS, expired dates, wrong currency/units.

### Security & Manual actions

Manual-action categories: user-generated spam, thin content, unnatural links to/from site, cloaking, sneaky redirects, pure spam, hidden text/keyword stuffing, sneaky mobile redirects, **site reputation abuse** (clarified Jan 2025 — noindex alone insufficient; moving to subdomain counts as evasion).

Reconsideration request must: admit violation, detail every remediation step, document outcomes (sample fixed URLs, removed link coun

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [extractumio](https://github.com/extractumio)
- **Source:** [extractumio/extractum-skills](https://github.com/extractumio/extractum-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-extractumio-extractum-skills-gcloud-search-console
- Seller: https://agentstack.voostack.com/s/extractumio
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
