If Google is not indexing your pages, the cause is almost always one of four things: Googlebot cannot reach the URL, the URL tells Google not to index it, another URL is treated as the canonical version, or Google reached the page and decided it was not worth storing. This guide walks through each in the order you should test them.
Step 1: Read what Google actually says about the URL
Start with the URL Inspection tool in Search Console, not with a crawler. Inspect the exact URL (including trailing slash and protocol) and record three values:
- Coverage status — the exclusion reason, verbatim.
- User-declared canonical vs Google-selected canonical. If these differ, you have a canonicalisation problem, not an indexing problem.
- Crawl allowed / Indexing allowed — a "No" here ends the investigation immediately.
What each exclusion reason actually means
| Status | What happened | First action |
|---|---|---|
| Discovered – currently not indexed | Google knows the URL exists but has not crawled it | Crawl budget / internal linking / server response time |
| Crawled – currently not indexed | Fetched, then not stored | Content value, duplication, template ratio |
| Duplicate, Google chose different canonical | Another URL won | Fix canonical + internal link signals |
| Excluded by 'noindex' tag | Explicit directive | Remove the tag or accept exclusion |
| Soft 404 | 200 response, empty-looking page | Return real content or a real 404/410 |
| Blocked by robots.txt | Crawl disallowed | Amend the disallow rule |
Step 2: Confirm the page is genuinely crawlable
Fetch the URL the way a bot does, without your browser session or cookies:
curl -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" \
-I https://example.com/your-page/
You are checking for three things: a 200 status, no X-Robots-Tag: noindex in the headers, and a response time that is not pathological. Server-level noindex headers are the single most commonly missed cause because they never appear in the HTML source.
X-Robots-Tag: noindex at the web-server or CDN layer, or a leftover Disallow: /. The HTML looks perfect and nothing indexes.
robots.txt mistakes that quietly kill sections
- Blocking
/wp-content/or a build directory, which prevents CSS/JS loading and degrades rendering. - A pattern such as
Disallow: /*?that removes every filtered or paginated URL from crawling. - Blocking a URL that also carries a canonical or noindex — Google cannot read a directive on a page it may not fetch.
Blocking is not the same as removing. To keep a page out of the index, allow the crawl and serve noindex. To save crawl budget on genuinely worthless URLs, block them and make sure nothing links to them.
Step 3: Resolve canonical conflicts
Google treats your canonical tag as a hint, and it will override you when other signals disagree. A canonical only works when every signal points the same way:
- The canonical tag is self-referencing on the page you want indexed.
- Internal links point to the canonical URL, not to a variant with parameters, uppercase characters or a different trailing slash.
- The XML sitemap lists only the canonical URL.
- Redirects resolve in a single hop to the canonical URL.
- Hreflang annotations, if present, reference canonical URLs and are reciprocal.
A frequent failure on template-driven sites: every page inherits the homepage canonical because the meta layer was implemented once in the layout and never overridden per route. Crawl the site and group by canonical value — if hundreds of URLs share one canonical, that is your answer.
Step 4: Deal with duplication and near-duplication
Duplication is rarely a full copy. It is usually structural:
- Location or service pages generated from one template with only the place name swapped.
- Product variants exposed as separate crawlable URLs.
- Tag, author, and date archives repeating excerpts already published elsewhere.
- Faceted navigation producing thousands of parameter permutations.
The remedy is not more pages — it is fewer, better ones. Consolidate near-duplicates with 301 redirects, keep one strong page per intent, and expose facets through non-crawlable interaction where they add no unique search value.
Step 5: Fix "Discovered – currently not indexed"
This status is about crawl economics. Google found the URL, queued it, and has not prioritised fetching it. Practical levers, in order of impact:
- Internal linking. Orphan pages reachable only from a sitemap are treated as low priority. Link every important page from a hub, a navigation element, or related content.
- Reduce crawl waste. Every parameter URL, session ID, endless calendar or empty tag archive competes for the same budget. On one large multilingual site with 18+ subdomains, cutting redundant URL patterns was what made the remaining pages get crawled at all.
- Improve server response. Sustained slow TTFB causes Google to throttle its own crawl rate. Check the Crawl stats report for response-time spikes correlating with reduced requests.
- Clean the sitemap. Submit only indexable, canonical, 200-status URLs with accurate
lastmodvalues.
Step 6: Fix "Crawled – currently not indexed"
Here the crawl succeeded, so the problem is the page itself. Ask honestly:
- Does this page answer a query that nothing else on the site answers?
- How much of the HTML is unique content versus header, footer, sidebar and boilerplate?
- Would a reader who lands here find the answer, or a summary that sends them elsewhere?
Typical fixes: merge three thin pages into one substantial page, add the specifics only you can supply (real process, real constraints, real examples), and remove pages that exist only to hold a keyword.
Step 7: Rule out rendering problems
If your main content is injected by JavaScript, Google must render before it can evaluate. Use the "View crawled page" HTML in URL Inspection — not your browser's DevTools — and search for a distinctive sentence from the body. If it is missing, indexing failure is a rendering failure. That subject has its own workflow in the JavaScript SEO guide.
A repeatable triage checklist
- URL Inspection: crawl allowed, indexing allowed, canonical match.
curl -Ias Googlebot: status code andX-Robots-Tag.- robots.txt tested against the exact path.
- Canonical tag self-references and matches internal links and sitemap.
- No redirect chain in front of the URL.
- At least one contextual internal link from an indexed page.
- Rendered HTML contains the main content.
- Content is materially different from every other page on the site.
What to do after the fix
Validate the fix in the Page indexing report so Google re-crawls the affected set, resubmit the sitemap if URLs changed, and then leave it alone. Re-indexing at scale takes weeks; repeatedly editing pages mid-validation only resets the clock. Track the count of indexed URLs per template weekly rather than watching individual pages daily.