Every other newsletter this year told me my SaaS needed GEO — Generative Engine Optimization. Write an llms.txt. Add "AI-only" schema. Chunk your content for the models. So before sinking a weekend into it, I read one contrarian source, opened Google Search Console for my tool, and looked at the actual numbers. The verdict was boring and freeing: for Google, optimizing for AI answers is still just SEO. The real problem wasn't my markup — it was that almost nothing about my site was discoverable in the first place. Here's the data, the three fixes that mattered, and the two places I face-planted.
Why I didn't buy the GEO hype
I'm building Mimi Seed, an open-source MCP server that lets indie devs drive Play Store / App Store / Firebase releases from inside Claude Code or Codex. Classic indie-hacker situation: tiny audience, and a constant temptation to chase the shiny new growth lever.
The single most useful thing I read was a curated list (awesome-geo) whose thesis is blunt: most "GEO" advice is repackaged SEO with a markup tax. Their reading of the primary docs:
- Google has publicly said optimizing for AI Overviews is the same SEO you already know. No special schema required.
-
llms.txtis a community proposal. Google doesn't support it and has no plans to. Treating it as mandatory is hype. - The one engine that does ask for special treatment is Bing/Copilot (FAQ markup, tables, IndexNow).
- The actual common denominator across every engine: clear authorship, a consistent entity identity, canonical URLs, and being cited by trustworthy external sources.
That last bullet turned out to be the whole game. But I didn't take their word for it — I went to the data.
What GSC actually told me
My landing page lives on a subdomain. I didn't even have a dedicated Search Console property for it — it was rolled up under the parent domain property. So I queried the parent property and filtered to just my pages. Ninety days:
- One URL had any impressions: the homepage. 19 impressions, 0 clicks, average position 6.2.
- The query breakdown came back empty. Every one of those 19 impressions was below GSC's anonymization threshold — i.e., low-volume brand-ish searches. Zero non-brand discovery.
- URL inspection: the homepage was indexed, canonical correct, crawled fine. So indexing wasn't broken.
- Referring URLs: exactly one —
libraries.io, an npm mirror. My entire backlink profile was an auto-generated package page.
This reframed everything. My problem was never snippet wording or AI-readability. You can't optimize the click-through rate of a result nobody sees. The bottleneck was impressions — being found at all — and the lever for that, per the data and the contrarian list, is external citations, not markup.
And one more thing I'd half-ignored: my sitemap had never been submitted to Search Console. It existed at /sitemap.xml, generated by the framework, registered nowhere.
The three fixes that were actually SEO
No llms.txt. No secret AI schema. Just hygiene:
1. A real entity graph. My JSON-LD was a lone SoftwareApplication object. I replaced it with a proper @graph tying together Organization + WebSite + SoftwareApplication, and — the part that matters for both SEO and "GEO" — a sameAs array linking the GitHub repo and both npm packages.
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Organization",
"@id": "https://example.com/#organization",
"name": "Mimi Seed",
"sameAs": [
"https://github.com/jeonghwanko/mimi-seed-sdk",
"https://www.npmjs.com/package/mimi-seed",
"https://www.npmjs.com/package/@yoonion/mimi-seed-mcp"
]
},
{ "@type": "WebSite", "publisher": { "@id": "https://example.com/#organization" } },
{ "@type": "SoftwareApplication", "publisher": { "@id": "https://example.com/#organization" } }
]
}
sameAs is the literal mechanism for telling a search/answer engine "the website, the GitHub org, and the npm packages are all the same entity." For a project that recently went through a rename, consolidating that identity is the highest-leverage markup change you can make.
2. A sitemap that isn't lying. My generated sitemap listed anchor URLs — /#install, /#features, /#cli. Here's the detail no tutorial mentions: Google strips the fragment. Every one of those collapses to the same canonical /. They add zero index coverage and just noise. Worse, the sitemap also listed /tool — which my robots.txt disallowed. That's a self-inflicted "Submitted URL blocked by robots.txt" warning. My landing is a single-page app, so the honest sitemap is exactly one URL. I trimmed it to that, then submitted it. Google fetched it within seconds: 0 errors, 1 URL — which is the fragment-dedup behavior proving itself.
3. A dedicated property. I added a URL-prefix property for the subdomain so its impressions/positions stop being averaged in with unrelated sites. Pure reporting hygiene, but you can't improve what you can't see cleanly.
Where I face-planted
Two pitfalls ate more time than the actual SEO work.
Next.js caches your public/ file list. Google's verification needed google<token>.html served at the site root. I dropped it into public/ on the live box and curled it — 404. But an existing file in the same directory (/icons/...png) returned 200. The running server had snapshotted the set of public files at build/boot and never rescanned. A graceful reload fixed it (the file was on disk the whole time). If you ever hot-patch a static file into a running Node server and it 404s while its neighbors don't, that's your clue — restart, don't debug the path.
Your API's Google identity ≠ your browser's. I tried to submit the sitemap programmatically and got a flat 403: insufficient permission for the new property — even though I'd just verified it in the browser. The catch: the automation authenticates as one Google account; my browser session was a different account. The property was owned by the browser identity, invisible to the API identity. Once I re-verified it under the same account that owned the parent domain property (the one the automation actually uses), the submit went through instantly. Verification is per-identity, and "I'm logged in as me" in two places doesn't mean it's the same me.
The honest limitation
I fixed the hygiene. I did not fix the actual bottleneck. My backlink profile is still one auto-generated npm mirror. The entity graph helps an engine understand my project once it finds it — but the data is unambiguous that the gating factor is being found, and that's a function of external citations I don't have yet. Markup was the easy 20%. The hard 80% — getting real, trustworthy sources to mention the project — is exactly the work that doesn't fit in a JSON-LD block.
So this post is also me doing something about that. Which is very on-brand for the conclusion.
What surprised me
The contrarian source was more actionable than any "47 GEO tactics" listicle, precisely because it told me what not to do. Skipping llms.txt and AI-schema cargo-culting saved the weekend I'd budgeted for them, and the data said that weekend would've moved nothing.
What I'd ask you
If you've shipped a small tool or SaaS: did "GEO" ever do anything measurable for you that plain SEO + getting cited didn't? Or is it, as far as the data goes, just SEO with a markup tax and better marketing? I'd genuinely like to be wrong here — tell me what you've measured.
Top comments (0)