Tools used in this workflow: htmlctl on GitHub for publishing and exact staging-to-prod promotion, and gsc-cli on GitHub for read-only Google Search Console reporting.
SEO is a feedback loop, not a launch task
The biggest mistake I used to make with SEO was treating it like a one-time publishing checklist. Write the page. Choose a title. Add a description. Ship it. Hope Google understands it.
That is not how it actually works. A title is a hypothesis. A meta description is a hypothesis. Internal links are hypotheses about which page should own which intent. The only way to find out whether those hypotheses are true is to publish, watch what Google does, and then update the site based on the evidence.
The workflow I use now is deliberately mechanical: publish, inspect, measure, update, deploy, repeat. Google Search Console tells me what Google is doing with the site. htmlctl gives me a fast and reversible way to turn those observations into content changes.
SEO becomes much less mystical once you treat every page as an experiment with Search Console as the telemetry.
The loop in one picture
The loop is simple enough that it can run weekly, or immediately after a meaningful content change:
- Publish to staging with htmlctl. Verify the title, canonical URL, sitemap, and rendered content before touching production.
- Promote the exact release to production. htmlctl promotion is byte-for-byte, so the thing tested on staging is the thing served on prod.
- Inspect important URLs in Google Search Console. Check whether the page is indexed, discovered, blocked, canonicalized correctly, or unknown to Google.
- Pull top pages and top queries. Look for impressions without clicks, queries going to the wrong page, and pages Google is testing unexpectedly.
- Update one specific thing. Title, intro, internal links, FAQ, comparison angle, or a supporting page. Avoid changing everything at once.
- Deploy again and re-measure. The next Search Console window tells you whether the hypothesis improved the site.
The commands I actually use
For this site, Search Console access is available through a local read-only CLI, and deployments go through htmlctl. The exact commands are not the point; the important part is that the measurement and publishing steps are both repeatable.
- GitHubhtmlctl — the static-site control plane I use for staging, release history, exact promotion, generated sitemaps, and rollback.
- GitHubgsc-cli — the read-only Google Search Console CLI I use for URL inspection, sitemap checks, top-page reports, top-query reports, and period comparisons.
Check deployment state
htmlctl status website/futurelab --context prod
htmlctl rollout history website/futurelab --context prod
curl -sf https://futurelab.studio/sitemap.xml
Check Search Console health
gsc-cli doctor \
--credentials-file ../gsc-cli/service-account.futurelab.local.json \
--site sc-domain:futurelab.studio \
--output table
gsc-cli sitemaps list \
--credentials-file ../gsc-cli/service-account.futurelab.local.json \
--site sc-domain:futurelab.studio \
--output table
Inspect a page after publishing
gsc-cli inspect url \
--credentials-file ../gsc-cli/service-account.futurelab.local.json \
--site sc-domain:futurelab.studio \
--url https://futurelab.studio/blog/github-copilot-pro-vs-pro-plus-vs-claude-code/ \
--output table
Find what is working
gsc-cli report overview \
--credentials-file ../gsc-cli/service-account.futurelab.local.json \
--site sc-domain:futurelab.studio \
--days 28 \
--output table
gsc-cli report compare \
--credentials-file ../gsc-cli/service-account.futurelab.local.json \
--site sc-domain:futurelab.studio \
--days 28 \
--dimension page \
--output table
gsc-cli report compare \
--credentials-file ../gsc-cli/service-account.futurelab.local.json \
--site sc-domain:futurelab.studio \
--days 28 \
--dimension query \
--output table
Publish the update
htmlctl apply -f site/ --context staging
# verify staging URLs, then promote the exact release
htmlctl promote website/futurelab --from staging --to prod
What Search Console tells you that a content checklist cannot
Search Console is useful because it shows the difference between the page you intended to publish and the page Google actually understood.
- Submitted and indexed means the page is live in Google's index and can compete.
- Discovered - currently not indexed means Google knows the URL exists but has not put it into the index yet.
- URL is unknown to Google means your internal links and sitemap have not yet produced a visible crawl signal.
- Google canonical differs from user canonical means Google thinks another URL is the real page.
- Queries mapping to the wrong page means your internal-link and title signals are not routing intent where you wanted.
Those states are not abstract diagnostics. They tell you what kind of edit to make next. An unknown page needs discovery and internal links. A discovered page may need patience, stronger links, or clearer uniqueness. A page with impressions and no clicks may need a better title and snippet. A query going to the wrong page may need stronger anchor text and a more explicit first section on the intended target.
Three examples from this site
The numbers are what made the loop feel real. In one 28-day Search Console window I checked — April 5 to May 2, 2026 — the site showed 284 clicks and 14,472 impressions across visible pages. Compared with the previous equivalent window, that was +253 clicks and +12,934 impressions. That kind of movement makes it much easier to see which bets are working.
Search Console growth after continuous SEO iteration
The Copilot comparison page: query fit was obvious
The old Copilot essay was a personal story. Search Console showed that Google was testing it for comparison queries like Claude vs Copilot, Copilot Pro vs Pro+, and Copilot Pro+ vs Claude Code. That mismatch was a gift: the demand was visible, but the page shape was wrong.
So I published a dedicated comparison page at GitHub Copilot Pro vs Pro+ vs Claude Code. In that same 28-day window, the new comparison page had already become the site's second strongest page: 73 clicks, 5,274 impressions, and an average position around 6.2. The lesson: if Google is already sending comparison impressions to an essay, write the comparison page.
TeleCodex: indexing fixed before intent routing
The dedicated TeleCodex page was initially not indexed, while the query telecodex was already getting impressions on broader pages like the comparison article and the mobile workflow article.
After tightening the title, intro, FAQ, and internal links, the dedicated page moved to Submitted and indexed. But Search Console still showed the real problem: the query telecodex had 10 clicks and 353 impressions, while most of that demand was still routed to other pages. The dedicated TeleCodex page had only 1 click and 417 impressions as a page, and for the exact telecodex query it was still receiving only a small slice. Indexing was fixed; intent routing was still settling.
MacTalk: discovered is not the same as indexed
The MacTalk story page made it into the index. The MacTalk vs Apple Dictation comparison page was different: Search Console showed Discovered - currently not indexed. That tells me not to over-invest in a full MacTalk cluster yet. One indexed story and one discovered comparison page are a seed, not a proven engine.
This is the part of the loop that keeps you honest. It is very easy to get excited about a cluster before Google has shown any demand. Search Console makes the difference visible.
Why htmlctl makes this easier
The content loop works only if publishing is cheap and reversible. htmlctl helps because the publishing model is built around exact desired state and immutable releases.
- Staging first. I can render the exact new page, check the title, and inspect the sitemap before production changes.
- Byte-identical promotion. The production release is the staging artifact, not a rebuild with hidden differences.
- Generated SEO artifacts. Sitemap, robots, canonical metadata, structured data, and OG images are part of the release, not manual chores.
- Component-level edits. A title, related-post card, or page body can be changed without rebuilding a whole CMS workflow.
- Rollback is operationally boring. If an update is wrong, the previous release is still there.
That matters because SEO iteration should be safe enough to do often. If every content update feels like a risky deploy, the loop dies. If publishing is a small controlled release, the loop becomes normal work.
The weekly SEO review I would actually run
For a small product site, I would not make this complicated. Once a week, or a few days after publishing a meaningful page, I would check:
- New URLs: are they indexed, discovered, or unknown?
- Top pages: which pages gained impressions and which ones gained clicks?
- Top queries: are the visible queries aligned with the pages that rank?
- CTR gaps: which pages get impressions but no clicks?
- Cannibalization: is a query split across multiple pages?
- Internal links: is the intended page linked with specific anchor text from the pages Google already likes?
Then I would choose one action:
- rewrite one title,
- add one FAQ,
- tighten one intro,
- add two internal links,
- or write one dedicated page for a query Google is already testing.
The restraint is important. If you change too much at once, you lose the ability to learn. Continuous SEO is less about heroic rewrites and more about small, observable corrections.
The principle
SEO is not separate from product work. It is one of the ways the product learns how the market describes the problem. Search Console shows you the language people use. htmlctl lets you reflect that learning back into the site quickly.
That is the exact process I am using here: publish the thing I believe is useful, watch which queries and pages Google tests, then improve the content and internal-link graph until the site and the search intent line up.
- GitHubhtmlctl — source repo for the publishing system used in this workflow.
- GitHubgsc-cli — source repo for the Search Console CLI used in the examples above.
- GoogleSearch Console API documentation — the API surface behind Search Console reporting and inspection workflows.
- GoogleURL Inspection tool — Google's explanation of indexed, discovered, canonical, and crawl states.
- FuturelabWe Don't Just Design for Humans Anymore — the earlier post about htmlctl's generated SEO artifacts.
- Futurelabhtmlctl product page — the product overview for the publishing system used here.