A while back I was working on a client's website, and somewhere in the middle of the audit I caught myself explaining the same things I'd explained to the last client. And the one before that. Robots.txt, canonical tags, why their site was loading on four different URL versions, why half their pages weren't getting indexed.

That's when it hit me: I should have one document for this. A single reference I can hand to any client with a new website, or any site that isn't following the technical basics. Something I can share with anyone who wants to learn what "good technical SEO" actually looks like.

While putting it together, I figured it shouldn't sit in a folder on my laptop. So here it is, on my website, for anyone who's stuck, wants a quick start, or just wants to double-check they aren't missing something.

But honestly, the first person this is for is me. I'll be coming back to this checklist every time I start work on a new site.

A bit of context on where it comes from:

5+years doing SEO
200+websites audited
Top brandsin India and across the globe, on strategy and technical SEO

Everything here comes from that work: things I've seen break, things I've seen fixed, and the difference those fixes made.

How I've structured this

I've organized it in the order a crawler actually experiences your website. First it finds your site through a few files at the root. Then it reads the head of each page, then the page itself. It renders the page, follows the links, figures out which URL is the real one, checks status codes, and somewhere along the way, Google also judges how fast and usable the page is.

Not every point matters equally for every site. If you have a 15-page website, you don't need an HTML sitemap or a pagination strategy. If you have 50,000 product pages, you need all of it. Take what applies to you.

And if you just want a quick look, I've added a checklist of everything at the end. Bookmark it and run through it whenever you're working on a site.

Let's start.

The files every website needs at the root

The crawler asks: Can I find your site?

robots.txt

This is the first file any well-behaved crawler looks for. It tells crawlers which parts of your site they're allowed to crawl and which they should stay out of. It lives at yoursite.com/robots.txt, and every website should have one.

Two things people often get wrong here:

Common mistakes

  • robots.txt controls crawling, not indexing. If you block a page in robots.txt, Google can still index the URL if other pages link to it. It just won't know what's on the page. If you want a page out of the index, use a noindex tag (and don't block it in robots.txt, otherwise Google can't see the noindex).
  • Don't block your CSS and JavaScript files. Google needs them to render your page the way a user sees it.

AI crawlers in your robots.txt

This one is new, and I think it's going to matter more every year.

AI platforms like ChatGPT, Claude, and Perplexity have their own crawlers, and each one identifies itself with a user agent. Some of the common ones:

OpenAI
GPTBotOAI-SearchBotChatGPT-User

Training, ChatGPT search, and visits a user asks ChatGPT to make

Anthropic
ClaudeBotClaude-SearchBotClaude-User

Training, Claude search, and user-requested visits

Perplexity
PerplexityBotPerplexity-User

Perplexity search and user-requested visits

Google
Google-Extended

Not a separate crawler, but a token that controls whether your content can be used for Gemini

You get to decide which of these you allow. That's a business decision, and there's no single right answer. But make it a conscious decision.

Here's why I say that. A lot of sites are blocking AI crawlers without knowing it. In July 2025, Cloudflare started blocking AI crawlers by default for new domains. So you can have a perfectly clean robots.txt and still be invisible to ChatGPT because of a setting in your CDN or firewall you never touched.

If AI visibility matters to you, check your robots.txt and your CDN or firewall bot settings.

A simple example that allows the AI search crawlers in:

robots.txt
User-agent: *
Disallow: /admin/
Disallow: /cart/

User-agent: OAI-SearchBot
Allow: /

User-agent: PerplexityBot
Allow: /

Sitemap: https://yoursite.com/sitemap.xml

sitemap.xml

Your XML sitemap is the list of pages you want search engines to know about. Every site should have one, submitted in Google Search Console and referenced in your robots.txt.

But having a sitemap isn't enough. It needs to be clean. I call this sitemap hygiene, and it comes down to a few rules:

  1. Only include URLs you actually want indexed. That means canonical URLs that return a 200 status code and don't have a noindex tag.
  2. No redirects, no 404s, no noindexed pages, no parameter URLs. If your sitemap says "index this" and the page says "don't index me" or "I've moved," you're sending mixed signals.
  3. Keep lastmod honest. Only update the date when the page content actually changes. Google uses lastmod if it's consistently accurate, and ignores it if it isn't. (Google ignores priority and changefreq entirely, so don't stress over those.)
  4. Split it up when it gets big. One sitemap file can hold up to 50,000 URLs (or 50 MB uncompressed). Larger sites should use a sitemap index pointing to multiple sitemaps, ideally split by page type so you can see in Search Console which sections are getting indexed.

HTML sitemap (for bigger websites)

If your website is big, an HTML sitemap is worth having. It's a regular page on your site that links out to your important pages in an organized way, which gives both users and crawlers a clear path to everything.

The best example I know is the New York Times. Have a look at their HTML sitemap: it's organized so that you can reach pretty much any article within three to four clicks, whether the article is from 1920 or 2025. That's what an ideal HTML sitemap does. It keeps your crawl depth low, so no important page is buried ten clicks deep where crawlers rarely reach.

Sitemap 1920 March March 14 The article

llms.txt optional

This one's a bit controversial. llms.txt is a proposed file that gives AI models a simple, markdown-based summary of your site. Half the SEO world says add it, the other half says it's useless.

Here's where I land: it's cheap to add, and there's no harm in having it. Some AI crawlers might use it to understand the context of your website. But don't expect results from it.

"No AI system currently uses llms.txt."

John Mueller, Google, June 2025

So add it if you want, and then spend your real effort on everything else in this list.

The page body

The crawler asks: What is on it, and how is it organized?

Use semantic HTML

Semantic HTML means using tags that describe what the content is, instead of wrapping everything in <div>s:

<header>
<nav>
<main>
<article>
<section>
<aside>

This makes it easier for search engines (and any crawler) to understand which part of your page is the main content, which part is navigation, and which part is the footer you repeat on every page. It's a small thing that helps crawlers spend less effort figuring out your page.

Heading tags, like a book index

Your heading tags tell crawlers what your page is about and how it's organized. The H1 and H2s especially carry the main context of the page. I like to think of headings like the index of a book:

H1One H1 per page. That's the title of the book. No other H1 anywhere on the page.
H2Each major section is an H2. Those are your chapters.
H3Subsections under an H2 are H3s. Those are the sections within a chapter.
H4Anything under an H3 is an H4. And so on.

Don't pick heading levels based on how big you want the text to look. That's what CSS is for.

Images

Images are usually the heaviest thing on a page, so a few rules:

  • Keep each image under 100 KB, ideally. It's a rule of thumb I follow, not a Google requirement, but it keeps pages light.
  • Use modern formats like WebP or AVIF. JPG works as a fallback.
  • Always add alt text. It's what screen readers read out, what shows if the image fails to load, and how search engines understand what the image is about.

Don't lazy-load your hero image

This is a really common mistake. While optimizing for speed, people lazy-load every image on the page, including the big hero image at the top. But that hero image is usually your Largest Contentful Paint (LCP) element, and lazy-loading it delays it and hurts your LCP score. Lazy-load the images below the fold, and load the hero immediately.

One thing to keep in mind if you care about Google Discover: Discover wants images at least 1,200 pixels wide. That's in tension with the 100 KB rule, so the answer is to compress well, not to shrink the image.

Keep your HTML under 2 MB

Googlebot only reads the first 2 MB of an HTML file. Anything after that point is ignored, as if it didn't exist.

Read by Googlebot Ignored
Measured on the uncompressed file. CSS and JS files each get their own 2 MB.

A couple of details matter here. The limit applies to the uncompressed file size. And it's per file: your CSS and JavaScript files are each fetched separately with their own 2 MB limit. Images don't count toward your HTML's limit.

Most pages are nowhere near 2 MB of HTML. But I've seen sites with massive inline scripts, huge embedded JSON blobs, or entire product catalogs dumped into a single page get dangerously close. If your important content sits at the bottom of a bloated page, make sure Google actually gets to it.

Separately, keep your total page weight (images, scripts, everything) as low as you can. That isn't a hard cutoff like the 2 MB rule, but it directly affects speed.

Rendering

The crawler asks: Can I actually see the content?

Server-side rendering, ideally

Ideally, your pages should be server-side rendered. That means when a crawler requests your page, the server sends back HTML with all your content already in it. The crawler sees exactly what a user sees, without having to run any JavaScript.

This matters even more now because of AI crawlers. Google can render JavaScript (eventually, and at a cost). But Vercel studied AI crawler traffic in late 2024 and found that the major AI crawlers, including GPTBot and ClaudeBot, fetch JavaScript files but don't execute them.

Server-side rendered

Googlebot: sees it all
GPTBot, ClaudeBot: see it all

Client-side only

<div id="root"></div>

Googlebot: sees it after rendering
GPTBot, ClaudeBot: see an empty page

If your content only appears after JavaScript runs, ChatGPT and Claude simply don't see it.

Or a hybrid approach

If parts of your site have to be client-side rendered, go hybrid. Server-side render the important text: the content you want search engines and AI crawlers to read. Load the interactive components and everything else on the client side.

Hidden content needs to be in the DOM

Many pages have content that only appears when a user clicks something. FAQ accordions are the classic example, along with tabs, "read more" buttons, and the expandable sections you see on most landing pages.

That's fine, as long as the hidden text is already in the HTML when the page loads. If it only gets fetched after the click, crawlers never see it.

My rule of thumb: the Ctrl+F test

Open the page, press Ctrl + F (or Cmd + F on a Mac), and search for a sentence from inside your accordion, without opening it. If the browser can find it, the text is in the page and crawlers can see it. If it can't, you've got a problem.

URLs

The crawler asks: Which version is the real one?

URLs are how people access your content, so they're a very important part of technical SEO. Here's the one golden rule that everything else builds on:

Every URL is unique.

If you change even one character (add a slash, remove a slash, add a dash), it's a completely new URL as far as search engines are concerned.

yoursite.com/page yoursite.com/page/

Once you understand that, most URL problems start making sense.

Your website should load on only one URL version

Every page on your website should be accessible through exactly one URL.

From my audits

Of the sites I've audited, I'd say roughly 30 to 40% get this wrong.

The common versions that cause duplicates:

  • http://yoursite.com/pageHTTP
  • https://yoursite.com/page/Trailing slash
  • https://www.yoursite.com/pagewww
https://yoursite.com/page The one version you picked

If your site loads on more than one of these, search engines see duplicate content: the same page on multiple URLs, competing with itself.

The rule of thumb: pick one version, and 301 redirect every other known variation to it. Then stay consistent across your whole site. Don't have some pages that use a trailing slash and others that don't. Same pattern, everywhere.

HTTPS, and the HSTS header

Your website should be on HTTPS, full stop. It's the standard, and most browsers will warn users away from sites still on HTTP.

On top of that, enable the HSTS header (HTTP Strict Transport Security). It tells browsers to always load your site over HTTPS, even if someone types or clicks an http:// link:

Response header
Strict-Transport-Security: max-age=31536000; includeSubDomains

Use clean URLs, and parameters only when you need them

Handling URL parameters can be a nightmare if it's done badly. Remember the golden rule: every added character creates a new URL. So these are three different URLs showing nearly the same content:

/shoes?color=red /shoes?color=red&size=m /shoes?size=m&color=red

My advice: use clean, static URLs wherever possible, and keep parameters for tracking purposes only.

Where you genuinely need parameters (like filters on an e-commerce category page), use canonical tags. Every filtered or parameterized version should have a canonical tag pointing to the main version of the page, not to itself:

Canonical on a filtered page
<!-- On /shoes/?color=red&size=9 -->
<link rel="canonical" href="https://yoursite.com/shoes/">

Internal search pages should be noindexed

If your website has a search bar, searching usually creates URLs like /search?q=whatever. Make sure those search result pages have a noindex meta robots tag (unless you've deliberately planned for specific search pages to be indexed).

This isn't just about duplicate content. It's a security issue.

From my audits

I've seen this exploited more than once. Attackers find a site whose search pages are indexable, then generate thousands of search URLs stuffed with spam terms, usually betting or adult keywords. Google crawls and indexes them. I've seen millions of these pages get created for a single website overnight. Then when people search for the brand, they see those spammy URLs in the results. It does real damage to a brand's reputation.

A noindex on your search pages shuts that down. Use noindex on its own here, not combined with a canonical pointing somewhere else. Google has said that mixing the two sends conflicting signals.

Status codes and redirects

The crawler asks: Does this page exist?

A proper 404 page, with a real 404 status

Your website should not load a page for a URL that doesn't exist.

Try this on your own site

yoursite.com/asdfghjkl
200 OKWhat I often see
404 Not FoundWhat should happen

What happens? On roughly 20 to 30% of the sites I've audited, the site loads something (often the homepage or an empty template) with a 200 OK status code. To a search engine, that means every random URL is a real page.

What should happen instead:

404

URLs that don't exist return a 404 status code, and users see a helpful 404 page that points them somewhere useful.

410

Pages that are gone for good can return 410 (Gone).

5xx

Server problems return a 5xx code, so search engines know it's temporary.

Soft 404s

A soft 404 is when a page returns 200 OK, but there's basically nothing on it: an empty category, a product with no content, a search with no results.

These hurt more than people think, because they drag down the overall quality of your site. Say you have 10 high-quality pages and 5 soft 404s:

15 pages, and a third of them are empty.

On average, your site looks a lot worse than it is. So find your soft 404s and handle them: add real content, return a proper 404 or 410, or noindex them. Either way, keep them out of the index.

Redirects

If you remove a page that's been around for a while, it has probably built up some authority (some people call it "link juice"): backlinks, rankings, history. You don't want to throw that away.

Redirect it to the most relevant, most similar page you have, using a 3xx redirect:

Permanent

301308

The page has moved for good.

Temporary

302307

A temporary move. When the situation is over, remove the redirect and the original page returns 200 OK again.

Gone

410

Gone for good, no relevant replacement, and you want it dropped from the index.

301 and 308 do the same job, as do 302 and 307. Use whichever your CMS or server supports. And if a page is gone for good, has no relevant replacement, and you want search engines to drop it from their index, use 410 Gone. It tells search engines this page isn't coming back.

Avoid redirect chains

Chain ABCD
One hop AD

A redirect chain is when URL A redirects to B, which redirects to C, which redirects to D. Every hop wastes crawl budget, slows down users, and can leak some of the authority you were trying to preserve. Crawlers may also give up before they reach the end. Worse are redirect loops, where A ends up redirecting back to A and the page never loads.

Chains usually build up over years of site migrations and URL changes. The fix:

  • Redirect directly to the final URL in one hop
  • Update your internal links to point at the final URL, so you aren't relying on redirects at all

Pagination

The crawler asks: How deep does this go?

People handle pagination in a lot of different ways, and the right approach depends on the size of your site.

What Google recommends: give every paginated page its own self-referencing canonical tag. So /category?page=2 canonicals to /category?page=2, not to page 1. Google's docs are explicit about this: don't use the first page as the canonical for the whole series. (And if you still have rel="next" and rel="prev" tags, Google stopped using those years ago.)

That works well for most sites. But for big websites with multiple category pages, each with dozens of paginated pages, the number of URLs can run into the millions. So big sites come up with their own strategies:

Google recommends

Self-referencing canonical on every page. Page 2 canonicals to page 2.

Google advises against

Canonicalizing pages 2+ to page 1. I see this a lot, but it can stop Google from discovering the products or articles that only appear on deeper pages.

A choice for big sites

Noindexing pages 2+ so only the first page gets indexed.

Handle with care

Infinite scroll, which needs to be implemented carefully so crawlers can still reach every item (each "page" of content still needs its own crawlable URL).

There's no single right answer for every site. If your site has thousands or lakhs of pages, you need a deliberate pagination strategy that doesn't waste crawl budget, while making sure your important pages still get crawled, indexed, and performing.

Speed and mobile

The crawler asks: Is it fast and usable on a phone?

Core Web Vitals

Your pages should load fast and pass Core Web Vitals. Page experience is a confirmed ranking signal. It isn't a dominant one, but beyond rankings, faster pages simply keep more people around: the bounce rate drops drastically when your page loads fast.

The three Core Web Vitals and their thresholds:

LCP Largest Contentful Paint

How fast the main content (usually the hero) loads

Good Needs work Poor

Good: 2.5 s or less

INP Interaction to Next Paint

How quickly the page responds when you click or tap

Good Needs work Poor

Good: 200 ms or less

CLS Cumulative Layout Shift

How much the layout jumps around while loading

Good Needs work Poor

Good: 0.1 or less

My rule of thumb

Aim for a PageSpeed Insights score of at least 60 to 70. But keep in mind: that score is lab data, a simulated test. What Google actually uses for rankings is field data, measured from real Chrome users visiting your site.

How Google judges your site's speed

Google doesn't just test one page. It looks at real user data across your site, evaluated at the 75th percentile of page loads, and groups similar pages together.

3 out of 4 visits need to hit the threshold.

If a group of your pages performs well, Google considers that part of your site fast. If a group performs poorly, it can drag down the whole section, not just one URL.

+8% sales

And speed isn't only about rankings. Google has published plenty of case studies on what faster pages do for business. One of my favorites: Vodafone improved their LCP by 31% and saw 8% more sales. It's worth browsing through these if you need to convince a client or a dev team.

Mobile-friendly, always

Google's main crawler is Googlebot Smartphone. That means Google primarily sees and judges the mobile version of your website. That's what mobile-first indexing means.

So your website must be mobile-friendly, and it must load fast on mobile devices, not just on desktop. If content is missing from your mobile version, as far as Google is concerned, it's missing.

Structured data

The crawler asks: What exactly is this about?

Finally, every important page on your website should have relevant structured data, in schema.org JSON-LD format.

Structured data gives search engines and AI crawlers the context of your page in a format they can read directly: what type of page it is, who wrote it, what product it's about, what the price is, what the FAQs are. They understand your page better and don't have to spend as many resources figuring it out. And when crawlers spend less effort per page, your crawl budget stretches further, so more of your pages get crawled and eventually indexed.

Let me be honest about what it doesn't do, though. Adding schema isn't a guaranteed ranking boost. Plenty of sites without schema outrank sites with it. But it's always better to make your content easier for crawlers to understand than harder.

And make sure the schema you add is valid. Broken or incomplete schema helps nobody. It should also follow Google's structured data guidelines (and those of other search engines): mark up only what's actually visible on the page, use the right types, and don't stuff in things that aren't true. Check it with Google's Rich Results Test and the Schema Markup Validator before you ship.

Watch out for double-escaped characters

One more thing on structured data, because it caught a lot of sites off guard. Google now unescapes JSON-LD only once. It used to keep decoding until nothing was left, which quietly cleaned up messy code. Now, if your CMS saves a value already escaped and your theme escapes it again on the way out, that extra layer stays.

Best case

An & shows up as &amp; in your product name.

Worst case

A double-escaped quote breaks the whole JSON-LD block, and because schema almost always comes from a template, every page using that template loses its rich results at the same moment, with no warning.

I wrote a full breakdown of this, including how to check your site in two minutes Google Now Does One Pass of JSON-LD Unescaping Read the post

The quick checklist

That's the baseline. Here's the whole thing at a glance, for when you just want to run through it. Tick things off as you go; your progress stays in this browser.

0 of 36 done
1 Root files 0/5
2 Head 0/5
3 Page body 0/5
4 Rendering 0/2
5 Links 0/4
6 URLs 0/5
7 Status codes and redirects 0/4
8 Pagination 0/1
9 Speed and mobile 0/2
10 Structured data 0/3

If you're working on a website and something here doesn't make sense, or you think I've missed something, reach out. I'll keep updating this as things change. And they always do.