GEO in practice: How we optimized Zenitho.ai for ChatGPT and Perplexity in April 2026
In 48 hours (April 21–22, 2026) we ran our own website through a full GEO (Generative Engine Optimization) stack: sped up First Contentful Paint from 4.3s to 1.7s, added 17 JSON-LD schema blocks, registered the site with four search engines, extended robots.txt with AI crawlers, and shipped an llms.txt. Here's every step, what worked, what surprised us, and the numbers we actually measured.
Scope note upfront. This article documents the technical and structural foundation we put in place in 48 hours — Core Web Vitals, indexation, JSON-LD,
robots.txt,llms.txt, IndexNow, middleware. What we can not yet prove: actual citation frequency in ChatGPT, Perplexity, and Gemini. That gets measured in Part 2, 30 days from now — AI citations need a different time horizon than a one-off technical sprint. So read this first piece as "how we built the runway", not "how often AI cites us today".
Why this article exists
In April 2026 every major Czech SEO agency published a theoretical guide to GEO — SEO Consult, MARF, Inpage, SEOkonzult, Symbio, Digichef. The guides are solid, but they almost all end the same way: "here's the definition, here are 10 tips." What's missing between them is a concrete implementation with real data. Someone who tried it on their own site and published the numbers.
So we decided to do it. Over two days we took Zenitho.ai — a site that had only gone through light SEO hygiene — and pushed it through the full GEO stack. This article is a literal diary of that work: what we changed, why we ordered it that way, what broke, and what it means for you if you want the same on your own site.
What GEO is (and how it differs from classical SEO)
GEO (Generative Engine Optimization) is optimizing your content and technical layer so that your website gets cited by large language models — ChatGPT, Perplexity, Google AI Overviews, Gemini, Claude, Microsoft Copilot. Synonyms: AEO (Answer Engine Optimization), LLMO (Large Language Model Optimization), AIO (AI Optimization).
The difference from classical SEO is the goal:
- SEO fights for a position on the SERP. You win when you're in the top ten results.
- GEO fights to be inside the answer. You win when an AI model pulls information from your site and cites you as a source.
Why it matters now: by late 2025, over 40% of Google queries (US) ended as so-called "zero-click" — the user got their answer from an AI Overview and never clicked a SERP result. The Czech number is lower, but the trend is identical. If AI models don't cite you, your visibility will erode over the next 12 months even if your classical SEO positions stay the same.
The starting state of Zenitho.ai (morning of April 21, 2026)
The site before any intervention:
- 0 JSON-LD blocks across the entire website
- No
llms.txt robots.txtwith no directives for AI crawlerssitemap.xmlmissing/sluzby/*subpages- FCP 4.3s, LCP "Error" (unmeasurable), Speed Index 8.8s (mobile PageSpeed)
- Not indexed in Google Search Console, Bing Webmaster Tools, or Seznam WMT
- Only listed on Google Maps; no other directories
- Accessibility bugs:
html lang="cz"(invalid BCP 47), broken heading hierarchy
In other words: a typical state for a site where nobody had systematically worked on SEO. A great baseline for the experiment — any movement from here would tell us the interventions were working.
Strategy: 5 layers, in this order
We didn't want to make random moves. We decided to work through five clearly separated layers, in this order:
- Technical foundation — Core Web Vitals, clean URLs, correct language
- Classical indexation — Google, Bing, Seznam
- AI-specific files —
robots.txtdirectives for AI bots +llms.txt - Structured data — JSON-LD schema on every page
- External signals and monitoring — directories + crawler detection
Why this order: speed and indexation are prerequisites. If crawlers time out or Google doesn't even know about you, everything else is wasted. Schema and AI files are the core — without them AI can't assign structure to your content. Directories and detection are the reinforcing layer — they boost signal, but alone they don't work.
Implementation, step by step
Step 0: Technical foundation (April 21, 2026, 16:00–23:43)
Seven hours, 20+ commits. The most painful layer, because PageSpeed doesn't forgive.
Before:
| Metric (mobile) | Before |
|---|---|
| First Contentful Paint | 4.3s |
| Largest Contentful Paint | Error (NO_LCP) |
| Total Blocking Time | Error (NO_LCP) |
| Speed Index | 8.8s |
| Cumulative Layout Shift | 0 |
LCP couldn't be measured at all. Reason: the viewport fade-in animation used opacity: 0, which PageSpeed interprets as "no visible LCP candidate." The fix: change it to opacity: 0.01. Unmeasurable became measurable — and that was just the first of twenty similar optimizations:
- Inline critical CSS,
deferGoogle Fonts until after interaction - Self-host Iconify (removed 300 kB of external JS)
- Defer Google Tag Manager until the first user interaction
- Replaced eager YouTube embed with a click-to-play facade (saved 7.9 MB of render-blocking on
sluzby/web) - WebP variants for every portfolio + hero image
- Skip 1.5 MB hero video on mobile (via
matchMediadetection) - Localized the paper-texture SVG (instead of external fetch)
After:
| Metric (mobile) | Before | After | Change |
|---|---|---|---|
| First Contentful Paint | 4.3s | 1.7s | −60% |
| Largest Contentful Paint | Error | 4.2s | measurable |
| Total Blocking Time | Error | 0 ms | green |
| Speed Index | 8.8s | 1.8s | −80% |
| CLS | 0 | 0.033 | green |
LCP 4.2s is still in the red — the next round. But three out of four metrics are green, crawlers stopped timing out, and Googlebot can now traverse the full site.
Why this matters for GEO: AI crawlers don't directly measure speed. But AI Overviews pull from Google's index, and Google weighs Core Web Vitals as a ranking factor. A slow site = lower index position = lower chance of being picked up by AI.
Step 1: Indexation in search engines
An underrated layer. Most GEO guides skip it, yet it's critical: most AI models (Gemini, AI Overviews, Copilot) pull from Google's or Bing's index. If you're not in them, AI can't see you.
What we did:
- Clean URLs — rewrote
.htmlextensions to canonical URLs./portfolioinstead of/portfolio.html. Configured via Vercel rewrites. sitemap.xml— added/sluzby/web,/sluzby/kliniky(previously missing)html lang="cs"— fixed from invalidcz(BCP 47 requires the two-letter ISO 639-1 language code;czis a country code, not a language)- Canonical + title — cleaned up across all pages
- Register, submit sitemap:
- Google Search Console → submit sitemap, Request indexing for every key page
- Bing Webmaster Tools → submit sitemap (Bing is worth it in Czechia too, because Copilot)
- Seznam WMT → verification file uploaded to root + meta tag, submit sitemap
Within 24 hours of Request indexing, every key page was in Google's index. Seznam took 3 days. Bing took 2.
IndexNow — automated push signal
Manually submitting the sitemap in every WMT after every change doesn't scale. On day two in the evening (April 22, after publishing this article) we therefore added IndexNow — an open protocol where a single POST to api.indexnow.org is forwarded to Bing, Seznam, Yandex, and Naver. You ping once; every participating engine receives it.
Why it matters for GEO: a routine crawl by Bingbot/SeznamBot discovers a page update in days to weeks. IndexNow is a push — it tells the engine, "look here again, now." Faster Bing index = faster Copilot coverage; faster Seznam = faster visibility in Czech AI assistants that pull from Seznam.
Implementation: stdlib Python script (zero deps) + GitHub Actions workflow, triggered by every push to main that changes HTML or sitemap:
on:
push:
branches: [main]
paths: ['**.html', 'sitemap.xml']
workflow_dispatch:
jobs:
ping:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 2 }
- name: Wait for Vercel production deploy
run: sleep 90
- name: Ping IndexNow (changed URLs)
run: python3 indexnow.py
Key detail: sleep 90. We wait 90 seconds before pinging so Vercel has time to deploy the new version to the CDN. If we pinged immediately on merge, the engine would fetch the stale version and IndexNow would backfire. workflow_dispatch also enables a manual ping of the entire sitemap (python3 indexnow.py --all) — useful after a major rewrite or a new language variant.
Authentication uses a static key file at the site root (<key>.txt, contents = the key itself). The engine fetches it to confirm you own the domain — standard ownership proof.
Google does not accept IndexNow. It has its own Indexing API, but that's restricted to JobPosting and BroadcastEvent — unusable for regular pages. For Google, the classic submit-sitemap + Request indexing in Search Console stays. Not a dealbreaker — Googlebot is the most aggressive crawler of the bunch anyway.
Net result: every merge to main now auto-notifies Bing, Seznam, and Yandex. Zero manual steps, zero chance of forgetting — and this article you're reading was the first URL the workflow pinged in production.
Step 2: AI-specific files
robots.txt for AI crawlers
We extended robots.txt with explicit User-agent directives for the main AI crawlers:
GPTBot(OpenAI training)OAI-SearchBot(ChatGPT Search)ChatGPT-User(ChatGPT in-answer browsing)PerplexityBotClaudeBot/anthropic-aiGoogle-Extended(Gemini training — separate from Googlebot)Applebot-Extended(Apple Intelligence)
Explicit Allow directives tell AI crawlers "yes, you can train on us and cite us." OpenAI and Anthropic have publicly confirmed they respect robots.txt.
llms.txt
llms.txt is an unofficial standard (Mintlify, April 2025). Goal: give LLMs a structured text summary of your site — like robots.txt, but for content. We filled ours with:
- A short company overview (one paragraph)
- Service pricing (24,900 – 64,900 CZK for websites)
- Two contrasting case studies with real numbers
- Team bios (4 people) with expertise
- Guarantee details
- Contact info and last-updated date
Important caveat: no major AI provider officially respects llms.txt yet. Not OpenAI, not Anthropic, not Google. Perplexity reportedly reads it experimentally but hasn't confirmed publicly. Why we still do it: it takes 15 minutes to write, and if the standard gets traction, we're ready. An asymmetric risk/reward bet.
Step 3: Structured data (17 JSON-LD blocks)
The core GEO work. Without schema, a website reads as unstructured text to machines. With JSON-LD ("this is an Organization, this is its Service with pricing, this is a FAQPage with 11 questions, these are the Person entities behind it") AI can recognize entities and relationships — and cite them.
What we added, page by page:
| Page | Schema types |
|---|---|
index.html | Organization, WebSite, WebPage, ProfessionalService |
sluzby.html | BreadcrumbList, CollectionPage, ItemList (services) |
sluzby/web.html | BreadcrumbList, Service, 3× Offer (Starter/Business/Premium pricing) |
sluzby/kliniky.html | BreadcrumbList, Service, FAQPage (11 Q&As) |
portfolio.html | BreadcrumbList, CollectionPage, ItemList (6 cases) |
o-nas.html | BreadcrumbList, AboutPage, 4× Person with knowsAbout |
kontakt.html | BreadcrumbList, ContactPage, ContactPoint, OpeningHoursSpecification |
Total: 17 blocks, 0 errors in Google Rich Results Test. On the second pass we added optional fields: logo, address, image, priceRange (Google flagged these as recommended, not required).
Concrete E-E-A-T tip: for AboutPage → Person entries, use the knowsAbout property with a list of domain skills. Google's Knowledge Graph uses this signal to establish entity authority. In our case, each person has 3–5 knowsAbout entries (e.g. "conversion rate optimization," "B2B lead generation," "marketing for healthcare providers").
Step 4: Edge Middleware for AI crawler detection
Vercel Web Analytics filters bots by design (it tracks humans via JS pixel; bots don't run JS). So for monitoring AI crawlers, it's useless. Solution: a Vercel Edge Middleware, 14 lines of code:
export const config = {
matcher: '/((?!assets|api|_vercel).*)'
};
const BOT_RE = /GPTBot|OAI-SearchBot|ChatGPT-User|PerplexityBot|ClaudeBot|anthropic-ai|Google-Extended|Googlebot|Bingbot|SeznamBot|Applebot/i;
export default function middleware(request) {
const ua = request.headers.get('user-agent') || '';
const match = ua.match(BOT_RE);
if (match) {
const path = new URL(request.url).pathname;
console.log(`[bot] ${match[0]} -> ${path}`);
}
}
Middleware runs on every non-static request. Logs show up in Vercel Observability → Middleware. On the Hobby plan you get aggregates (invocation count, paths, actions); on Pro you get the actual log text. In the first day we saw 14 middleware invocations — bot/human ratio traceable, but detailed UA text stays behind the paywall.
Step 5: External signals (directories and platforms)
Entity recognition in AI models leans on what the rest of the internet says about you. The more independent domains cite the "Zenitho" entity, the stronger the entity signal.
We registered on:
- firmy.cz — the most important Czech business directory. Structured listing with services and contacts.
- Clutch.co — international agency directory. B2B wings of AI models draw from here.
- LinkedIn Company Page — with full company structure, services section, tagged team
- Google Business Profile (formerly My Business) — for local signals and Maps
Each platform is another authority domain confirming "this is Zenitho agency, offering X, located in Y." AI models pick up these cross-references during entity resolution.
Results after 48 hours
| Area | Before (April 21 morning) | After (April 22 evening) |
|---|---|---|
| FCP (mobile) | 4.3s | 1.7s |
| LCP (mobile) | Error (NO_LCP) | 4.2s |
| Speed Index | 8.8s | 1.8s |
| JSON-LD blocks on site | 0 | 17 |
| Schema errors (Rich Results Test) | — | 0 |
| Indexed in Google | No | Yes (24h) |
| Indexed in Bing | No | Yes (2 days) |
| Indexed in Seznam | No | Yes (3 days) |
AI crawler directives in robots.txt | 0 | 8 |
llms.txt | Didn't exist | Published, 4.4 kB |
| Directory listings | 1 (Maps) | 5 |
| AI crawler monitoring | None | Edge Middleware |
What we haven't measured yet: the actual rate of citations in ChatGPT/Perplexity/Gemini. That's inherently hard to measure — the tools for it (Otterly, Peec AI, AthenaHQ) are paid and need 2–4 weeks for a meaningful trend. We'll report in a follow-up article in 30 days.
What surprised us
1) Vercel Web Analytics filters bots. We assumed turning on Analytics would show us AI crawlers. It didn't — Analytics tracks humans with browsers; bots don't execute JS. Fix: Edge Middleware.
2) No one officially respects llms.txt. OpenAI, Anthropic, Google don't officially crawl it. Perplexity supposedly does (unconfirmed publicly). We still recommend doing it — minimal investment, asymmetric upside.
3) JSON-LD alone isn't enough. Probably the most common mental shortcut. Schema tells machines the structure, but they still read the content. If your Service schema wraps boilerplate copy ("professional custom websites"), AI will cite a competitor with weaker schema but unique data and concrete numbers over you.
4) The Czech market is asleep in practice. The big Czech agencies published theoretical GEO guides in 2026. But almost nobody has published a concrete implementation with numbers. That's the gap this article fills — and we hope it inspires you to the same openness.
Key takeaways
- Speed is a prerequisite, not a GEO feature. Without a fast site, crawlers timeout or drop requests. But speed alone doesn't earn citations — content does.
- Index yourself everywhere AI draws from. Google, Bing, Seznam. Without classical indexation you're invisible to 80% of AI systems.
- Schema is a must-have, not a silver bullet. 17 JSON-LD blocks alone won't increase AI citations. You also need content worth citing.
llms.txtis an investment in the future. Nobody officially respects it today. In a few months that may change. 15 minutes of work, negligible risk.- Detect crawlers, don't hope. Without your own logs you don't know who's visiting. Edge Middleware in 14 lines of code gives you the answer.
Checklist: 10 steps for small-to-medium Czech businesses
- Run your site through PageSpeed Insights. Targets: FCP under 2s, LCP under 2.5s, CLS under 0.1.
- Fix
html lang="cs"(BCP 47) — notcz. - Ship clean URLs (drop the
.htmlextension). - Register the site in Google Search Console. Submit the sitemap. Request indexing.
- Repeat for Bing Webmaster Tools and Seznam WMT.
- Add to
robots.txt:User-agent: GPTBot / PerplexityBot / ClaudeBot / Google-ExtendedwithAllow: /. - Create
llms.txtat the root — a short text overview of the company, pricing, people, contact. - Add JSON-LD schema: at minimum
Organization,ProfessionalService(withpriceRangeandareaServed),FAQPageif you have common questions. - Validate with Google Rich Results Test and Schema.org Validator. Target: 0 errors.
- List the company on firmy.cz, Clutch, LinkedIn Company Page, Google Business Profile.
Advanced: Edge Middleware for AI crawler detection (code above).
Want GEO for your website?
We're Zenitho — a Czech agency that doesn't just teach GEO but actually ships it. On our own site and for clients across private clinics, B2B services, and local businesses.
Request GEO for your websiteFrequently asked questions
Does a small Czech company need to work on GEO right now?
If you target B2B, professional services, or healthcare — yes, start now. The share of users who routinely search ChatGPT and Perplexity for information about companies has been growing year over year, including in the Czech market. B2C e-commerce has less urgency, but the first five steps (speed, sitemap, JSON-LD, Google indexation, clean URLs) pay off in classical SEO too — so do them anyway.
What's the effort ratio between classical SEO and GEO?
In practice, 80% of the work is "classical" — speed, indexation, content quality, schema. The remaining 20% is GEO-specific: llms.txt, AI crawler directives, entity mentions in directories. GEO doesn't work without solid classical SEO.
What if AI systems never adopt llms.txt?
Investment: ~15 minutes. Trivial maintenance. Even if the standard is fully rejected, you haven't lost more than an hour of work. Risk effectively zero, upside meaningful — which is why we recommend it.
When will we see results?
Classical SEO (Google ranking): 2–6 weeks after reindexing. GEO citations: very hard to measure. We recommend building a list of 20 relevant queries (e.g., "Prague digital agency for clinics") and testing them monthly in ChatGPT, Perplexity, and Gemini. You won't get absolute numbers, but you'll see a trend over 2–3 months.
Is there a tool that tracks AI citations?
Yes — Otterly.AI, Peec AI, AthenaHQ. They're paid (~$50–$200/month) and measure how often your domain appears in AI responses. Worth it for small companies only after 3–6 months of GEO work, when there's signal to measure.
What if I don't use Vercel?
Edge Middleware is Vercel-specific. Equivalents: Cloudflare Workers, AWS Lambda@Edge, Netlify Edge Functions. The concept is the same everywhere — intercept the request, parse User-Agent, log bot matches. The code stays around 14 lines on any of these platforms.