← Back to Blog

How to Do a Full SEO and GEO Overhaul on a Hugo Blog

A full SEO and GEO overhaul on a Hugo blog deployed to Cloudflare Pages covers technical SEO (sitemap, meta tags, structured data, broken links), internal cross-links between related posts, title and description optimization, and GEO bookends (quick answer blocks, definition sections, FAQ sections) that let AI search engines extract and cite the content. Every post gets touched, but the existing content stays intact. The structure goes around it, not through it.

What Is GEO (Generative Engine Optimization)?

GEO is structuring web content so AI search engines (Perplexity, ChatGPT, Google AI Overviews) can extract and cite it. Traditional SEO optimizes for Google’s link-based ranking. GEO optimizes for how LLMs pick text to quote. The Princeton GEO study (KDD 2024) found the most effective techniques are adding statistics (+40% citation rate), using definitive language, front-loading answers, and including FAQ sections with question-format headings.

Why This Matters

SEO gets pages indexed and ranked. GEO gets pages cited in AI-generated answers. A blog can rank #1 on Google and still never show up in a Perplexity or ChatGPT answer if the content isn’t structured for extraction.

What You Need

  • Hugo static site generator (v0.154+ used here)
  • Cloudflare Pages project connected to a GitHub repo
  • An existing blog with 20+ posts
  • Familiarity with Hugo frontmatter and template syntax
  • Time estimate: 2-3 hours for the full overhaul (with AI assistance)

The Full Process

The blog listing page showed 35 posts, but clicking most of them served the homepage instead of the post. The root cause: Hugo’s compiled output (blog/ directory) was never committed to git. Since Cloudflare Pages deploys from GitHub, those pages didn’t exist on the live site. CF Pages’ SPA fallback served the root index.html for any unknown route, making broken links look like redirects rather than 404s.

Fix: git add blog/ to track all compiled output, then push.

Gotcha encountered: 22 blog post folders and 44 tag page folders were untracked. The listing page’s index.html was committed (so the listing looked fine), but individual post folders were not.

Phase 2: Internal Cross-Linking

Read all 36 posts, categorized them into topic clusters, and added ~50 natural cross-references:

  • CLAUDE.md setup chain (diet, architecture, skills, chief of staff)
  • Session management loop (tmux, spawn, hooks, keyboard shortcut)
  • Slides trilogy (discovery, PowerPoint vs HTML, deploy to CF)
  • Scraping/research ring (ghostwriting, LinkedIn debugging, Instagram)
  • Email workflow (MJML building, deliverability testing)
  • Build/deploy path (slides, dashboard, unit tests, Supabase)

Also fixed 4 broken internal links using /posts/ prefix instead of /blog/.

Phase 3: SEO Audit and Fixes

  1. Sitemap: robots.txt pointed to a root sitemap with 1 URL. Changed to point to /blog/sitemap.xml (84 URLs).
  2. OG Image: No social sharing image existed. Created a branded 1200x630 default and added og:image + twitter:image to the template.
  3. Titles: 6 posts used raw filename slugs as their <title> tag. Added human titles with explicit slug fields to preserve URLs.
  4. Meta Descriptions: 3 posts were missing descriptions, falling back to the site-wide default.
  5. Structured Data: BlogPosting schema was missing publisher, image, and mainEntityOfPage. Added all three.
  6. Thin Tag Pages: 55 tag pages, many with 1 post. Added noindex, follow for tags with fewer than 3 posts.
  7. Duplicate Content: Two near-identical posts from the same day consolidated into one.
  8. Bugs: Duplicate H1 in one post, unclosed CSS media query in the single-post template.

Phase 4: GEO Bookends

Added three structural elements to all 26 tutorial posts without changing the existing body content:

  1. Quick answer block (40-80 words) as the first paragraph after frontmatter. Answers the core question in isolation. 44% of AI citations pull from the first 30% of text.
  2. “What Is X?” definition section where missing (10 posts). Clean 2-3 sentence definitions as featured snippet targets.
  3. FAQ section (## Common Questions) with 3-5 questions per post at the bottom. Question-format headings are direct citation targets for AI search.

Phase 5: Authorship Transparency

Added notes to every post distinguishing human-written content (9 posts: “this one was written by me”) from AI-written content (27 posts: full disclosure about AI authorship). Updated the template to use per-post author field so bylines differ: “By Alex Dobrenko” vs “By Code for Creatives.”

Verifying It Works

After each phase, the blog was rebuilt with hugo and the compiled output checked:

# Verify title tags
grep "<title>" blog/post-slug/index.html

# Verify OG image
grep "og:image" blog/post-slug/index.html

# Verify structured data
grep "publisher" blog/post-slug/index.html

# Verify noindex on thin tags
grep "noindex" blog/tags/timezone/index.html

# Verify no noindex on thick tags
grep "noindex" blog/tags/claude-code/index.html

Common Questions

What is the difference between SEO and GEO?

SEO optimizes for Google’s link-based ranking: keywords, backlinks, page speed. GEO optimizes for AI search citation: extractable structure, front-loaded answers, definition sections, and FAQ blocks that models can quote directly. Different optimization targets, but most GEO changes also help traditional SEO.

Can GEO changes hurt traditional SEO?

No. Quick answer blocks, definition sections, and FAQ sections are the same elements Google favors for featured snippets. These additions improve both traditional and AI search visibility at the same time.

Should I create separate GEO-optimized pages?

No. Separate pages targeting the same topics cause keyword cannibalization. Two pages on the same domain compete for the same terms, and Google picks one and suppresses the other. Add GEO structure to existing posts instead: quick answer at the top, FAQ at the bottom, original content untouched in the middle.

How long before GEO changes take effect?

Traditional search re-indexing takes days to weeks depending on crawl frequency. Perplexity and similar AI engines re-crawl on their own schedule, typically 1-4 weeks for active domains. Submitting the sitemap in Google Search Console speeds things up.

Does changing a Hugo post title change the URL?

Yes, if using the /:slug/ permalink pattern. Hugo generates the slug from the title by default. To change a title without breaking the URL, add an explicit slug field to the post’s frontmatter that preserves the original URL path.


A note from Alex: hi i’m alex - i run code for creatives. i’m a writer so i feel that it is important to say - i had claude write this piece based on my ideas and ramblings, voice notes, and teachings. the concepts were mine but the words themselves aren’t. i want to say that because its important for me to distinguish, as a writer, what is written ‘by me’ and what’s not. maybe that idea will seem insane and antiquated in a year, i’m not sure, but for now it helps me feel okay about putting stuff out there like this that a) i know is helpful and b) is not MY voice but exists within the umbrella of my business and work. If you have any thoughts or musings on this, i’d genuinely love to hear them - its an open question, all of this stuff, and my guess is as good as yours.

Ready to build this yourself?

Join the next cohort of Code for Creatives

Join the Next Cohort →