Jump to a chapter
The Short Version: Key Takeaways
SEO in 2026 is one foundation for both Google and AI answer engines: fast, server-rendered pages, one clear answer per question, connected schema and real authority from other sites. Astro ships static HTML by default, which removes most technical obstacles before you start. The 21 chapters below show how, step by step.
- Five things first: claim your Google Business Profile, answer each buyer question in the first 50 words of its section, pass Core Web Vitals on mobile, add connected
OrganizationandArticleschema, and let AI crawlers in. - Rich results have shrunk. Google stopped showing FAQ rich results on 7 May 2026, dropped HowTo rich results in 2023 and retired the sitelinks search box in November 2024. The markup still helps machines understand a page.
- Put content in the HTML. Google renders JavaScript quickly (a 10-second median in a 2024 Vercel and MERJ study), but OpenAI's and Anthropic's crawlers do not run JavaScript at all.
- Cite your sources. In the KDD 2024 "GEO" study, methods such as adding citations and statistics boosted visibility in generative engine answers by up to 40%.
Want to know where your own site stands first? Run a free PageSpeed Insights audit and come back to the chapters it flags.
What SEO Really Is Now
SEO still stands for search engine optimisation, but the job has grown into what some now call search everywhere optimisation. Your job is to be the answer wherever people look: Google, Bing, YouTube, Reddit, and increasingly ChatGPT, Perplexity, Claude, and Google's AI Overviews.
The single most useful reframe: you don't have an SEO goal, you have a business goal. More customers, more revenue, more qualified leads. SEO is the most durable way to reach people at the precise moment they're looking for what you sell, and unlike paid ads, the traffic keeps arriving after you stop paying.
What are the four jobs of a search engine?
- Crawl. Bots follow links and fetch pages across the web.
- Render. A headless browser executes JavaScript to see the final page (this step is why front-end architecture matters, covered in Ch. 2).
- Index. The engine stores what it understood in a giant library. If you're not indexed, you cannot rank. Full stop.
- Rank. When someone searches, it orders results by relevance, quality, and trust.
How do search engines understand meaning?
Old SEO matched strings of text. Modern search is vectorised and entity-based: engines convert your content into mathematical representations of meaning and map the world as a graph of entities (people, places, products, concepts) and their relationships. This is Google's Knowledge Graph. Ranking #1 for a broad topic means convincing that graph that your brand is a definitive entity for it, not that you repeated a keyword 30 times.
Write for a knowledgeable human first. Everything technical in this guide exists to remove obstacles between that human's need and your content. Technical SEO cannot rescue thin content, and great content can't rank from a broken site. You need both.
How Search & AI Engines Work
Two systems now read your site: classic crawlers and AI answer engines. They reward the same foundation (clean, fast, server-rendered HTML) but retrieve and present it differently.
What is crawl budget, and how does Google render JavaScript?
Google assigns each site a crawl budget, a finite amount of attention. Slow servers, redirect loops, endless faceted-filter URLs, and piles of low-value pages burn that budget before your important pages get seen. Google also processes pages in two steps: it reads the raw HTML first, then queues the page for JavaScript rendering. A 2024 study by Vercel and MERJ measured a median render delay of about 10 seconds, but the slowest few percent of pages waited hours, and OpenAI's and Anthropic's crawlers do not render JavaScript at all. Content that only appears after client-side JS runs is seen late by Google, and not at all by those AI engines.
A single-page app that renders everything in the browser hands crawlers a near-empty HTML shell on the first pass. Server-rendered or statically generated HTML (Astro's default) gives every reader, Googlebot and Bingbot and AI crawlers alike, the full content immediately, with no render queue and no hydration wait. This is the core reason Astro is a strong SEO substrate, expanded in Part IX.
How do AI answer engines find and cite pages?
AI engines don't browse like people. Most use retrieval-augmented generation (RAG) and a technique Google calls query fan-out:
- Fan-out: your question is split into several sub-queries. "Best CRM for small law firms in Kenya" might fan out to "best CRM 2026," "CRM for law firms," and "CRM pricing Kenya."
- Retrieval: the model pulls specific passages from pages it can parse cleanly.
- Synthesis: it combines those passages into one answer.
- Citation: it names a handful of sources. This is where your brand appears, or doesn't.
The practical takeaway: you're no longer optimising only for the long question a user typed, but for the many sub-queries a model generates. Your content must be extractable from clean HTML, because many AI crawlers do not execute JavaScript the way Googlebot does. Chapter 13 covers this in full.
Google indexes the mobile version of your site by default. If content, links, or structured data exist on desktop but are stripped on mobile, Google effectively doesn't have them. Parity between mobile and desktop is non-negotiable.
Search Intent & the Funnel
Google rewards the page that ends the search. It uses aggregated click and interaction data to rank results (Google confirmed its NavBoost system in 2023 testimony in US v. Google), so a page that sends people straight back to the results to try another is unlikely to hold its position. Matching intent is the highest-leverage decision in SEO.
What are the types of search intent?
| Intent | Funnel stage | Example query | Right page type |
|---|---|---|---|
| Informational | Awareness | "how to reduce cloud costs" | Guide / blog post |
| Investigational | Consideration | "AWS vs Azure pricing" | Comparison |
| Commercial | Decision | "best cost-optimisation tools" | Listicle / "best of" |
| Transactional | Action | "buy CloudHealth" | Product / pricing page |
| Navigational | Branded | "TekZuri contact" | The specific page they want |
How do you read search intent for free?
Google the keyword and study the top 10 results. Whatever format dominates (blog posts, product pages, comparison tables, videos) is what searchers want, because Google has already tested it against billions of clicks. If the SERP is all listicles and you publish a product page, you will not rank there no matter how good the page is. Match the format first, then out-execute on quality.
You almost never rank for a broad head term (e.g. "project management") by targeting it directly. You earn it by dominating the hundreds of specific micro-intents beneath it, which is exactly what the pillar-and-cluster model in Chapter 4 is built to do.
Keyword & Entity Research
Keywords are still the map, but the terrain is topics and entities. Cover a subject completely and clearly and you'll surface for queries you never explicitly wrote.
How do you choose which keywords to target?
Score every candidate on four axes before committing:
- Demand. Are people actually searching this? (Volume matters, but high volume ≠ high conversions.)
- Fit. Does it map to something you sell or to a real step in your funnel?
- Intent. Can you satisfy the need better than the pages currently ranking?
- Difficulty. Can your site realistically outrank them right now? A new site won't beat Amazon for "running shoes."
The bottom-up strategy: money pages first
Most beginners start with broad top-of-funnel posts that never drive revenue. Work backwards instead:
- Money pages first. These are the pages that directly convert: product, service, pricing, feature.
- Build a topic cluster around one money page: a pillar long enough to cover the topic completely (often 2,000+ words) plus specific cluster articles that each link back to it.
- Finish one cluster completely before starting the next. Depth beats scattered breadth.
Engines use NLP to check whether you've covered a topic the way an expert would. Write about espresso and they expect to see related entities: burr grinder, extraction yield, crema, roast profile. Their absence signals shallow coverage. Tools like Surfer or Clearscope surface these terms, but the goal isn't stuffing them in; it's genuinely covering the subject. Every cluster page linking to the pillar with descriptive anchor text is what builds the topical authority needed to rank the pillar for its broad head term.
Where do you find keywords?
- Google Search Console. Your #1 source: real queries already bringing you impressions.
- Autosuggest, "People Also Ask," and AlsoAsked. Free, live question data.
- Reddit & niche communities. The exact language your customers use for their problems.
- Competitor sitemaps. Paste one into an AI tool and ask it to find topic gaps you haven't covered.
If two of your pages target the same intent, Google gets confused about which to rank and often demotes both. Audit for overlap, merge the weaker into the stronger, and 301-redirect the retired URL. One intent, one canonical page.
Content That Ranks
AI can generate competent, average content for free, so average content no longer ranks. The bar is now information gain: net-new value that doesn't already exist on the results page.
Beat the slop with things a model can't invent
- First-hand data. "We surveyed 1,000 users," real numbers from your own operations.
- Expert quotes. Interview the specialists in your company or industry.
- Original graphics. Diagrams, flowcharts, annotated screenshots. Not stock photos. (Google Images and Lens drive real traffic.)
- Specific, lived examples. Concrete cases, edge conditions, and the mistakes you actually made.
The four-step blueprint
- Research. Read the top 5 ranking pages. Note what they all cover, then find what they all miss. That gap is your angle.
- Structure. Outline to match the dominant SERP format and the sub-questions in "People Also Ask."
- Write. Add the human layer above. Lead each section with a direct answer, then explain.
- Optimise. Check topical completeness, tighten headings, add internal links.
Experience, Expertise, Authoritativeness, Trust. Critical for anything touching health, finance, safety, or money ("Your Money or Your Life" topics). Google wants to know who stands behind the content. Give every serious article a real byline linking to a detailed author page (credentials, publications, LinkedIn), and mark authors up with Person schema connected to your Organization. Trust is the load-bearing member of the four. A site that users and other sites distrust won't rank on expertise alone.
How do you format content for featured snippets and AI answers?
To win the answer box (and to be quotable by AI engines), put a concise 40–55-word answer immediately under an H2 phrased as the question. Use short paragraphs, definition lists, numbered steps, and comparison tables. This "answer-first" structure is the single most portable technique across Google snippets, voice, and generative engines.
Rankings rot. Every 3–6 months, pull pages losing traffic in Search Console and refresh them with new data, current-year examples, updated screenshots, and a genuine "last updated" date. Pages with zero traffic and zero backlinks should be improved, consolidated, or 301-redirected away. Dead weight drags down the whole domain's quality signal.
On-Page SEO
On-page work is the surgical layer: the signals that tell an engine precisely what a page is about. The mindset shifts from writer to detail-obsessed editor.
| Element | Best practice |
|---|---|
| Title tag | Under ~60 characters, main keyword front-loaded, written to earn the click. This is your headline in the SERP. |
| Meta description | Under ~155 characters. Not a ranking factor; it's ad copy. Sell the click. Google may rewrite it, so make the page itself strong. |
| H1 | Exactly one per page, describing the page. Distinct from the title tag is fine. |
| H2 / H3 | Logical, nested outline. Question-shaped H2s help snippets and AI extraction. |
| URL | Short, lowercase, hyphenated, descriptive: /ransomware-recovery-guide. No dates or IDs you'll regret. |
| Keyword prominence | The main term should appear naturally in the first ~100 words and in a heading. |
| Internal links | The most under-used lever. Link cluster pages to the pillar and to money pages with descriptive anchor text. |
| Image alt / filenames | roasted-coffee-beans.jpg, not IMG_4931.jpg. Write real alt text for accessibility and image search. |
| Semantic HTML | Use <article>, <nav>, <main>, real headings and lists. It helps assistive tech, crawlers, and LLMs equally. |
It passes authority to the pages that matter, teaches Google how your topics relate, and it's entirely within your control, with no outreach required. Most sites leave enormous value on the table here.
Site Architecture & Internal Linking
Architecture is information. A flat, logical structure spreads authority efficiently and helps every page get crawled and understood.
How deep should your site structure be?
Keep it shallow: every important page should be reachable within a few clicks of the homepage (the old "3-click rule" is a useful guideline, not a Google requirement). Pages buried five levels deep get crawled rarely and rank poorly. Watch for orphan pages, pages with no internal links pointing to them, which crawlers may never find.
Each page holds a share of "link authority" and passes some through its outbound links. Your homepage usually has the most (it attracts the most backlinks), so link directly from it to your highest-value money pages instead of burying them. Use hub-and-spoke clusters, descriptive (not "click here") anchor text, and breadcrumbs to route authority deliberately. Mark breadcrumbs up with BreadcrumbList schema (Ch. 10) so the path shows in search results.
Silos and taxonomy
Group related content under clean, hierarchical paths. /shoes/running/nike-pegasus reads better to both users and engines than a flat slug soup. Keep pagination sane: paginated pages should self-reference canonically and never duplicate title tags.
Technical SEO & Crawl Control
Technical errors quietly sink great content. Most modern stacks handle the basics, but you own the crawl directives, canonicalisation, and redirects.
| Lever | What it does |
|---|---|
robots.txt | Tells crawlers which paths to skip (admin, internal search results). It blocks crawling, not indexing, so don't use it to hide pages from search. |
<meta name="robots"> | noindex, follow keeps a low-value page out of the index while still passing link authority through it. This is how you actually deindex. |
rel="canonical" | Points duplicate or parameter URLs (?sort=price) at the master version so signals consolidate on one page. |
| Redirects | 301/308 for permanent moves (passes authority); 302/307 for temporary. Avoid redirect chains; they waste crawl budget and leak authority. |
| XML sitemap | Lists canonical URLs you want indexed. Submit the sitemap index in Search Console. Add image/video sitemaps for media-heavy sites. |
hreflang | Maps language/region variants so the right version serves the right country (Ch. 12). |
| HTTPS | Table stakes. A valid certificate is a baseline ranking and trust signal. |
| Trailing slashes | Pick one convention and enforce it. /page and /page/ as separate live URLs is duplicate content. |
Start with Google's free PageSpeed Insights for a quick read, then run Screaming Frog SEO Spider (free up to 500 URLs) periodically to catch 404s, redirect chains, missing titles/H1s, duplicate content, and images without alt text. For large sites, log-file analysis reveals what Googlebot actually crawls, and where it's wasting budget on junk URLs.
Core Web Vitals
Google ranks partly on real-world Chrome user data (the CrUX dataset). Three field metrics define "page experience," and you must pass them on mobile.
How do you fix LCP, INP and CLS?
- LCP. Serve the hero as a preloaded, correctly sized WebP/AVIF; avoid render-blocking CSS/JS; use a CDN. (Astro's
priorityimage prop does most of this for you, covered in Ch. 18.) - INP. Ship less JavaScript and break up long tasks on the main thread. Offload third-party scripts to a web worker (Ch. 20).
- CLS. Set explicit
widthandheight(or aspect-ratio) on every image, ad slot, and embed so the browser reserves space before they load.
Lighthouse gives you a lab score in a simulated environment; rankings use field data from real users (CrUX), visible in Search Console's Core Web Vitals report and PageSpeed Insights. Optimise for the field numbers. A green lab score with slow real-world INP still fails.
Structured Data / Schema
Schema is machine-readable context in JSON-LD. It won't make a bad page rank, but it unlocks rich results, feeds the Knowledge Graph, and gives LLMs clean facts to extract, increasingly the bigger payoff.
The schema types worth implementing
| Type | Use on | Note |
|---|---|---|
Organization + WebSite | Site-wide | Foundational entity and site name in results. (Google retired the sitelinks search box in November 2024.) core |
BreadcrumbList | Every deep page | Shows the path in the SERP; reinforces architecture. |
Article / BlogPosting | Content pages | Connect to Person author + Organization publisher. |
Product + AggregateRating | E-commerce | Price, availability, review stars in results. |
FAQPage | Q&A blocks | No rich result any more (see the note below). Still useful as machine-readable Q&A. changed |
HowTo | Step guides | No longer produces rich results in Google (removed in 2023); still harmless as machine-readable steps. |
LocalBusiness | Physical/local | NAP, hours, geo. Pairs with Google Business Profile (Ch. 12). |
Person | Author pages | The backbone of E-E-A-T signals. |
VideoObject / Event | Media / events | Video thumbnails and event listings in search. |
Since August 2023 Google had shown FAQ rich results only for well-known government and health sites. On 7 May 2026 it stopped showing them altogether, and it has since removed the FAQ rich result documentation (Google Search Central changelog). The FAQPage schema type itself remains valid Schema.org markup, and unused structured data causes no problems in Search. It's now more of a GEO/LLM signal than a rich-snippet play. Keep it for machine comprehension, but don't expect the old blue expandable results.
Don't scatter disconnected snippets. Link them with @id so your Article references its author (a Person) and publisher (your Organization), forming a single connected graph. This is what helps Google resolve your brand as a coherent entity. Always validate output with Google's Rich Results Test and Schema.org validator, and never mark up content that isn't visible on the page.
Link Building & Authority
Backlinks are votes of confidence, still one of the strongest ranking signals and a major driver of whether AI engines trust and cite you. Quality and relevance beat volume every time.
Don't obsess over links on day one. Publish 10–15 genuinely excellent pages first, because you need something worth linking to. Then pursue links deliberately:
Tactics that actually work
- Be the source. Original surveys, studies, and data are catnip for journalists and bloggers who need something to cite.
- Journalist queries. Answer reporter requests on services such as Source of Sources, Qwoted or the relaunched HARO. Fifteen focused minutes a day can earn high-authority links.
- Linkable assets. Free calculators, templates, and definitive guides accumulate links passively for years.
- Broken-link building. Find dead outbound links on relevant sites, then offer your resource as the replacement.
- Unlinked mentions. Set an alert for your brand; when a site names you without linking, politely ask them to link it.
- Digital PR. Turn your data into a story worth covering, and pitch it.
Buy links, join link schemes, or spam guest posts with keyword-stuffed anchors. These trigger algorithmic and manual penalties that are painful to recover from. Keep anchor text natural and varied. An unnaturally high ratio of exact-match anchors is itself a spam signal.
Local & International SEO
If you serve a place, local SEO is often your highest-ROI channel. If you serve many regions or languages, international signals keep the right version in front of the right user.
What are the local SEO essentials?
- Google Business Profile. Claim it, fill it out completely (categories, services, hours, photos), and keep it current. This single asset drives the map pack more than anything else.
- NAP consistency. Identical Name, Address, Phone across your site, GBP, and every directory. Inconsistency confuses the ranking systems.
- Reviews. Actively collect them and reply to every one. Volume, recency, and rating all feed local rankings and human trust.
- Local citations. Listings in reputable local and industry directories reinforce your existence and location.
- Local schema & landing pages.
LocalBusinessmarkup, plus a genuinely distinct page per location or service area (not thin duplicates).
In markets like Kenya and East Africa, Google Business Profile, strong reviews, and precise service-area pages (see our page on working with businesses in Nairobi) consistently outperform generic national content for "near me" and city-level queries, and they surface well in AI answers about local providers. It is the core of the local SEO and digital marketing we run for Kenyan SMEs.
How do you handle international SEO?
Use hreflang tags to declare language/region variants (en-KE, en-GB) and prevent duplicate-content ambiguity. Choose a clear URL strategy: subfolders (/ke/) are usually simpler and consolidate authority better than separate ccTLDs for most small teams. Keep one sitemap per locale and translate real content, not just the UI chrome.
GEO: Generative Engine Optimisation
A growing share of searches never reach a blue link. People ask ChatGPT, Perplexity, Gemini, Claude, and Google's AI Overviews and get a synthesised answer. GEO is the discipline of being one of the few sources those engines cite.
Is GEO different from SEO?
GEO is SEO with an extra layer, not a replacement. Generative engines pull from the same indexes that power classic search. If your page isn't crawlable, indexed, and relevant, no AI trick will save it. Classic SEO is now necessary but not sufficient. On top of that foundation, these are the levers with the strongest evidence:
- Answer-first structure. Lead each section with a direct, self-contained answer, then context. Clear H2/H3 hierarchy, bullets, and tables let models extract you cleanly.
- Cite authoritative sources inline. Research (notably the Princeton "GEO" study, published at KDD 2024) found that pages quoting statistics and citing trustworthy sources earned substantially more visibility in generated answers, with the biggest gains for lower-ranked sites. Signal is symmetric: cite trustworthy sources and LLMs treat you as one.
- Specific statistics and named quotes. Concrete numbers and expert attribution get pulled into answers far more than vague prose.
- Own the "best-of" and comparison queries. Models lean on consensus. If ten roundups name you, the AI will confidently name you too.
- Off-site presence. Reddit and LinkedIn are frequently cited by AI engines. A real presence where your buyers talk compounds your citation rate.
- Freshness. AI engines tend to favour recently updated sources for anything that changes. Keep a visible update cadence.
AI engines can only cite what they can fetch. Make sure your robots.txt allows the AI user agents you want: GPTBot, OAI-SearchBot, ChatGPT-User, ClaudeBot, PerplexityBot, Google-Extended, and others. A common trap: since 1 July 2025 Cloudflare has made blocking AI crawlers its default. Check your CDN's bot settings and server logs, because you may be invisible to AI search without realising it.
Does llms.txt help?
llms.txt is a proposed plain-text file at your domain root offering a curated, AI-friendly index of your key content. Two honest facts to hold at once: (1) Google states that Google Search does not use llms.txt or other AI-only files, including for its generative AI features, and that they neither help nor harm rankings there. (2) Other systems may use it, including the emerging wave of autonomous agents that read sites programmatically. It's low-cost and won't hurt, so treat it as optional agent-readability infrastructure, not as a ranking lever.
There's no "position #1" in an LLM. The metric is reference rate or share of voice: how often you're mentioned across many prompts. Google Search Console now has Generative AI performance reports (launched June 2026, rolled out to all sites from 31 August 2026) showing impressions in AI Overviews and AI Mode, and dedicated trackers (Profound, Peec AI, Scrunch, and others) monitor citations across engines. Test it yourself first: ask each engine "who are the best [your category] in [your city]?" and see whether you appear. If you don't, being invisible is costing you customers already.
Measuring & Iterating
What you don't measure, you can't improve, and vanity metrics quietly waste months. Tie SEO to business outcomes, then let the data pick your next move.
Your core instruments
- Google Search Console. The source of truth: impressions, clicks, CTR, average position, index coverage, Core Web Vitals, and the Generative AI performance reports for AI Overviews and AI Mode impressions. Free and irreplaceable.
- GA4. Segment the Organic Search channel, track conversions and revenue, and see which landing pages actually earn money.
- Rank tracking. Monitor your priority keywords over time to catch drops early.
- Screaming Frog / Sitebulb. Scheduled technical crawls for the errors in Chapter 8.
Is it a core update or a penalty?
- Core updates re-weight how Google assesses quality; recovery comes from being genuinely better, not from a quick fix.
- Helpfulness signals demote sites made for search engines rather than people: thin, unoriginal, or mass-produced content. The separate helpful content system was folded into Google's core ranking systems in March 2024, so this now plays out through core updates.
- Manual actions (spammy links, cloaking) appear in Search Console and require a fix plus a reconsideration request.
Publish, then wait for data (SEO is slow; give it weeks), then find pages with impressions but low CTR (fix titles) or good rank on page 2 (add depth and links). Refresh decaying winners, then repeat. Small, compounding improvements beat sporadic rewrites.
Don't over-react to daily fluctuations. Rankings bounce; algorithms wobble. Look at 28-day and 3-month trends before making structural decisions.
Why Astro Is a Great SEO Substrate
Astro's defining choice, to ship zero JavaScript by default and render real HTML, happens to be exactly what crawlers and AI engines want. You start several technical-SEO problems ahead, which is why we build client sites on Astro.
The mechanics that matter for SEO
- Static HTML first. Every reader (Googlebot, Bingbot, GPTBot, ClaudeBot) receives the full content immediately: no render queue, no hydration delay, no empty JS shell.
- Islands architecture. Interactive components (React, Vue, Svelte) are isolated "islands" hydrated individually, so the rest of the page stays static and instant.
- Great Core Web Vitals by default. Less JS means faster LCP and lower INP almost for free.
- First-class SEO tooling. Built-in image optimisation, official sitemap and RSS integrations, and type-safe content collections.
This section targets Astro 7 (released 22 June 2026; current line 7.x). Every SEO-relevant API here is unchanged from Astro 6, so all of it applies exactly as written: the <Font /> component, the image priority/layout props, <ClientRouter />, the official sitemap/RSS integrations, and the Content Layer.
Astro 7 is a foundations release, not an API shake-up. A new Rust .astro compiler, Vite 8 with the Rolldown bundler, and the Sätteri Markdown pipeline made builds 15–61% faster in the Astro team's own tests, which matters most on large content sites and programmatic-SEO catalogues with thousands of pages. Route caching is now stable, cutting TTFB on SSR pages (a direct LCP win); CDN cache providers are still experimental. It needs a current Node 22 LTS release or newer, so check Astro's install docs for the exact minimum.
Stricter HTML. The new Rust compiler parses markup to standards and now errors on things the old compiler silently fixed (unclosed tags, unterminated attributes). This surfaces latent bugs rather than shipping them, so run a local build after upgrading and fix anything it flags.
Markdown pipeline swapped. Sätteri is now the default Markdown/MDX processor, replacing remark/rehype. If your SEO setup leans on rehype/remark plugins (auto heading anchors, rel attributes on external links, reading-time, table-of-contents), install @astrojs/markdown-remark to keep them working. Plain Markdown needs no changes.
Astro shines for content and marketing sites: blogs, docs, landing pages, city/service pages, programmatic catalogues. For a heavily interactive, authenticated app (a dashboard SaaS) where nearly every view is dynamic and personalised, a full app framework like Next.js is often the better fit. Astro can do SSR, but don't fight its grain.
Astro SEO Setup: The Essentials
Astro gives you a clean canvas but doesn't auto-generate meta tags, canonicals, or schema. Wire them once into a reusable head component and every page inherits correct SEO.
Step 1: set your site
This is the foundation for canonical URLs and sitemaps. Without it, both break silently.
import { defineConfig } from 'astro/config'; import sitemap from '@astrojs/sitemap'; export default defineConfig({ site: 'https://tekzuri.com', // required for canonical + sitemap trailingSlash: 'always', // match your canonicals; tekzuri.com URLs end in / integrations: [sitemap()], });
Step 2: a single BaseHead component
Compute the canonical from the current URL, and centralise title, description, Open Graph, and Twitter cards so social shares and search both look right.
--- interface Props { title: string; description: string; image?: string; } const { title, description, image = '/og-default.jpg' } = Astro.props; // Canonical: always absolute, always the current path const canonical = new URL(Astro.url.pathname, Astro.site); const ogImage = new URL(image, Astro.site); --- <title>{title}</title> <meta name="description" content={description} /> <link rel="canonical" href={canonical} /> <!-- Open Graph --> <meta property="og:title" content={title} /> <meta property="og:description" content={description} /> <meta property="og:image" content={ogImage} /> <meta property="og:url" content={canonical} /> <meta property="og:type" content="website" /> <!-- Twitter --> <meta name="twitter:card" content="summary_large_image" />
Prefer a maintained package? The community astro-seo integration exposes a single <SEO /> component covering canonicals, OG, Twitter, and robots directives. Roll your own when you want full control; use the package to move fast.
Step 3: inject JSON-LD
Astro doesn't generate schema, but adding it is trivial: build a plain object and serialise it. Use set:html so Astro doesn't escape the JSON.
--- const schema = { "@context": "https://schema.org", "@type": "Article", "headline": title, "author": { "@type": "Person", "name": "Yash Shah" }, "publisher": { "@type": "Organization", "name": "TekZuri" } }; --- <script type="application/ld+json" set:html={JSON.stringify(schema)} />
Sitemaps, robots.txt & RSS
Three small files decide whether your pages get discovered. Astro generates the sitemap; you write robots.txt and the feed.
Sitemap with real lastmod
The @astrojs/sitemap defaults produce a single file with no modification dates. Add serialize to set a real lastmod per URL (for example from each post's updatedDate ?? date frontmatter) and filter to exclude drafts; entryLimit auto-splits large sites into an index. Skip changefreq and priority: Google ignores both, and only uses lastmod when it is consistently and verifiably accurate. Stamping every URL with the build date teaches Google to ignore yours.
sitemap({
filter: (page) => !page.includes('/drafts/'),
entryLimit: 10000, // splits into sitemap-index.xml when large
serialize(item) {
// lastModified: a Map of URL -> content date you build from your collections
const modified = lastModified.get(item.url);
if (modified) item.lastmod = modified.toISOString();
return item;
},
})The sitemap integration reads your statically known routes. On-demand (SSR) dynamic routes are not auto-included, a common trap on large catalogues and CMS-driven sites. If you render pages at request time, generate those sitemap entries yourself (a custom sitemap.xml.ts endpoint) and always eyeball the built sitemap before deploying.
robots.txt, and letting the AI crawlers in
Astro does not create this file. Drop it in public/ and point it at your sitemap index. Explicitly allow the AI agents you want citing you (see Ch. 13).
User-agent: * Allow: / # Allow AI answer engines to read and cite you User-agent: GPTBot Allow: / User-agent: OAI-SearchBot Allow: / User-agent: ClaudeBot Allow: / User-agent: PerplexityBot Allow: / User-agent: Google-Extended Allow: / Sitemap: https://tekzuri.com/sitemap-index.xml
RSS for discovery & free syndication
Feeds are still consumed by readers, aggregators, and a growing number of AI agents. Consider including the full post body (the content field) rather than only an excerpt, so machines have more to work with.
import rss from '@astrojs/rss'; import { getCollection } from 'astro:content'; export async function GET(context) { const posts = await getCollection('blog'); return rss({ title: 'TekZuri Blog', description: 'Web, AI & automation for East Africa.', site: context.site, items: posts.map((p) => ({ title: p.data.title, pubDate: p.data.pubDate, description: p.data.description, link: `/blog/${p.id}/`, })), }); }
Image Optimisation in Astro
Images are usually the heaviest resource on a page and very often your LCP element. Astro's astro:assets pipeline fixes most of this at build time, but only if you use the components correctly.
Rule 1: store images in src/, not public/
Images imported from src/ get optimised, compressed, format-converted, and hashed. Files in public/ are copied as-is with zero processing. Keep only truly static assets (favicon, robots.txt) in public/.
Rule 2: use <Image />, never a bare <img> for local assets
The component auto-converts to WebP/AVIF, sets width/height to prevent layout shift (CLS), and adds sensible loading/decoding defaults, all with no config.
--- import { Image } from 'astro:assets'; import hero from '../assets/hero.png'; --- <!-- optimized: WebP, compressed, no layout shift --> <Image src={hero} alt="Dashboard preview" />
Rule 3: mark the hero priority to fix LCP
For above-the-fold images (your hero, the LCP element), add priority. Astro sets loading="eager", fetchpriority="high", and optimal decoding so the browser fetches it immediately. Everything below the fold stays lazy-loaded automatically.
<Image src={hero} alt="..." priority /> <!-- below the fold: default lazy loading is correct, leave it --> <Image src={chart} alt="Revenue by region" />
Rule 4: responsive images with layout, widths & sizes
The layout prop (constrained, full-width, fixed) generates a proper srcset so phones don't download desktop-sized images. Pair with sizes to tell the browser how much space the image occupies at each breakpoint.
<Image src={photo} alt="..." layout="constrained" widths={[400, 800, 1200]} sizes="(max-width: 600px) 100vw, 800px" />
Rule 5: use <Picture /> for modern formats & art direction
When you want AVIF with a WebP fallback (or different crops per breakpoint), reach for <Picture />. List the most modern format first.
import { Picture } from 'astro:assets'; <Picture src={photo} formats={['avif', 'webp']} fallbackFormat="png" alt="..." />
Remote images
To optimise images from a CMS or DAM, allowlist their domains. Remote images need explicit width/height, or use inferSize (which, in current Astro, only fetches dimensions for authorised domains).
image: {
domains: ['images.tekzuri.com'],
remotePatterns: [{ protocol: 'https' }],
}| Do | Don't |
|---|---|
Keep source images in src/assets/ | Dump them in public/ expecting optimisation |
Add priority to the LCP/hero image | Lazy-load the hero (delays LCP) |
Always provide meaningful alt | Ship decorative images without alt="" |
| Let below-the-fold images lazy-load | Set every image to eager |
| Use SVG directly for icons/logos | Run vector SVGs through raster optimisation |
Convert heavy GIFs to <video> (mp4/webm) | Serve multi-MB animated GIFs |
Fonts, CSS & Asset Performance
Fonts and render-blocking CSS are quiet LCP killers. Astro's newer tooling self-hosts fonts and trims CSS with almost no effort.
The <Font /> component (Astro Fonts API)
Astro can self-host any font provider automatically. It downloads and caches the files, adds font-display: swap, generates size-matched fallbacks (reducing layout shift), and injects the right preload hints. This removes the third-party DNS lookup and round-trip you pay with the Google Fonts CDN.
// astro.config.mjs import { defineConfig, fontProviders } from 'astro/config'; export default defineConfig({ fonts: [{ provider: fontProviders.google(), name: 'Inter', cssVariable: '--font-inter', }], }); // in your layout <head> import { Font } from 'astro:assets'; <Font cssVariable="--font-inter" preload />
Only preload the fonts actually used above the fold. Preloading everything competes with your LCP image for bandwidth and can make things slower.
CSS & the rest
- Critical CSS. Astro scopes styles per component and inlines small stylesheets, so above-the-fold CSS ships fast without manual extraction.
- Tailwind v4. The old
@astrojs/tailwindintegration is deprecated; use the@tailwindcss/viteplugin, which runs inside Vite 8 (now with the Rolldown bundler) for faster builds and smaller output. - Compression. Ensure your host serves Brotli/Gzip and long cache lifetimes for hashed, immutable assets. Community integrations like
astro-compresscan further minify HTML/CSS/JS at build time.
Islands, Hydration & Core Web Vitals
Every island you hydrate is JavaScript on the main thread, and that's where INP is won or lost. Choose the lightest client directive that still works.
Client directives, ranked by SEO impact
| Directive | Loads when | Use for |
|---|---|---|
client:visible | Scrolled into view | Anything below the fold: carousels, charts, comment widgets. best |
client:idle | Main thread is free | Non-critical above-the-fold interactivity. good |
client:media | A media query matches | Mobile-only menus, responsive-only widgets. |
client:load | Immediately | Only truly critical UI. Use sparingly. costly |
client:only | Client only, no SSR HTML | Last resort. Content isn't in the initial HTML, so crawlers and AI may miss it. SEO risk |
client:only renders nothing on the server, so its content is invisible to the first-pass crawl and to AI engines. Never put SEO-critical content (headings, body copy, links) inside a client:only island.
Server Islands, third-party scripts & prefetch
- Server Islands (
server:defer) render a fast static shell and stream in per-component dynamic content (personalised or request-time data) without turning the whole page into SSR. - Partytown (
@astrojs/partytown) moves heavy third-party scripts (analytics, tag managers) off the main thread into a web worker. This is a direct, measurable INP win. - Prefetch. Enable Astro's built-in
prefetchso linked pages load near-instantly on hover or tap, cutting perceived latency.
The Client Router (View Transitions)
Astro's <ClientRouter /> (formerly <ViewTransitions />, imported from astro:transitions) gives SPA-like, animated navigation while keeping server-rendered HTML that crawlers read perfectly. Navigation feels snappier for visitors without sacrificing indexability.
import { ClientRouter } from 'astro:transitions'; <head> <ClientRouter /> </head>
Content Collections & Programmatic SEO
Type-safe content plus static generation is Astro's superpower for scale, from a disciplined blog to thousands of landing pages generated from a dataset.
Enforce SEO fields with a typed schema
Content Collections validate frontmatter at build time. Make title and description required and a missing meta description becomes a build error instead of a silently un-optimised page in production.
import { defineCollection, z } from 'astro:content'; import { glob } from 'astro/loaders'; const blog = defineCollection({ loader: glob({ pattern: '**/*.md', base: './src/content/blog' }), schema: z.object({ title: z.string().max(60), // title-tag discipline description: z.string().max(160), // meta-description discipline pubDate: z.date(), image: z.string().optional(), }), }); export const collections = { blog };
Programmatic SEO with getStaticPaths()
To capture wide, long-tail demand ("best CRM for [industry] in [city]"), generate a page per data row at build time. Because they pre-render to raw HTML, they're fast and instantly indexable.
--- export async function getStaticPaths() { const res = await fetch('https://api.tekzuri.com/integrations'); const items = await res.json(); return items.map((it) => ({ params: { slug: it.slug }, // 'mpesa', 'kra-etims', ... props: { data: it }, })); } const { data } = Astro.props; --- <h1>Integrate with {data.name}</h1> <p>{data.uniqueDescription}</p>
Do not just swap a keyword across an identical template ("Mad Libs SEO"). Google penalises near-duplicate doorway pages. Every generated page must carry genuine information gain: unique data, real reviews, distinct images, actual local specifics. If you can't make each page meaningfully different, generate fewer pages.
Rendering strategy per route
Default to static (SSG) for everything crawlers and AI should read. Use SSR only when the HTML must reflect request-time data: live availability, personalisation, auth, or regional pricing. Astro lets you mix per route:
--- export const prerender = false; // this page renders on demand (SSR) ---
Rule of thumb: let Astro ship static HTML by default, and pay the SSR cost only where the content genuinely can't be known at build time.
The 60-Day Execution Plan
Stop reading, start shipping. Four two-week sprints that take you from a clean Astro foundation to programmatic scale and authority-building.
Foundation & Intent
- Stand up Astro: set
site, add@astrojs/sitemap, writerobots.txt(allow AI bots). - Connect Google Search Console & GA4.
- Keyword + entity research; pick one wide term and its 20–30 micro-intents.
- Identify your money pages.
Pillar & Cluster
- Publish the money page + a pillar that covers the topic completely, with original data and graphics.
- Publish 4–5 cluster posts, each linking back to the pillar.
- Author E-E-A-T profiles; wire up BaseHead, canonicals, and JSON-LD.
Programmatic Scale
- Build a dataset (JSON/Airtable) of locations, use-cases, or integrations.
- Generate pages via
getStaticPaths()only where each one has real, distinct data; for most small sites that is tens of pages, not hundreds. - Apply dynamic schema; optimise all imagery with
<Image />+priority.
Authority & AI
- Run Screaming Frog; fix 404s, chains, and canonical errors from the build.
- Launch a digital-PR push using your original data; answer journalist requests daily.
- Seed presence on Reddit/LinkedIn; check AI engines for brand mentions.
The Pre-Launch Checklist
Run this before every launch and after every migration.
Technical
siteset; canonical tags absolute and correct on every page.- Sitemap generated and submitted; robots.txt references it and allows AI crawlers.
- HTTPS enforced; one trailing-slash convention; no redirect chains.
- Core Web Vitals green on mobile field data (LCP < 2.5s, INP < 200ms, CLS < 0.1).
- Hero image uses
priority; all images havealtand reserved dimensions. - No SEO-critical content trapped in
client:onlyislands.
On-page & content
- Unique title (<60c) and meta description (<160c) per page; one H1 each.
- Content matches the dominant SERP intent and format.
- Internal links from clusters to pillar and money pages, with descriptive anchors.
- No two pages competing for the same intent (cannibalisation checked).
AI-readiness (GEO)
- Answer-first sections; question-shaped H2s; statistics and inline citations.
- Valid JSON-LD (Organization, Article, Breadcrumb, FAQ where relevant).
- AI crawlers verified reachable (check CDN/bot settings and server logs).
- Visible "last updated" dates; freshness cadence scheduled.
Make your content genuinely the best answer, make it fast and crawlable, structure it so both humans and machines understand it, and earn the trust of other sites. Every chapter here is a way of doing one of those four things.
Rather have this built than build it yourself? TekZuri builds fast Astro websites with everything in this checklist wired in from day one. See how we build websites, or book a free strategy call to find out which chapters your current site needs most.
Related posts
· Yash ShahHow much does a website cost in Kenya in 2026?
A website in Kenya costs about KES 10,000 to 100,000 for a simple or business site and KES 60,000 to 300,000+ for e-commerce with M-Pesa. 2026 guide.
Read article→
· Yash ShahDigital marketing for Kenyan SMEs, honestly
Digital marketing for small businesses in Kenya, without the hype. Where a founder on a tight budget should actually spend limited time and money.
Read article→
· Yash ShahLead generation for small businesses
Lead generation for small businesses is a different problem from the one the big-agency playbook solves. Here's what brings in qualified leads.
Read article→
