Gsc portfolio audit skill
Audit EVERY Google Search Console property at once — rank all sites by clicks and impressions with period-over-period deltas, then diff keywords per site to surface what is newly ranking, rising, dropping, lost, or ranking well without earning clicks.
by OpenClaudia·MIT license·★ 705 Stars on the repo·GitHub ↗
npx degit OpenClaudia/openclaudia-skills/skills/gsc-portfolio-audit#main ~/.claude/skills/gsc-portfolio-auditChecked ·commit main
Files of Gsc portfolio audit
Show the full text68 lines
GSC Portfolio Audit
Answers "how is everything doing?" across every property on a Search Console account, which is the question the per-site tooling can't answer without dozens of manual exports.
Setup
Requires an OAuth refresh token with https://www.googleapis.com/auth/webmasters.readonly:
export GOOGLE_GSC_CLIENT_ID=... # or GOOGLE_CLIENT_ID
export GOOGLE_GSC_CLIENT_SECRET=... # or GOOGLE_CLIENT_SECRET
export GOOGLE_REFRESH_TOKEN=...
export GSC_EXCLUDE="olddomain.com" # optional, comma-separated
pip install requests
The most common setup failure is unauthorized_client on token refresh. It means the refresh token was issued for a different OAuth client than the id/secret you paired with it. Accounts that have added Google integrations over time usually have several clients; match the pair that minted the token.
Run it
python3 scripts/audit_gsc.py # full: ranking + keyword diff for the top 12
python3 scripts/audit_gsc.py portfolio # just the ranked table
python3 scripts/audit_gsc.py queries --site sc-domain:example.com
python3 scripts/audit_gsc.py --days 90 # quarter over quarter
Flags: --days (window, compared against the window immediately before it), --site (repeatable), --top, --limit, --min-clicks.
Sections and what they mean
| Section | Read it as |
|---|---|
| NEW | queries with zero clicks last period. Where growth is actually coming from. |
| RISING | up ≥50%. Check whether position moved too — if it didn't, demand rose, not your ranking. |
| DROPPING | down ≥40% off a real base. Position tells you which kind: rank fell = ranking loss; rank held but clicks collapsed = something took the clicks above you (AI Overview, a new SERP feature, or the query changed shape). |
| LOST | ranked before, no data now. |
| CTR GAP | ≥1,500 impressions, top 10, under 2% CTR. Title and description rewrites, the cheapest wins available. |
Interpreting
- Report clicks first, impressions second. One large property can swing portfolio impressions enough to mask that everything else grew.
- Separate brand from non-brand. A site whose entire keyword set is its own name (or misspellings of a competitor's) has no acquisition engine, however good the click count looks. Say so plainly in the report.
- A whole-site collapse on its own head term is usually not SEO. Check ownership before diagnosing rankings:
whois <domain> | grep -i "registrar\|updated date"plus whether it still resolves. Expired, transferred, or disputed domains produce a textbook ranking cliff that no amount of SEO work will fix. - "new" in the portfolio table means zero clicks in the prior window, which for a recently launched site is a launch, not a data gap.
- Don't skip queries in languages you can't read. On multi-market sites the growth is usually in non-English long tail; translate the interesting ones rather than filtering them out.
- A property returning 403 is verified for listing but not for search analytics. The script reports it instead of hiding it.
Notes
- GSC data lags about 3 days; the script offsets for this automatically.
- Both periods are fetched per property in parallel, so a 40-property account takes seconds.
- Query rows are capped at 25,000 per period, well above what any single site returns for a 28-day window.
| 1 | |
| 2 | name gsc-portfolio-audit |
| 3 | description > |
| 4 | Audit EVERY Google Search Console property at once — rank all sites by clicks and |
| 5 | impressions with period-over-period deltas, then diff keywords per site to surface what |
| 6 | is newly ranking, rising, dropping, lost, or ranking well without earning clicks. |
| 7 | Built for agencies and multi-site owners. Use when asked to compare all sites, rank |
| 8 | properties by traffic, find new keywords across a portfolio, or spot which site is down. |
| 9 | Trigger phrases: "audit GSC", "all my sites", "rank my properties", "portfolio search |
| 10 | performance", "which sites are down", "what new keywords are we ranking for", |
| 11 | "client site performance", "GSC report across accounts". |
| 12 | For ONE site's queries, pages, or index coverage, use the search-console skill instead. |
| 13 | |
| 14 | |
| 15 | # GSC Portfolio Audit |
| 16 | |
| 17 | Answers "how is everything doing?" across every property on a Search Console account, which is the question the per-site tooling can't answer without dozens of manual exports. |
| 18 | |
| 19 | ## Setup |
| 20 | |
| 21 | Requires an OAuth refresh token with `https://www.googleapis.com/auth/webmasters.readonly`: |
| 22 | |
| 23 | |
| 24 | export GOOGLE_GSC_CLIENT_ID=... # or GOOGLE_CLIENT_ID |
| 25 | export GOOGLE_GSC_CLIENT_SECRET=... # or GOOGLE_CLIENT_SECRET |
| 26 | export GOOGLE_REFRESH_TOKEN=... |
| 27 | export GSC_EXCLUDE="olddomain.com" # optional, comma-separated |
| 28 | pip install requests |
| 29 | |
| 30 | |
| 31 | **The most common setup failure is `unauthorized_client` on token refresh.** It means the refresh token was issued for a different OAuth client than the id/secret you paired with it. Accounts that have added Google integrations over time usually have several clients; match the pair that minted the token. |
| 32 | |
| 33 | ## Run it |
| 34 | |
| 35 | |
| 36 | python3 scripts/audit_gsc.py # full: ranking + keyword diff for the top 12 |
| 37 | python3 scripts/audit_gsc.py portfolio # just the ranked table |
| 38 | python3 scripts/audit_gsc.py queries --site sc-domain:example.com |
| 39 | python3 scripts/audit_gsc.py --days 90 # quarter over quarter |
| 40 | |
| 41 | |
| 42 | Flags: `--days` (window, compared against the window immediately before it), `--site` (repeatable), `--top`, `--limit`, `--min-clicks`. |
| 43 | |
| 44 | ## Sections and what they mean |
| 45 | |
| 46 | | Section | Read it as | |
| 47 | |---|---| |
| 48 | | NEW | queries with zero clicks last period. Where growth is actually coming from. | |
| 49 | | RISING | up ≥50%. Check whether position moved too — if it didn't, demand rose, not your ranking. | |
| 50 | | DROPPING | down ≥40% off a real base. **Position tells you which kind:** rank fell = ranking loss; rank held but clicks collapsed = something took the clicks above you (AI Overview, a new SERP feature, or the query changed shape). | |
| 51 | | LOST | ranked before, no data now. | |
| 52 | | CTR GAP | ≥1,500 impressions, top 10, under 2% CTR. Title and description rewrites, the cheapest wins available. | |
| 53 | |
| 54 | ## Interpreting |
| 55 | |
| 56 | **Report clicks first, impressions second.** One large property can swing portfolio impressions enough to mask that everything else grew. |
| 57 | **Separate brand from non-brand.** A site whose entire keyword set is its own name (or misspellings of a competitor's) has no acquisition engine, however good the click count looks. Say so plainly in the report. |
| 58 | **A whole-site collapse on its own head term is usually not SEO.** Check ownership before diagnosing rankings: `whois <domain> | grep -i "registrar\|updated date"` plus whether it still resolves. Expired, transferred, or disputed domains produce a textbook ranking cliff that no amount of SEO work will fix. |
| 59 | **"new" in the portfolio table means zero clicks in the prior window**, which for a recently launched site is a launch, not a data gap. |
| 60 | **Don't skip queries in languages you can't read.** On multi-market sites the growth is usually in non-English long tail; translate the interesting ones rather than filtering them out. |
| 61 | A property returning 403 is verified for listing but not for search analytics. The script reports it instead of hiding it. |
| 62 | |
| 63 | ## Notes |
| 64 | |
| 65 | GSC data lags about 3 days; the script offsets for this automatically. |
| 66 | Both periods are fetched per property in parallel, so a 40-property account takes seconds. |
| 67 | Query rows are capped at 25,000 per period, well above what any single site returns for a 28-day window. |
| 68 |
Discussion
Alternatives
Browse more free Claude skills or everything in Finance.