Find the content your site is missing — straight from Google Search Console.
Every site's Search Console data already contains the answer to "what should I write next?" — queries with lots of impressions and zero clicks are people searching for something your site almost provides. gscgap finds those queries and ranks them by how much traffic a fix would unlock.
$ gscgap gap sc-domain:example.com
# Content opportunities — sc-domain:example.com (last 90d)
# People searched for these 32,410 times, saw your site, and never clicked.
1. react to nextjs migration 3240 impr pos 11.4
2. nextjs 15 upgrade checklist 1890 impr pos 9.8 (+3 variants)
3. google search console api guide 1100 impr pos 12.2
| Signal | What it means |
|---|---|
| High impressions | People are already searching for this — proven demand |
| Zero clicks | Your page is visible but not winning the click |
| Position 8–15 | You're just outside the top 10 — one better page flips it |
No keyword tools, no guesswork, no paid APIs. The demand is real because it's your own site's search data.
Requires Python 3.8+. No third-party dependencies — pure stdlib.
git clone https://github.com/wonsukchoi/gscgap.git
cd gscgap
pip install . # or: python3 -m pip install --user .Option A — service account (server-side, no login). For servers, CI, and automation. Create a service account in Google Cloud, download its JSON key, grant it user access on the property in Search Console, then:
export GSCGAP_SERVICE_ACCOUNT=/path/to/service-account.json
gscgap gap sc-domain:example.com # works immediately, no login stepRequires pip install google-auth (the only optional dependency).
Option B — device OAuth (for personal machines). Log in with your own Google account — no service account needed:
- Create an OAuth client at Google Cloud Console — type Desktop app. Enable the Search Console API.
- Export the credentials:
export GSCGAP_CLIENT_ID=your-client-id.apps.googleusercontent.com export GSCGAP_CLIENT_SECRET=your-client-secret
- Log in (prints a device-authorization link — works from any browser,
including your phone):
gscgap login
- Make sure your Google account is a user on the Search Console property you want to analyze (Settings → Users and permissions).
gscgap sites # list properties you can read
gscgap gap sc-domain:example.com # find content gaps (terminal report)
gscgap gap sc-domain:example.com --days 30 --min-impressions 100
gscgap report sc-domain:example.com # write gscgap-report.html
gscgap export sc-domain:example.com # write gscgap-export.json
gscgap logout # remove saved credentials| Flag | Default | Meaning |
|---|---|---|
--days |
90 |
Lookback window |
--min-impressions |
50 |
Ignore queries below this many impressions |
--min-position |
5.0 |
Best position to consider (1-4 = already winning) |
--max-position |
15.0 |
Worst position to consider (beyond = too far) |
--no-group |
off | Don't merge query variants ("react to nextjs" + "react to next js") |
--limit |
15 |
Max opportunities to show |
- Terminal — ranked list with impressions, position, and variant counts
- HTML report — shareable summary with stats and a clean table
- JSON export — machine-readable for your own pipelines (AI agents, CI)
The JSON export is shaped for downstream agents. Feed it to any coding agent:
gscgap export sc-domain:example.com
# → gscgap-export.json with ranked {query, impressions, position, score}- Pull 90 days of queries from the Search Console API (read-only)
- Filter to the opportunity band: 50+ impressions, 0 clicks, position 5–15
- Merge query variants ("react to nextjs" / "react to next js")
- Rank by
impressions × (20 − position)— more demand, closer to page 1 - Show the top N as a report
- Tokens are stored in
~/.gscgap/tokens.jsonwith0600permissions - Read-only OAuth scope (
webmasters.readonly) — gscgap can never modify data - No telemetry, no network calls beyond Google's own APIs
python3 -m unittest discover tests # run testsMIT — free for personal and commercial use. Built by Wonsuk Choi.