- Monday
Google Search Console Automation: The Weekly Loop That Decides What I Publish Next
- Mark Fulton
- Claude Code, SEO Automation, Search Console
- 0 comments
Almost every guide I found on Google Search Console automation stops in the same place. You create a service account, enable the API, paste some JSON into a config file, ask your AI tool "what are my top queries," and the article ends. Setup is the easy half. The hard half is the decision: what do you actually do with four thousand rows of query data on a Monday morning, and how does that turn into a published change on the site by Monday afternoon?
That gap is why I built the loop in this post. I run four blogs (199.domains, PounceDomains, Favors.dev, and this one) as one solo operator alongside roughly 14 launched products. I do not have time to sit in the Search Console UI comparing date ranges and squinting at a CTR column. So the review runs itself once a week, writes down what it found, decides what gets refreshed and what gets written next, and hands me a short list I can approve in about ten minutes.
This is the measurement half of the engine. The publishing half is the daily Claude Code SEO routine I wrote about here, and the two only work because they share one file. I will get to that file, because it is the actual trick.
What "Google Search Console automation" actually means (and what most guides skip)
Search for this topic and you get two clusters of results, neither of which is a working system.
The first cluster is connector tutorials: MCP servers, service-account setup guides, no-code data pipes. They are accurate as far as they go. The mcp-gsc server exposes roughly 20 read-focused tools and deliberately disables destructive operations unless you opt in, which is a sensible default. But every one of these guides ends at "now you can ask questions about your data." Asking questions is not automation. Asking questions is a nicer dashboard.
The second cluster is content-refresh advice: find posts that lost clicks, find queries you rank 8th for, update and republish. The advice is correct and it is completely manual. You are still clicking through the UI, still exporting to a spreadsheet, still deciding by hand which of 60 posts is worth an afternoon.
Nobody joins the two halves. Real automation means the data pull, the decision, and the change all happen without you being the connective tissue. That is three things, not one:
Pull the performance data on a schedule and store it somewhere durable.
Diff it against the last pull so you are looking at movement, not a snapshot.
Act: refresh the posts that are close, write the posts that are missing, and record what you did so next week's run knows.
Step 3 is where every competitor's article ends and mine starts.
The weekly loop I actually run
Here is the whole thing. It runs Monday morning as a scheduled Claude Code task, one run per blog, and takes a few minutes per property.
Step 1: pull the data, and pull it the right way
The pull uses the Search Analytics query method of the Search Console API, not a screen scrape and not the UI export. Three details matter here and most guides get them wrong:
Ask for more rows than you think you need. The rowLimit parameter accepts 1 to 25,000 and defaults to 1,000. A default pull silently truncates your long tail, which is exactly where the striking-distance keywords live. I pull 5,000 rows per property.
Do not trust the last few days. The API response carries a first_incomplete_date, and Google's own docs say values after it "may still change noticeably." My run pulls the trailing 28 days ending three days back, so nothing in the window is still settling. Skipping this is how you generate a false "traffic is collapsing" alert every Monday.
Know that the API gives you top rows, not all rows. The documentation is explicit that it "does not guarantee to return all data rows but rather top ones." So I never treat a total from the API as the site's true total. I treat it as a consistent sample, which is fine, because the loop cares about movement between two pulls, not absolute truth.
I pull two dimension sets per property: query plus page (the striking-distance material) and page plus date (the trend material). Both go straight to disk as JSON.
Step 2: diff against last week, not against zero
The run loads last week's JSON from the same folder and produces a delta per URL and per query: clicks, impressions, average position, CTR. This is the single change that made the loop useful. A snapshot tells you "this post gets 40 clicks a week," which you cannot act on. A delta tells you "this post lost 18 clicks and dropped from position 6 to 11 in seven days," which is a decision.
The first run has nothing to diff against, so it just writes the baseline and reports nothing. That is expected. The loop gets useful in week two.
Step 3: sort every URL into one of four buckets
The delta gets bucketed by rules I picked and have since adjusted. These are my thresholds, not universal law, and you should tune yours to your traffic volume:
Striking distance. Average position between 8 and 20 with meaningful impressions. The post is on page one or just off it and a genuine content improvement can move it. This is the highest-value bucket and it is almost always the biggest.
CTR gap. Position 5 or better but CTR under about 2%. The ranking is fine and the title and meta description are not doing their job. This is the cheapest fix on the list, usually 15 minutes.
Decay. Clicks down more than 30% versus the prior period, with the position drop to explain it. Candidate for a real rewrite, not a tweak.
Orphan opportunity. A query with real impressions where the ranking URL is the wrong page, which usually means the right page does not exist yet. This bucket is not a refresh list, it is a writing list.
Everything that fits none of these is ignored, which is most of the file. That is the point. The purpose of the bucketing is to throw away 95% of the data before a human sees it.
Step 4: act on the buckets
Striking-distance and CTR-gap items get worked the same run. The agent opens the actual post file in the repo, reads the current content, compares it against what the winning queries suggest is missing, and proposes a specific edit: a new H2 answering a query the post never addresses, a rewritten title tag, an added FAQ entry, a fixed internal link. It does not rewrite the whole article, because whole-article rewrites are how you lose the rankings you already have.
Every proposed change lands as a diff I review. Nothing publishes itself in this half of the engine. That is deliberate, and it is the same human-approval line I keep in every marketing workflow I run: the system drafts, a person sends.
Step 5: refill the calendar
The orphan-opportunity bucket gets appended to the content calendar as candidate topics, each carrying its impression count and current best position so the daily publishing routine can prioritize. This is the part I like most, because it closes the loop: last month's published post generates this week's impression data, which produces next month's topic. The engine feeds itself. If the Accelerator sessions have a single recurring theme, it is this shape, a system whose output becomes its own input.
The state file is the whole trick
If you take one thing from this post, take this. Each blog has a SEO-TRACKING.md file committed to its repo, and it holds:
The date of the last run and the window pulled.
Per-post: target keyword, current position, clicks and impressions this period, position and clicks last period.
A dated log of every change made, one line each: "2026-07-13, added FAQ on X, position 14."
The current bucket assignment for anything actively being worked.
That file is why the automation compounds instead of repeating itself. Without it, every run starts from zero and re-proposes the same three edits forever. With it, the agent can read "I added an FAQ to this post three weeks ago and it went from 14 to 9" and behave differently than it would on a post it has never touched.
It also means the whole system is inspectable. When a run does something dumb, I open a markdown file and read what it thought, instead of digging through logs. And because it is committed to the repo, the history of every SEO decision on every blog is in git.
This is the difference between a prompt and a system, which I have written about at length: a system has state, a prompt does not.
How to build this yourself
You do not need my repos. The build is about an afternoon.
Get API access. Create a Google Cloud project, enable the Search Console API, create a service account, and add the service account email as a user on your Search Console property. If you use a domain property rather than a URL-prefix property, add it there. Store the JSON key outside the repo and reference it by path.
Write the pull script. Roughly 60 lines. It takes a property, a date window, and a dimension set, calls searchAnalytics.query with a rowLimit of 5,000, and writes JSON to a dated file. Plain script, no AI involved. Deterministic work should be deterministic code.
Write the tracking file by hand once. Seed SEO-TRACKING.md with your existing posts and their target keywords. Ten minutes of typing that saves the agent from guessing.
Write the review instructions. This is the agent-facing part: read the two most recent JSON pulls, compute deltas, apply the bucket thresholds, propose edits for the top items, append candidates to the calendar, update the tracking file. Be explicit about thresholds and explicit about what it may not do (mine is not allowed to publish, delete, or touch more than five posts per run).
Schedule it. Claude Code runs non-interactively with the print flag, and the docs cover the flags you need for scripted use, including allowedTools for pre-approving specific tools and a JSON output format if you want the run's cost and result programmatically. Point Task Scheduler or cron at it once a week.
Step 4 is the one people rush. The quality of your review instructions is the quality of your automation, and vague instructions produce a very confident agent doing useless work.
What this automation still gets wrong
I am not going to pretend this is finished.
It has no idea whether a ranking change was caused by my edit or by a core update. It correlates, it does not attribute, and I have watched it take credit for movement that was clearly Google-wide. I read its conclusions with that in mind.
It is bad at judging whether a striking-distance post is actually salvageable. Some posts sit at position 12 because the page is thin, and some sit at 12 because three competitors have 400 referring domains and I am not going to win that with an extra H2. The agent cannot tell those apart yet, so I still veto maybe a third of its refresh proposals.
And the thresholds are guesses that happen to work at my traffic volume. If your site does 500 clicks a day rather than my numbers, "clicks down 30%" is noise, not signal.
None of that makes it not worth running. It reliably surfaces the six or seven things worth doing this week out of a file with thousands of rows, which is the entire job I gave it.
One 2026 change worth knowing about
If you are building any of this, factor in that Search Console itself moved. In June 2026 Google introduced Search Generative AI performance reports, covering impressions, pages, countries, devices, and dates for URLs appearing in generative AI features across Search and Discover. Rollout started with a subset of UK site owners with wider availability planned.
The honest caveat: that report does not include click data yet, and Google has said more metrics will come over time. So you can see whether you are being surfaced in AI answers, but not what it earns you. I have not wired it into the loop for that reason. Impressions with no clicks is a number my bucket rules cannot act on. Worth watching, not worth automating yet.
If you want the whole engine
I ran a full session on this: My Claude Code SEO Blog Engine, covering all three routines, daily publishing, this weekly rank review, and the self-refilling content calendar, with the real tracking files from my blogs on screen. The session has ended but the full replay is available instantly, along with the engine kit, so you can watch it and set it up the same afternoon.
If you want the sessions plus everything else I have built, that lives in the Reinventing AI Accelerator: live training every couple of weeks and the vault of AI apps, tools, and agents from every past session. One small ask, go look at what is in the vault and decide if it is worth it to you. That is the whole pitch.
Frequently asked questions
Can Claude Code access Google Search Console directly?
Not by itself. Claude Code has no built-in Search Console integration, so you connect it one of two ways: an MCP server that wraps the Search Console API, or a plain script that calls the API and writes files the agent reads. I use the script. It is more code up front and far more reliable on a schedule, because a cron job that depends on an MCP connection has one more thing that can silently be down at 6am.
How often should a Search Console automation run?
Weekly, for content decisions. Search Console data is not real-time, the last few days of any window are still incomplete, and ranking changes you act on daily are mostly noise you are reacting to. I run indexing requests for new posts daily because those are time-sensitive, and the analysis loop weekly because that matches how fast the underlying data actually moves.
Is automated content refreshing risky for rankings?
The risky version is: point an AI at a ranking post, let it rewrite the whole thing, publish without review. That is how you lose a position you already had. The version in this post proposes bounded, specific edits (one new section, one rewritten title, one added FAQ) and a human approves the diff before anything goes live. Constrain the edit size and keep the approval step and the risk is small.
Do I need the Search Console API, or can I just export CSVs?
You can start with CSVs. The UI export gets you the same core numbers and you can hand them to an agent to analyze. What you lose is the schedule: someone has to remember to export every week, and the moment that person forgets, the loop dies. The API exists so nobody has to remember. If you are testing whether the bucketing rules make sense for your site, do two manual exports first and skip the API entirely.
What do I do if a post never leaves striking distance?
After three refresh attempts with no movement, I stop refreshing and treat it as a different problem. Usually it is one of two things: the search intent does not match what my post is (which needs a new post, not an edit), or the page has no authority behind it (which needs links or internal linking, not more words). Repeating the same content edit a fourth time is the single easiest way to waste an automation's budget.
Subscribe Now for More AI Insights
Subscribe for Updates from Reinventing AI
Stay current on the most cutting-edge AI solutions for ambitious entrepreneurs and marketers!