Site search

Search IndexLane

Type at least two characters to search.

    Technical note

    Index bloat from non-content URL patterns

    Tag pages, author archives, date archives, and empty filter pages can clutter index coverage without adding unique value. Measure the patterns before deciding what to remove.

    Owner NikoPublished August 30, 2026Read 5 min

    Most SEO monitoring focuses on pages that are not indexed. The inverse problem receives less attention: pages that are indexable even though they provide no useful search landing experience. Large sets of duplicate filters, empty archives, and generated URLs can expand the crawlable surface and make index reports harder to interpret. Confirm index status from Search Console samples or another documented source rather than calling every crawlable URL "index bloat."

    The size of that surface depends on the CMS and configuration. Measure the site's real URL patterns rather than applying a universal archive-to-content ratio.

    Identifying bloat patterns

    Index bloat forms in predictable patterns. The most common sources on any CMS:

    • Tag pages — a thirty-word description repeated across hundreds of tag archives
    • Author archives — a bio paragraph and a list of posts, duplicated for every author
    • Date archives — "/2026/07/" pages that lose meaning as they age
    • Empty category pages — category URLs with no products or posts
    • Pagination overflow — page 47 of a category listing that Google indexes but no user visits
    • Filtered product listings — "/products?color=red&size=m&brand=x" permutations

    A Rust program reading your sitemap can flag these patterns by URL structure:

    use regex::Regex;
    
    fn classify_url(url: &str) -> &str {
        let tag_pattern = Regex::new(r"/tag/").unwrap();
        let author_pattern = Regex::new(r"/author/").unwrap();
        let date_pattern = Regex::new(r"/\d{4}/\d{2}/").unwrap();
        let page_pattern = Regex::new(r"/page/\d+").unwrap();
        let filter_pattern = Regex::new(r"\?.*=").unwrap();
    
        if tag_pattern.is_match(url) { "tag" }
        else if author_pattern.is_match(url) { "author" }
        else if date_pattern.is_match(url) { "date-archive" }
        else if page_pattern.is_match(url) { "pagination" }
        else if filter_pattern.is_match(url) { "filter" }
        else { "content" }
    }
    

    Run this against URL samples exported from Search Console, crawl data, sitemaps, and server logs. The ratio of content to everything else is a triage metric, not a Google threshold. Review whether each classified pattern has a useful audience and distinct content before removing it.

    Measuring the crawl-to-content ratio

    In Python, classify a URL list exported from your monitoring tools:

    import re
    
    def classify_patterns(urls):
        patterns = {
            'tag': re.compile(r'/tag/'),
            'author': re.compile(r'/author/'),
            'date': re.compile(r'/\d{4}/\d{2}/'),
            'page': re.compile(r'/page/\d+'),
        }
        counts = {'content': 0, 'bloat': 0}
        for url in urls:
            matched = False
            for name, pattern in patterns.items():
                if pattern.search(url):
                    counts['bloat'] += 1
                    matched = True
                    break
            if not matched:
                counts['content'] += 1
        return counts
    

    Choose a control per pattern

    Pattern stateAppropriate control
    Useful, distinct landing pageKeep 200, self-canonical, and internally linked
    Duplicate but still needed for usersCanonicalise only to a genuinely equivalent page
    Valid page that should not appear in SearchKeep crawlable and return noindex from one owner
    Unbounded filter or internal-search crawl spaceStop generating links and consider a tested robots rule
    Resource does not existReturn 404 or 410

    Do not combine robots blocking with noindex and expect Google to read the directive. Do not redirect unrelated empty pages to a category root.

    Reducing bloat on WordPress

    WordPress can expose tag, author, date, search, attachment, and pagination routes depending on its theme and plugins. If an archive has no distinct purpose or useful landing content, it can be noindexed while remaining available to users. Configure this in the SEO plugin or one template owner; do not emit a second robots tag blindly:

    add_filter('wp_robots', function (array $robots): array {
        if (is_tag() || is_author() || is_date()) {
            $robots['noindex'] = true;
        }
        return $robots;
    });
    

    For an application route, make the policy part of that route's metadata or response contract rather than matching a fragile path prefix. An HTTP header works for HTML and non-HTML responses:

    X-Robots-Tag: noindex
    

    For Laravel, apply a middleware group to your route definitions:

    Route::middleware(['crawl.noindex'])->group(function () {
        Route::get('/tag/{slug}', [TagController::class, 'show']);
        Route::get('/author/{username}', [AuthorController::class, 'show']);
        Route::get('/archive/{year}/{month}', [ArchiveController::class, 'show']);
    });
    

    The middleware adds the appropriate header:

    public function handle(Request $request, Closure $next): mixed
    {
        $response = $next($request);
        $response->header('X-Robots-Tag', 'noindex');
    
        return $response;
    }
    

    When not to noindex

    Not all non-content URLs should be noindexed. Category pages with unique curated content, author pages with original editorial introductions, and date archives that serve as hubs for event-based content may all be worth keeping indexed. The rule: if a page provides unique value that a user would search for, keep it in the index. If it exists solely because the CMS generated it, noindex it.

    Run the classification after routing, taxonomy, faceted-navigation, or CMS changes and track each pattern against its own inventory. There is no universal archive-to-content threshold: a change matters when it exposes a growing URL pattern with no useful landing-page purpose, receives repeated crawls, or starts appearing unexpectedly in index reports.

    Related notes

    Crawl requests do not prove indexation

    Separate discovery, verified crawl requests, fetched output, index selection, search visibility, and business outcomes when reading crawler logs.

    Read note →

    Client-side frameworks vs. indexation: ensuring HTML renders what bots see

    Compare the normal document, rendered DOM, RSC payload, missing-route behavior, and deployment environments separately when a framework site looks correct in-browser but search output disagrees.

    Read note →