<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: SEOSage</title>
    <description>The latest articles on DEV Community by SEOSage (seosage).</description>
    <link>https://dev.to/seosage</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F15083%2F0d98766a-2d03-4b13-91a3-b0972dc3cca4.png</url>
      <title>DEV Community: SEOSage</title>
      <link>https://dev.to/seosage</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/seosage"/>
    <language>en</language>
    <item>
      <title>Hreflang: The Audit That Stops Your Pages Fighting Across Countries</title>
      <dc:creator>Kessy Stalford</dc:creator>
      <pubDate>Tue, 13 Oct 2026 02:53:40 +0000</pubDate>
      <link>https://dev.to/seosage/hreflang-the-audit-that-stops-your-pages-fighting-across-countries-1o2i</link>
      <guid>https://dev.to/seosage/hreflang-the-audit-that-stops-your-pages-fighting-across-countries-1o2i</guid>
      <description>&lt;p&gt;I work at SEOSage, which builds desktop SEO audit software. The steps below work with any crawler.&lt;/p&gt;

&lt;h2&gt;
  
  
  The wrong version of your page is ranking somewhere right now.
&lt;/h2&gt;

&lt;p&gt;Hreflang tells Google which language or regional version of a page to show to which audience. When it is wrong — or missing — the US page ranks in the UK, the English page outranks the German one in Berlin, and your own pages cannibalise each other across markets. Nobody notices until a regional manager asks why their page never shows up locally. This audit finds every hreflang error before that conversation.&lt;/p&gt;

&lt;h2&gt;
  
  
  How hreflang breaks
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Missing return links&lt;/strong&gt; — page A declares itself the alternate of page B, but page B does not declare A back. Google ignores hreflang without reciprocity. This is the single most common error.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wrong language or region codes&lt;/strong&gt; — &lt;code&gt;en-UK&lt;/code&gt; instead of &lt;code&gt;en-GB&lt;/code&gt;, made-up codes, or language-only tags where region-specific ones were needed. One wrong code and the whole cluster is suspect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No x-default&lt;/strong&gt; — without a fallback page for unmatched audiences, Google guesses. Declare one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hreflang on non-indexable pages&lt;/strong&gt; — tags pointing at noindexed URLs, canonicals pointing elsewhere, or pages that 404. Hreflang only works between live, indexable, self-canonical pages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conflicting signals&lt;/strong&gt; — hreflang says these pages are alternates while the canonical says they are all the same page. Google trusts the canonical and your hreflang is decoration.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The audit: crawl the tags, then verify the cluster
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Extract every hreflang tag.&lt;/strong&gt; Crawl the site and export all hreflang annotations: page URL, declared language/region, target URL. Sitemap-declared hreflang counts too — gather both, because mismatches between header tags and sitemap declarations are their own failure mode.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check reciprocity.&lt;/strong&gt; For every A→B declaration, confirm B→A exists. Build the cluster map: every page in a language cluster should reference every other page in that cluster. A spreadsheet pivot does this in minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate the codes.&lt;/strong&gt; Check every language and region code against the standard lists. Flag anything Google does not recognise, and flag language-only tags where the business actually serves distinct regions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify the targets are real.&lt;/strong&gt; Every hreflang target must return 200, be indexable, and carry a self-referencing canonical. A hreflang pointing at a redirect or a noindexed page is a dead signal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-check Search Console.&lt;/strong&gt; The International Targeting report (and the language report in newer GSC) shows which errors Google sees. Use it to confirm your crawl findings, not as the starting point.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Fix by cluster, not by tag
&lt;/h2&gt;

&lt;p&gt;Hreflang errors cluster by template: one wrong include file breaks every product page in a market. Fix the template or the sitemap generator, not individual tags. The usual order: fix the codes first (cheap, global), then reciprocity (template-level), then target validity (page-level), then add the missing x-default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prioritise by traffic
&lt;/h2&gt;

&lt;p&gt;Same habit as every audit: the broken cluster on the market that brings revenue outranks the one on a dormant locale. I overlay GA traffic on the crawl in SEOSage so the hreflang work lands where the visitors are — the same traffic-first habit, applied internationally. Any workflow that combines hreflang extraction with traffic gives you the same ordering.&lt;/p&gt;

&lt;h2&gt;
  
  
  The maintenance rule
&lt;/h2&gt;

&lt;p&gt;Hreflang rots when sites change: new locales launch without tags, pages get noindexed without updating the cluster, templates get replaced and the include disappears. Re-run the hreflang extraction after every site change involving locales, templates, or canonicals — and audit the full cluster map quarterly. International SEO is the last place you want silent failures.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I work at SEOSage, a desktop SEO audit tool. These steps work with any crawler you already use. Do your language versions all link back to each other?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Broken Links: The Audit That Protects Every Page You Have</title>
      <dc:creator>Kessy Stalford</dc:creator>
      <pubDate>Tue, 13 Oct 2026 02:28:11 +0000</pubDate>
      <link>https://dev.to/seosage/broken-links-the-audit-that-protects-every-page-you-have-1k81</link>
      <guid>https://dev.to/seosage/broken-links-the-audit-that-protects-every-page-you-have-1k81</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure: I work at SEOSage, a desktop SEO audit tool. These steps work with any crawler you already use. When did you last run a full status-code crawl of your site?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Duplicate Content: How to Find and Fix Pages Competing With Themselves</title>
      <dc:creator>Kessy Stalford</dc:creator>
      <pubDate>Mon, 12 Oct 2026 18:37:40 +0000</pubDate>
      <link>https://dev.to/seosage/duplicate-content-how-to-find-and-fix-pages-competing-with-themselves-3b99</link>
      <guid>https://dev.to/seosage/duplicate-content-how-to-find-and-fix-pages-competing-with-themselves-3b99</guid>
      <description>&lt;p&gt;I work at SEOSage, which builds desktop SEO audit software. The steps below work with any crawler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your pages should not compete with each other.
&lt;/h2&gt;

&lt;p&gt;Duplicate content rarely triggers a penalty — that is a myth for most sites. The real damage is quieter: when three near-identical pages exist, search engines split the ranking signals between them, pick a canonical you did not intend, and none of the versions ranks as well as one consolidated page would. This audit finds the internal competition and ends it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three kinds of duplication
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Exact duplicates&lt;/strong&gt; — the same page served at multiple URLs: trailing-slash variants, www vs non-www, HTTP vs HTTPS, uppercase vs lowercase, print versions. Usually a configuration problem, not a content one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Near-duplicates&lt;/strong&gt; — pages that differ only slightly: sorted and filtered views, paginated series, location pages with the city name swapped, tag pages echoing category pages. The most common and the hardest to see without a crawl.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thin duplicates&lt;/strong&gt; — pages with almost nothing unique: auto-generated tag archives, empty category shells, boilerplate service pages cloned per suburb. These dilute the site even when each URL is technically unique.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The audit: compare, don't guess
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Compare the metadata.&lt;/strong&gt; Export every title, meta description, and H1 from a full crawl. Sort by title: identical titles across different URLs are your first suspect list. Duplicate meta descriptions are the second. This one export catches most exact and template-level duplicates in minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the content.&lt;/strong&gt; For the suspect URLs, compare actual page content — many crawlers flag near-duplicate content with a similarity threshold. Focus on the template: if every location page is 95% identical, the fix is one content rewrite strategy, not fifty edits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Map the canonicals.&lt;/strong&gt; For each duplicate cluster, check where the canonical tag points. The most common finding: canonicals pointing at themselves on pages that should defer to a master version, or canonicals on pages Google has chosen to ignore because the content barely matches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-check Search Console.&lt;/strong&gt; The Page indexing report's "Duplicate, Google chose different canonical than user" and "Duplicate without user-selected canonical" entries confirm which clusters Google actually sees as duplicates — audit evidence, straight from the source.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Fix by cluster, not by URL
&lt;/h2&gt;

&lt;p&gt;Each cluster gets one decision:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consolidate&lt;/strong&gt; — one page should exist where three near-duplicates do. Pick the winner, move any unique value into it, and redirect the rest to it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Canonicalise&lt;/strong&gt; — when the duplicate URLs must stay live (sorted views, print pages), point every variant's canonical at the clean master URL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Differentiate&lt;/strong&gt; — when the pages deserve to exist separately (real location pages), give each genuinely unique content: local specifics, distinct services, original copy. Swapped city names are not unique content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remove&lt;/strong&gt; — thin auto-generated pages that serve no user get noindexed or deleted, with their internal links updated.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prioritise by traffic
&lt;/h2&gt;

&lt;p&gt;Consolidation touches rankings, so start where the stakes are: clusters containing pages that already bring visitors. I overlay GA traffic on the crawl in SEOSage so the duplicate clusters sort by traffic — the same traffic-first habit, applied to duplication. Merge the earning clusters first; the thin archives can wait their turn.&lt;/p&gt;

&lt;h2&gt;
  
  
  The maintenance rule
&lt;/h2&gt;

&lt;p&gt;Duplication regenerates. New plugins create new parameter views, new templates clone the old boilerplate, new locations get another swapped-city page. Re-run the title/meta comparison after every site change — it is the fastest tripwire in the whole audit set, and it catches new clusters before they split your signals again.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I work at SEOSage, a desktop SEO audit tool. These steps work with any crawler you already use. How many URLs on your site share the same title tag right now?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Schema Markup: How to Audit It Before Google Ignores It</title>
      <dc:creator>Kessy Stalford</dc:creator>
      <pubDate>Mon, 12 Oct 2026 18:28:39 +0000</pubDate>
      <link>https://dev.to/seosage/schema-markup-how-to-audit-it-before-google-ignores-it-3688</link>
      <guid>https://dev.to/seosage/schema-markup-how-to-audit-it-before-google-ignores-it-3688</guid>
      <description>&lt;p&gt;I work at SEOSage, which builds desktop SEO audit software. The steps below work with any crawler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Schema does not buy you rankings. It buys you eligibility.
&lt;/h2&gt;

&lt;p&gt;Structured data is not a ranking factor. It is a ticket to rich results — the review stars, prices, FAQ panels, and breadcrumbs that make your listing bigger on the search page. Most sites I audit have one of two problems: no schema where it obviously fits, or schema that is broken, misleading, or applied to pages where it can never win anything. Both waste the effort that went into writing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The audit: inventory first
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Crawl and inventory every schema type.&lt;/strong&gt; Extract all JSON-LD (and microdata) across the site: which pages carry schema, which types, which properties. You will usually find three things: templates that never got schema, templates with schema nobody maintains, and copy-pasted blocks from a plugin that do not match the page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check type-to-page fit.&lt;/strong&gt; Each page should carry the schema that matches what it is — Article for posts, Product for product pages, LocalBusiness for the location page, BreadcrumbList everywhere relevant. A Product schema on a blog post, or FAQ schema on a page Google no longer shows FAQ rich results for, is effort spent in the wrong place.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate every type.&lt;/strong&gt; Run representative URLs through Google's Rich Results Test. Fix invalid properties, missing required fields, and warnings on pages that matter. Warnings on low-traffic pages can wait — errors on the pages that earn cannot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Match schema to content.&lt;/strong&gt; The markup must describe what the page actually shows. Ratings with no visible reviews, prices that do not match the checkout, dates that expired years ago — this is how schema stops being eligible for rich results and starts looking like spam.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The common failures
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stale schema:&lt;/strong&gt; sale prices from two years ago, events that already happened, reviews from a retired product. Schema rots faster than content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plugin duplication:&lt;/strong&gt; two plugins injecting conflicting blocks on the same page. One source of truth per page type.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invisible markup:&lt;/strong&gt; FAQ schema answering questions that do not appear on the page, aggregate ratings with no reviews shown. Google treats this as misleading.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wrong bets:&lt;/strong&gt; schema types for rich results that no longer exist or never applied to the niche. Check what rich results your vertical actually gets before writing markup for them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prioritise by traffic
&lt;/h2&gt;

&lt;p&gt;Same habit as every audit: fix the pages that earn first. I overlay GA traffic on the crawl in SEOSage so the schema work lands on templates that already bring visitors — the product pages with stars missing, the articles with breadcrumbs absent. A perfect FAQ block on a page nobody visits is the last item on the list, not the first.&lt;/p&gt;

&lt;h2&gt;
  
  
  The maintenance rule
&lt;/h2&gt;

&lt;p&gt;Schema needs a review whenever content changes: new prices, new products, new posts, retired offers. Add schema to the publishing checklist — before a page goes live, the markup should be written, validated, and matched to what the page shows. And re-run the inventory after every template or plugin change; that is when duplicate blocks and stale markup sneak back in.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I work at SEOSage, a desktop SEO audit tool. These steps work with any crawler you already use. Which page on your site most obviously deserves schema it does not have?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Your Lab Scores Lie: An Audit Guide to Core Web Vitals That Actually Matter</title>
      <dc:creator>Kessy Stalford</dc:creator>
      <pubDate>Mon, 12 Oct 2026 18:21:44 +0000</pubDate>
      <link>https://dev.to/seosage/your-lab-scores-lie-an-audit-guide-to-core-web-vitals-that-actually-matter-5ge</link>
      <guid>https://dev.to/seosage/your-lab-scores-lie-an-audit-guide-to-core-web-vitals-that-actually-matter-5ge</guid>
      <description>&lt;p&gt;I work at SEOSage, which builds desktop SEO audit software. The steps below work with any crawler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Google ranks on field data. You are probably measuring lab data.
&lt;/h2&gt;

&lt;p&gt;Core Web Vitals come from real users — the Chrome User Experience Report, 75th percentile, over 28 days. Most audits I see start and end with a Lighthouse run: lab data, one machine, one network, no real users. Lab scores are a diagnostic tool, not the grade. This audit reads the field data first and only touches the lab to diagnose what the field says is broken.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three vitals, in plain terms
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;LCP (Largest Contentful Paint)&lt;/strong&gt; — how fast the main content appears. Under 2.5s is good. This is the one most sites fail, and it is almost always media and blocking resources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;INP (Interaction to Next Paint)&lt;/strong&gt; — how fast the page responds when a user clicks or taps. Under 200ms is good. Heavy JavaScript is the usual culprit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CLS (Cumulative Layout Shift)&lt;/strong&gt; — how much the page jumps around while loading. Under 0.1 is good. Unreserved image and ad slots, late-loading fonts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You do not need to memorise the thresholds. You need to know which template each failure lives on.&lt;/p&gt;

&lt;h2&gt;
  
  
  The audit: field first
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pull the field data.&lt;/strong&gt; Open PageSpeed Insights for your homepage, one key landing page, and one template page (product, article, category). Then open Search Console's Core Web Vitals report — it shows the same field data grouped by URL pattern, which tells you whether the problem is one page or a whole template.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Group by template.&lt;/strong&gt; If every blog post fails CLS, you fix the template once, not fifty pages. Template-level grouping is where this audit saves its time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diagnose in the lab.&lt;/strong&gt; Only now open Lighthouse — for the failing templates, to find the cause: unoptimized images, render-blocking scripts, font swaps, layout-shifting banners.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix the pattern.&lt;/strong&gt; Compress and properly size images, defer non-critical JS, reserve space for media and ads, preload the main font. One fix per template, verified in the lab, then rolled out.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Prioritise by traffic
&lt;/h2&gt;

&lt;p&gt;Not all failing templates matter equally. A slow blog archive nobody visits loses to a failing product template that brings revenue. I overlay GA traffic on my audits in SEOSage so the vitals work lands on the templates that earn first — the same traffic-first habit, applied to performance. Any workflow that combines URL-level vitals data with traffic gives you the same ordering.&lt;/p&gt;

&lt;h2&gt;
  
  
  The field-data lag
&lt;/h2&gt;

&lt;p&gt;Field data moves slowly — 28 days of real users. After you ship a fix, the lab improves immediately and the field report takes weeks. That is normal; do not roll back a working fix because Search Console has not caught up yet. Re-check the field report monthly, and re-run the lab right after every template change — that is when regressions are born.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I work at SEOSage, a desktop SEO audit tool. These steps work with any crawler you already use. When did you last check your field data instead of your Lighthouse score?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>performance</category>
    </item>
    <item>
      <title>Crawl Budget: The Audit That Gets More of Your Pages Crawled</title>
      <dc:creator>Kessy Stalford</dc:creator>
      <pubDate>Mon, 12 Oct 2026 17:59:32 +0000</pubDate>
      <link>https://dev.to/seosage/crawl-budget-the-audit-that-gets-more-of-your-pages-crawled-1nfj</link>
      <guid>https://dev.to/seosage/crawl-budget-the-audit-that-gets-more-of-your-pages-crawled-1nfj</guid>
      <description>&lt;h2&gt;
  
  
  &lt;em&gt;Disclosure: I work at SEOSage, a desktop SEO audit tool. These steps work with any crawler you already use. What share of your crawl would you guess is junk URLs?&lt;/em&gt;
&lt;/h2&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Internal Linking: How to Make Every Page Count</title>
      <dc:creator>Kessy Stalford</dc:creator>
      <pubDate>Mon, 12 Oct 2026 16:49:50 +0000</pubDate>
      <link>https://dev.to/seosage/internal-linking-how-to-make-every-page-count-2b8m</link>
      <guid>https://dev.to/seosage/internal-linking-how-to-make-every-page-count-2b8m</guid>
      <description>&lt;h2&gt;
  
  
  &lt;em&gt;Disclosure: I work at SEOSage, a desktop SEO audit tool. These steps work with any crawler you already use. How many clicks deep is your most important page?&lt;/em&gt;
&lt;/h2&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Stop Trusting Your Sitemap: How to Reconcile It With a Crawl</title>
      <dc:creator>Kessy Stalford</dc:creator>
      <pubDate>Mon, 12 Oct 2026 16:36:38 +0000</pubDate>
      <link>https://dev.to/seosage/stop-trusting-your-sitemap-how-to-reconcile-it-with-a-crawl-23be</link>
      <guid>https://dev.to/seosage/stop-trusting-your-sitemap-how-to-reconcile-it-with-a-crawl-23be</guid>
      <description>&lt;p&gt;I work at SEOSage, which builds desktop SEO audit software. The steps below work with any crawler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your sitemap says one thing. Your site says another.
&lt;/h2&gt;

&lt;p&gt;A sitemap is a declaration: "these are my important pages." A crawl is the evidence: "this is what is actually reachable." Most sites I look at have never reconciled the two. When I finally do the comparison for them, the gaps are always the same three buckets — and each bucket is an action list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bucket 1: In the sitemap, never crawled
&lt;/h2&gt;

&lt;p&gt;These URLs cannot be reached by following links from the homepage. Some are true orphans your navigation forgot. Some are pages behind crawl blocks — noindex rules, robots disallows, or login walls you did not intend.&lt;/p&gt;

&lt;p&gt;For each one, make a deliberate call: if the page matters, link to it from relevant pages. If it was retired, remove it from the sitemap and either let it 404/410 or redirect it to the closest live equivalent. The worst choice is doing nothing — a URL you declare but nobody can reach teaches crawlers to distrust your sitemap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bucket 2: Crawled, not in the sitemap
&lt;/h2&gt;

&lt;p&gt;Most of these are fine — ordinary pages your navigation reaches. But scan the list for what should never be indexed: staging leftovers, parameter duplicates, thin archive and tag pages, old campaign landing pages. Being crawled is the first step toward being indexed, so this bucket is where index bloat is born.&lt;/p&gt;

&lt;p&gt;The fix is not to add everything to the sitemap. It is to clean the crawlable site: noindex or block what should not be indexed, and keep the sitemap to pages that genuinely deserve to rank.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bucket 3: Indexed, in neither list
&lt;/h2&gt;

&lt;p&gt;Google found these through external links — old URLs, moved pages, retired campaigns. You did not declare them and your crawl cannot reach them, but they are in the index anyway.&lt;/p&gt;

&lt;p&gt;Do not just add them to the sitemap to make the lists match. That bakes the mess into your declaration. Decide deliberately: redirect to the closest live page or let them go. A sitemap should contain only URLs that return 200, are indexable, and are the canonical version.&lt;/p&gt;

&lt;h2&gt;
  
  
  The reconciliation habit
&lt;/h2&gt;

&lt;p&gt;A sitemap should be generated from the same system that builds the site, not maintained by hand — and it should be reconciled against a crawl after every redesign, migration, or CMS change. That is when the three buckets fill up: new templates create crawlable pages that never make it into the sitemap, and retired pages linger in the sitemap long after they stopped being reachable.&lt;/p&gt;

&lt;p&gt;I do the reconciliation in SEOSage — it can crawl a sitemap directly and flag sitemap URLs that redirect or error alongside crawl-only and orphan URLs, with GA traffic overlaid so I fix the buckets in traffic order. Any crawler that supports sitemap crawl and orphan detection gives you the same three lists; the point is the comparison, not the tool.&lt;/p&gt;

&lt;p&gt;Once the lists agree, most of the "mystery" problems people chase — pages that never get indexed, sitemap warnings that never go away, crawl budget spent on junk — tend to disappear on their own.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I work at SEOSage, a desktop SEO audit tool. These steps work with any crawler you already use. When was the last time you compared your sitemap against an actual crawl?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Redirect Chains: The Slow Leak in Your Site's Link Equity</title>
      <dc:creator>Kessy Stalford</dc:creator>
      <pubDate>Mon, 12 Oct 2026 10:05:35 +0000</pubDate>
      <link>https://dev.to/seosage/redirect-chains-the-slow-leak-in-your-sites-link-equity-2g6p</link>
      <guid>https://dev.to/seosage/redirect-chains-the-slow-leak-in-your-sites-link-equity-2g6p</guid>
      <description>&lt;p&gt;I work at SEOSage, which builds desktop SEO audit software. The steps below work with any crawler.&lt;/p&gt;




&lt;h2&gt;
  
  
  The crawl report says "redirect chain" and you ignore it
&lt;/h2&gt;

&lt;p&gt;If you have ever run a site crawl and scrolled past a long list of redirect chains thinking "they resolve, so they work," you are not alone. Redirects do work for users — the browser eventually lands somewhere. The problem is quieter: every extra hop costs you. It costs crawl budget, because the crawler has to fetch two, three, or four URLs to see one page. It costs link equity, because the signal from external links decays a little with each hop. And on big sites it costs something harder to see — your internal links, your sitemap, and your actual site disagree about where the real pages live.&lt;/p&gt;

&lt;p&gt;A chain is any URL that redirects more than once: &lt;code&gt;/blog/old-post&lt;/code&gt; → &lt;code&gt;/blog/new-post&lt;/code&gt; → &lt;code&gt;/2024/blog/new-post&lt;/code&gt; → final URL. One redirect is normal. Two is a smell. Three or more is a leak you should fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where chains come from
&lt;/h2&gt;

&lt;p&gt;They are rarely made on purpose. They accumulate:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;HTTP to HTTPS plus www to non-www plus trailing-slash cleanup&lt;/strong&gt; — stack three "harmless" rules and every old link starts with a 3-hop journey.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Site redesigns&lt;/strong&gt; — old URLs were redirected to new ones, then the new ones got redirected again in the next redesign. Nobody goes back and shortens the old rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal links that were never updated&lt;/strong&gt; — the site itself keeps linking to the old URLs, so Google keeps discovering them and crawling the full chain every time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That third one is the most common cause on sites that "fixed" their redirects years ago. The redirect rules are fine; the links are stale.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to find them
&lt;/h2&gt;

&lt;p&gt;Crawl the site and pull the redirect report. For every chain, record three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;start URL&lt;/strong&gt; — where the chain begins (this is what your site or someone else still links to).&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;final URL&lt;/strong&gt; — where the chain lands. This is the real page. Everything should point here.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;hop count&lt;/strong&gt; — anything over one hop is worth reviewing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then sort by traffic. Fixing a 4-hop chain on a page that earns visits matters; a chain on a page nobody visits can wait. This is exactly why I overlay GA traffic on crawl data in SEOSage — the fix list gets sorted by pages that already bring business, and I can see at a glance which chains are worth the edit. Any crawler that exports a redirect report gives you the raw data; the traffic overlay just decides the order.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to fix them, permanently
&lt;/h2&gt;

&lt;p&gt;There are two fixes, and you need both:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Update the links.&lt;/strong&gt; Change your internal links and your sitemap to point at the final URL. The chain becomes almost irrelevant for internal traffic because nothing starts it. This is the fix people skip — they fix the redirect rules and leave the stale links, so the chain keeps getting crawled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Shorten the rule.&lt;/strong&gt; Where a chain starts from an old URL you still control (a legacy path, an old domain), point the rule directly at the final URL. &lt;code&gt;/blog/old-post&lt;/code&gt; should go straight to the final destination, not through two intermediate versions.&lt;/p&gt;

&lt;p&gt;After both, re-crawl. A proper fix shows as: zero chains with more than one hop on URLs your site actually links to. I re-run the redirect report in SEOSage after the changes because it flags any chain longer than one hop and shows start → final, so I can confirm every chain collapsed to a single redirect. Any crawler with a redirect report works for the same confirmation — the point is to verify, not to trust the fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one-hop rule
&lt;/h2&gt;

&lt;p&gt;From now on, treat it as a house rule: &lt;strong&gt;internal links always point at the final URL, and no chain may exceed one hop.&lt;/strong&gt; It is a five-minute habit when you add or move a page, and it stops the slow leak before it starts.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I work at SEOSage, a desktop SEO audit tool. These steps work with any crawler you already use. What tool do you use to check your redirect chains?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Orphan Pages: How to Find and Fix Pages Nothing Links To</title>
      <dc:creator>Kessy Stalford</dc:creator>
      <pubDate>Sat, 10 Oct 2026 05:08:19 +0000</pubDate>
      <link>https://dev.to/seosage/orphan-pages-how-to-find-and-fix-pages-nothing-links-to-2iih</link>
      <guid>https://dev.to/seosage/orphan-pages-how-to-find-and-fix-pages-nothing-links-to-2iih</guid>
      <description>&lt;p&gt;An orphan page is a page on your site that no other page on your site links to. Search engines can still find some of them through your sitemap or external links, but visitors browsing your site never will — and crawlers deprioritise pages that nothing points at.&lt;/p&gt;

&lt;p&gt;The good news: finding orphans takes about fifteen minutes with any desktop crawler. Fixing them takes longer, but the fix is a decision, not a technical trick.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclosure: I work with SEOSage, a desktop SEO crawler.&lt;/strong&gt; Everything in this guide works in any crawler that reports internal links, including free ones. Delete every tool name and the process still works.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What you need
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A desktop crawler&lt;/strong&gt; that reports inlinks (links from your own pages to each page). SEOSage is the one I use day to day — a desktop crawler for Mac and Windows with unlimited local crawls on a flat $19/month or $149/year licence, which matters here because an orphan check is only trustworthy on a complete crawl. Screaming Frog SEO Spider (free up to 500 URLs) or Sitebulb (trial) work too, as long as the crawl covers the whole section you're checking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your XML sitemap URL&lt;/strong&gt; — usually &lt;code&gt;/sitemap.xml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A spreadsheet&lt;/strong&gt; with columns: URL / Inlinks / Decision / Done?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 1: Crawl the site
&lt;/h2&gt;

&lt;p&gt;Run a standard internal crawl of your homepage with default settings. When it finishes, you need one number per URL: how many internal pages link to it.&lt;/p&gt;

&lt;p&gt;Most crawlers show this as an "Inlinks" column in the internal tab. Export the full list of crawled URLs with their inlink counts to your spreadsheet.&lt;/p&gt;

&lt;p&gt;Watch out for one trap: if your crawl is incomplete (you stopped it early, or your site is bigger than a free tier's URL cap), pages outside the crawled section will look like orphans when they aren't. Either crawl the whole site or crawl section by section (&lt;code&gt;/blog/&lt;/code&gt;, &lt;code&gt;/products/&lt;/code&gt;, etc.) and note which sections each orphan result actually covers. SEOSage now guards against this in the tool itself: it only reports orphan pages after a full crawl, and on a crawl stopped early it holds the orphan list back and notes why, instead of presenting partial inlink data as orphans.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Find the zero-inlink pages
&lt;/h2&gt;

&lt;p&gt;Sort your export by inlinks, ascending. The rows with &lt;strong&gt;0 inlinks&lt;/strong&gt; are your orphan candidates.&lt;/p&gt;

&lt;p&gt;Now cross-check against your sitemap:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fetch your sitemap (your crawler can usually crawl a sitemap directly, or download it and open it in a text editor).&lt;/li&gt;
&lt;li&gt;List every URL in the sitemap that does &lt;strong&gt;not&lt;/strong&gt; appear in your crawl at all. These are true orphans — pages that exist, are declared in your sitemap, but are not reachable by following links from your homepage. They are often the most important finds: old landing pages, forgotten campaign pages, or content that got unlinked in a redesign.&lt;/li&gt;
&lt;li&gt;Merge both lists (0-inlink crawled pages + sitemap-only pages) into one candidate list.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before you act, filter out pages that are &lt;em&gt;supposed&lt;/em&gt; to be unlinked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Thank-you / confirmation pages after form submissions&lt;/li&gt;
&lt;li&gt;Checkout and account pages&lt;/li&gt;
&lt;li&gt;Staging, test, or admin URLs that leaked into the sitemap (fix the sitemap, not the links)&lt;/li&gt;
&lt;li&gt;Deliberate landing pages fed only by ads or email, where you do not want organic visitors wandering in from elsewhere on the site — these are fine, but write "intentional" in your Decision column so future-you does not "fix" them again&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: Decide — keep, link, redirect, or remove
&lt;/h2&gt;

&lt;p&gt;Every remaining orphan gets exactly one decision:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep and link (the default).&lt;/strong&gt; The page has real content someone might want. Add links to it from the most relevant pages: the parent category page, a related article, or a "resources" hub. Two or three contextual links from genuinely related pages beat one link dumped in a footer. Write anchor text that describes the page, not "click here."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redirect.&lt;/strong&gt; The page is outdated or duplicated, but its URL may have external links or bookmarks. Redirect it (301) to the closest matching live page. Check first that the target is a 200 page, not another redirect — do not create chains.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remove.&lt;/strong&gt; The page has no value, no traffic, and no external links. Delete it, let it return a proper 404 (or 410), and remove it from the sitemap. A clean 404 for a worthless page is not an SEO problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep unlinked (rare, deliberate).&lt;/strong&gt; Only for the intentional cases above — and only if they are also excluded from the sitemap, or you accept that the sitemap is telling Google the page matters while your links say it does not. That mixed signal is why most accidental orphans underperform.&lt;/p&gt;

&lt;p&gt;How to choose quickly: open each orphan and ask, "If a visitor landed here from Google, would this page help them?" Yes → link it. Was yes once → redirect it. Never → remove it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Fix the sitemap while you are here
&lt;/h2&gt;

&lt;p&gt;Your sitemap should list only pages that return 200, are indexable, and are the canonical version of themselves. While you have the crawl open:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remove sitemap URLs that redirect (list the final destination instead)&lt;/li&gt;
&lt;li&gt;Remove sitemap URLs with a &lt;code&gt;noindex&lt;/code&gt; tag or blocked by robots.txt — sending Google a URL and telling it not to index or crawl it is a contradiction&lt;/li&gt;
&lt;li&gt;Add any important page you just rescued from orphan status, if your sitemap is manual&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your sitemap is auto-generated by your CMS, fix the source (the page status or settings), not the file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Re-crawl and verify
&lt;/h2&gt;

&lt;p&gt;Wait until your link changes are live, then re-crawl the same scope as Step 1 and re-export the inlink counts.&lt;/p&gt;

&lt;p&gt;Check three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Every page you decided to "link" now has at least 1 inlink — ideally 2–3.&lt;/li&gt;
&lt;li&gt;Every redirect you created lands directly on a 200 page in one hop.&lt;/li&gt;
&lt;li&gt;Your orphan count dropped to only the intentional ones.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Diff the two exports. If a "fixed" page still shows 0 inlinks, the link you added is probably on a page outside the crawl scope, behind JavaScript your crawl did not render, or pointing at a URL variant (trailing slash, &lt;code&gt;www&lt;/code&gt; vs non-&lt;code&gt;www&lt;/code&gt;) that is not the canonical one. Fix the link target to the exact canonical URL.&lt;/p&gt;

&lt;h2&gt;
  
  
  A realistic timetable
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Under 500 pages:&lt;/strong&gt; one sitting, start to finish.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;500–5,000 pages:&lt;/strong&gt; crawl and analysis in one sitting; link fixes spread over a few days because they are small content edits, not one bulk action.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bigger than that:&lt;/strong&gt; work section by section; directories (folders) usually share templates, so fixing one category page often rescues a whole group of orphans at once.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mistake to avoid is treating this as a one-time cleanup. Every redesign, migration, or menu change creates new orphans. Add "re-run the orphan check" to whatever checklist you already use after site changes, and it stays a fifteen-minute job instead of becoming an archaeological dig.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick recap
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Crawl the site; export URLs with inlink counts.&lt;/li&gt;
&lt;li&gt;Zero-inlink pages + sitemap-only pages = your orphan candidates.&lt;/li&gt;
&lt;li&gt;Exclude intentional unlinked pages (thank-you, checkout, ad-only landers).&lt;/li&gt;
&lt;li&gt;Decide per page: link it, redirect it, remove it, or deliberately leave it.&lt;/li&gt;
&lt;li&gt;Clean the sitemap: 200, indexable, canonical URLs only.&lt;/li&gt;
&lt;li&gt;Re-crawl and diff to verify every fix actually landed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do this once and your internal linking stops having silent dead ends — which usually does more for the pages you already have than publishing new ones on top of a broken structure.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Stop Fixing SEO Issues in the Order Your Crawler Lists Them</title>
      <dc:creator>Kessy Stalford</dc:creator>
      <pubDate>Wed, 07 Oct 2026 08:25:59 +0000</pubDate>
      <link>https://dev.to/seosage/stop-fixing-seo-issues-in-the-order-your-crawler-lists-them-1j3i</link>
      <guid>https://dev.to/seosage/stop-fixing-seo-issues-in-the-order-your-crawler-lists-them-1j3i</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; I work with SEOSage, one of the tools mentioned near the end of this post. Everything before that section is tool-agnostic, and the workflow below works with a free crawler, a spreadsheet, and Google Search Console. I've tried to write this so it's still useful if you delete every mention of SEOSage — because it should be.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every SEO crawler hands you the same thing: a long, intimidating list of issues, sorted by how the tool happens to organise them. Missing titles. Duplicate H1s. Redirect chains. Images without alt text. Pages with thin content.&lt;/p&gt;

&lt;p&gt;And almost everyone — myself included, for longer than I'd like to admit — starts at the top of that list and works down.&lt;/p&gt;

&lt;p&gt;That's the problem. Your crawler's list order is an accident of how the software groups issues. It has nothing to do with money, traffic, or what a visitor experiences today. A broken page nobody has visited in six months sits in the same list, with the same visual weight, as the landing page that earns you leads every single day and currently returns a 404 to half the people tapping your ad.&lt;/p&gt;

&lt;p&gt;This post is about reordering that list by the one thing that actually matters: &lt;strong&gt;whether anyone is trying to use the page.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The real cost of list-order fixing
&lt;/h2&gt;

&lt;p&gt;When you fix issues in crawler order, three things tend to happen:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;You burn hours on invisible pages.&lt;/strong&gt; Old tag archives, forgotten campaign landers, staging leftovers that somehow got indexed. Technically broken, practically irrelevant.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The urgent stuff waits.&lt;/strong&gt; The money page with the redirect loop, the pricing page dropping out of the index, the checkout-adjacent page with the rendering problem. They were on page three of your export.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clients and stakeholders can't see the point.&lt;/strong&gt; "We fixed 1,400 issues" is a vanity metric. "We fixed the 11 pages people actually land on" is a result.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Traffic-first prioritisation flips the sequence: crawl everything, find out which broken pages people are actually reaching (or trying to reach), fix those first, then sweep the rest in descending order of real-world impact.&lt;/p&gt;

&lt;p&gt;Here's the full workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Crawl the whole site, not a sample
&lt;/h2&gt;

&lt;p&gt;Start with a complete crawl. If your site is small, this is trivial. If it's large, crawl in sections — templates, folders, subdomains — but make sure the union of your sections covers everything, including the dusty corners. You can't prioritise what you never crawled.&lt;/p&gt;

&lt;p&gt;Capture, at minimum, for every URL:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Status code (200, 301, 404, 500, etc.)&lt;/li&gt;
&lt;li&gt;Indexability (indexable, noindex, blocked by robots, canonicalised elsewhere)&lt;/li&gt;
&lt;li&gt;Title and H1 presence/duplication&lt;/li&gt;
&lt;li&gt;Redirect chains and loops&lt;/li&gt;
&lt;li&gt;Inlinks (how many internal links point to the page)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One honest limitation: a crawler only sees what it can reach. Orphan pages with zero inlinks won't show up unless you feed the crawler extra URL lists. Pull URLs from your XML sitemap, your CMS export, or last year's crawl and add them as a supplementary list. The pages nobody links to and nobody visits are exactly the ones you may later decide to delete — but decide that on purpose, not by accident.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Get your traffic data into the same table
&lt;/h2&gt;

&lt;p&gt;Now export two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google Search Console&lt;/strong&gt; → Pages report (clicks and impressions per landing page, last 90 days is a good window)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Analytics (GA4)&lt;/strong&gt; → Landing page report (sessions/engagement per page), if you have it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Join them to your crawl data on the URL. In a spreadsheet that's a &lt;code&gt;VLOOKUP&lt;/code&gt;/&lt;code&gt;XLOOKUP&lt;/code&gt; on a normalised URL (strip trailing slashes and tracking parameters first, or your match rate will be miserable).&lt;/p&gt;

&lt;p&gt;You now have, for every page: what's wrong with it &lt;em&gt;and&lt;/em&gt; whether anyone cares.&lt;/p&gt;

&lt;p&gt;If you have no analytics access — a prospect's site, a brand-new domain — Search Console alone is a perfectly good traffic proxy. No traffic data at all? Fall back to inlinks as a rough importance signal: heavily internally-linked pages tend to be the ones the business cares about. But treat that as a distant second choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Sort by "broken × visited"
&lt;/h2&gt;

&lt;p&gt;Create a simple priority view:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Priority&lt;/th&gt;
&lt;th&gt;Condition&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P0 — fix today&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Error (4xx/5xx) or not indexable, &lt;strong&gt;and&lt;/strong&gt; has sessions/clicks in the last 90 days&lt;/td&gt;
&lt;td&gt;Real people are hitting a dead end &lt;em&gt;right now&lt;/em&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P1 — this week&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Redirect chain, wrong canonical, or duplicate title on a page with traffic&lt;/td&gt;
&lt;td&gt;Visited pages leaking equity or confusing Google&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P2 — batch it&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Issues on pages with impressions but few/no clicks&lt;/td&gt;
&lt;td&gt;Google shows them; users don't pick them. Fix after P1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P3 — backlog/delete&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Issues on pages with zero traffic and zero impressions&lt;/td&gt;
&lt;td&gt;Fix cheaply, noindex, or remove. Don't gold-plate these&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This table is the entire method. Everything else is execution detail.&lt;/p&gt;

&lt;p&gt;The first time you do this, the P0 list is usually shockingly short — five to fifteen URLs on most sites — and shockingly important. I have seen a single redirect-looping service page, quietly eating paid and organic landings for weeks, surface instantly the moment traffic was overlaid on the crawl. In list-order world, it was issue #1,204.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Fix in priority order, then re-crawl
&lt;/h2&gt;

&lt;p&gt;Work P0 down. For each fix, note what changed and when. Then re-crawl and &lt;strong&gt;diff&lt;/strong&gt;: confirm the status code changed, the canonical points where you intended, the chain collapsed to a single hop.&lt;/p&gt;

&lt;p&gt;Re-crawling is the step people skip, and it's the only one that proves anything. "We changed it in the CMS" is not verification. Your crawler showing a clean 200 on the previously-broken money page is.&lt;/p&gt;

&lt;p&gt;Then move to P1. P3 pages get a deliberate decision — fix, noindex, redirect to something relevant, or delete — rather than another pass of cosmetic repairs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Doing this with whatever tool you already have
&lt;/h2&gt;

&lt;p&gt;You do not need new software for this workflow. Honestly, a spreadsheet and forty minutes will get most sites 80% of the value.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;How the traffic overlay happens&lt;/th&gt;
&lt;th&gt;Watch out for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Screaming Frog (free or paid)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Crawl, then connect the GA4/GSC APIs (Configuration → API Access) or export CSVs and join in Sheets/Excel&lt;/td&gt;
&lt;td&gt;Free tier caps at 500 URLs; URL normalisation before joining&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sitebulb&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Crawl with GA/GSC data sources enabled in project settings, then filter reports by traffic&lt;/td&gt;
&lt;td&gt;Schedule crawls so the overlay doesn't go stale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;SEOSage&lt;/strong&gt; &lt;em&gt;(disclosure: my employer)&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;GA connection pulls sessions onto each crawled page; sort/filter the page list by traffic so broken-but-visited rows float up&lt;/td&gt;
&lt;td&gt;Desktop app: crawl runs on your machine, so big crawls need the laptop plugged in and awake&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pure spreadsheet&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Crawl export + GSC Pages export + &lt;code&gt;XLOOKUP&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Slowest, but zero cost and you learn your data intimately&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Pick the row you already own. The method is identical; only the join mechanics differ.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this changes in practice
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Your reports get shorter and better.&lt;/strong&gt; Instead of "2,300 issues found," you report "9 visited pages were broken; all 9 fixed and verified; next batch is 40 redirect chains on pages with impressions." Stakeholders understand that sentence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your crawl budget conversations get easier.&lt;/strong&gt; Pages with zero traffic, zero impressions, and zero inlinks are candidates for removal, which shrinks the site Google has to crawl and stops those URLs diluting your reports forever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You stop being afraid of the list.&lt;/strong&gt; A 10,000-issue crawl export is paralysing. A P0 list of 11 URLs is a Tuesday morning.&lt;/p&gt;

&lt;h2&gt;
  
  
  A quick start for this week
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Run one full crawl of your main site. Save the export; don't touch anything yet.&lt;/li&gt;
&lt;li&gt;Export 90 days of GSC landing page clicks/impressions.&lt;/li&gt;
&lt;li&gt;Join them. Normalise URLs first.&lt;/li&gt;
&lt;li&gt;Filter: status ≠ 200 (or non-indexable) &lt;strong&gt;and&lt;/strong&gt; clicks &amp;gt; 0. That's your P0.&lt;/li&gt;
&lt;li&gt;Fix those, re-crawl, confirm.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the P0 list comes back empty: genuinely good news, and now you know it instead of guessing.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure restated: I work with SEOSage. This post describes a workflow, not a pitch — it runs fine in Screaming Frog, Sitebulb, or a spreadsheet. SEOSage's angle on it is that GA traffic sits next to each crawled page so the sort in Step 3 is built in rather than a manual join, and crawls run locally on your Mac or Windows machine without a page cap. If the manual join doesn't bother you, you lose nothing by ignoring that entirely.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Found a broken-but-visited page this way that surprised you? I'd genuinely like to hear what it was in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to Run Your First Technical SEO Audit (Free Checklist, Any Crawler)</title>
      <dc:creator>Kessy Stalford</dc:creator>
      <pubDate>Mon, 05 Oct 2026 05:12:55 +0000</pubDate>
      <link>https://dev.to/seosage/how-to-run-your-first-technical-seo-audit-free-checklist-any-crawler-184b</link>
      <guid>https://dev.to/seosage/how-to-run-your-first-technical-seo-audit-free-checklist-any-crawler-184b</guid>
      <description>&lt;h1&gt;
  
  
  How to Run Your First Technical SEO Audit (Free Checklist, Any Crawler)
&lt;/h1&gt;

&lt;p&gt;Your site is live, traffic is flat, and someone told you to "run a technical audit." That usually means opening a crawler, staring at 40 tabs of issues, and fixing things in whatever order the tool lists them.&lt;/p&gt;

&lt;p&gt;Don't do that. Run the audit in this order instead — it takes about an hour on a small site, and you only need a free crawler to do it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclosure: I work with SEOSage, one of the desktop crawlers listed here.&lt;/strong&gt; Everything below works in any crawler, including the free ones. Skip the comparison table entirely and the checklist still does the job.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What you need before you start
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A desktop crawler.&lt;/strong&gt; Screaming Frog SEO Spider (free up to 500 URLs), Sitebulb (free trial), or any equivalent that runs on your own machine. Desktop crawlers run locally, so there's no upload queue and no per-page metering while you learn.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Search Console access&lt;/strong&gt; for the site (free, and you'll use it to cross-check the crawl).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A spreadsheet&lt;/strong&gt; to log what you found and what you changed. A simple sheet with URL / Issue / Fixed? columns is enough.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An hour with no meetings.&lt;/strong&gt; Audits get abandoned halfway more often than they get finished.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 1: Crawl the site
&lt;/h2&gt;

&lt;p&gt;Open your crawler, paste in your homepage URL, and start with the default configuration. For a first audit you don't need JavaScript rendering, external link checking, or API integrations turned on. A plain crawl of internal HTML pages is the right scope.&lt;/p&gt;

&lt;p&gt;While it runs, note three numbers at the end: total URLs found, how many returned a 200 status, and how many were redirects or errors. Those three numbers are your baseline. Every fix below moves one of them.&lt;/p&gt;

&lt;p&gt;If your site is bigger than your free crawler's limit, crawl in sections: homepage plus one directory at a time (for example &lt;code&gt;/blog/&lt;/code&gt;, then &lt;code&gt;/products/&lt;/code&gt;). The checklist works the same on a partial crawl — you just repeat it per section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Check status codes
&lt;/h2&gt;

&lt;p&gt;Filter your crawl to non-200 responses and work through them in this order:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5xx errors (server errors).&lt;/strong&gt; These are the only truly urgent ones. A 500 means the page is down for everyone, including Google. Fix the server issue or restore the page before anything else on this list.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;404s (not found).&lt;/strong&gt; For each broken URL ask two questions: does anything internal link to it, and did it used to have content? If it had content and internal links, either restore the page or redirect it to the closest equivalent. If it never had content and nothing links to it, leave it — a clean 404 is fine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redirects (3xx).&lt;/strong&gt; A single redirect is not a problem. Chains are. Sort by redirect chain length and flatten anything with two or more hops so every old URL lands directly on the final page. Look specifically for loops (A → B → A), which crawlers flag clearly and browsers handle badly.&lt;/p&gt;

&lt;p&gt;Write every fix into your spreadsheet as you go. Do not trust yourself to remember which 404 you decided to leave alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Check indexability
&lt;/h2&gt;

&lt;p&gt;A page can return a perfect 200 and still be invisible to Google. In your crawl, check three signals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;noindex&lt;/code&gt; tags.&lt;/strong&gt; Look for pages carrying a meta robots &lt;code&gt;noindex&lt;/code&gt; or an &lt;code&gt;X-Robots-Tag: noindex&lt;/code&gt; header. On a first audit, most of these are staging leftovers or a theme default someone forgot to remove. Every important page — homepage, services, products, key articles — should be indexable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;robots.txt blocks.&lt;/strong&gt; Check whether any important directory is disallowed. Crawlers show this as "blocked by robots.txt." A blocked page can't be crawled, so Google only sees it if other sites link to it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Canonical tags.&lt;/strong&gt; Each page should either canonical to itself or deliberately point at a preferred version. Watch for: canonicals pointing to the homepage from every page (a classic plugin misconfiguration), canonicals pointing at redirected URLs, and missing canonicals on paginated or parameter versions of pages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cross-check in Search Console under &lt;strong&gt;Pages → Why pages aren’t indexed&lt;/strong&gt;. If the crawler and Search Console disagree, believe Search Console about what Google actually did, and use the crawler to find the cause.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Check titles and headings
&lt;/h2&gt;

&lt;p&gt;Filter for these four problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Missing title tags.&lt;/strong&gt; Usually templates that were never finished.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Duplicate titles.&lt;/strong&gt; Often product or category pages generated from the same template. Rewrite the worst offenders manually; fix the template for the rest.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Missing or multiple H1s.&lt;/strong&gt; One H1 per page that matches what the page is actually about. Multiple H1s aren't a disaster, but a missing H1 usually means a heading structure problem worth fixing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overly long titles.&lt;/strong&gt; Anything much over ~60 characters gets truncated in results. Shorten the ones on pages you actually want clicked — don't churn through all of them.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do not rewrite every title on the site in one sitting. Fix missing and duplicate first; they carry the most weight for the least effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Check internal linking and orphan pages
&lt;/h2&gt;

&lt;p&gt;Internal links are how both visitors and crawlers distribute attention around your site. Look for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Orphan pages:&lt;/strong&gt; URLs with zero internal links pointing to them. Crawlers compute this from the crawl itself; Search Console also lists some under "Alternate page" reports. If a page matters, link to it from a relevant parent page. If it doesn't matter, consider removing it rather than leaving it stranded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pages buried too deep:&lt;/strong&gt; anything more than 3–4 clicks from the homepage tends to get crawled rarely and ranked weakly. Flatten where it makes sense for humans, not just bots.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Broken internal links:&lt;/strong&gt; every internal link pointing at a 404 or a redirect chain is wasted. Your status-code work in Step 2 gives you the target list; now fix the source links.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 6: Compare sitemap vs crawl
&lt;/h2&gt;

&lt;p&gt;Your XML sitemap is a promise; your crawl is the reality. Compare the two lists:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In sitemap but not crawlable&lt;/strong&gt; (404, redirected, noindexed): remove or fix. A sitemap full of dead URLs wastes crawl attention and signals neglect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Crawlable and important but not in sitemap:&lt;/strong&gt; add it, especially new sections the sitemap generator missed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redirected URLs in the sitemap:&lt;/strong&gt; update them to the final destination URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Search Console, submit the cleaned sitemap and note the date. Sitemap fixes are boring and genuinely effective — this is the step people skip that shouldn't be skipped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Re-crawl and diff
&lt;/h2&gt;

&lt;p&gt;A week after your fixes (or immediately, for status-code fixes), crawl again with the same configuration and compare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Total non-200s down?&lt;/li&gt;
&lt;li&gt;Redirect chains flattened?&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;noindex&lt;/code&gt; only where you intended it?&lt;/li&gt;
&lt;li&gt;Sitemap and crawl now matching?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This before/after diff is your report. If you do audits for clients, this comparison — not the raw issue count — is what demonstrates the work. If it's your own site, the diff tells you whether to keep going down this checklist or move to content work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which crawler should you use?
&lt;/h2&gt;

&lt;p&gt;Any desktop crawler that runs locally will do this whole checklist. The honest differences:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Free tier&lt;/th&gt;
&lt;th&gt;Practical note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Screaming Frog SEO Spider&lt;/td&gt;
&lt;td&gt;Mac, Windows, Linux&lt;/td&gt;
&lt;td&gt;Free up to 500 URLs&lt;/td&gt;
&lt;td&gt;The long-standing default; paid licence removes the cap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sitebulb&lt;/td&gt;
&lt;td&gt;Mac, Windows&lt;/td&gt;
&lt;td&gt;Trial&lt;/td&gt;
&lt;td&gt;Strong visual reports and prioritised hints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEOSage&lt;/td&gt;
&lt;td&gt;Mac, Windows&lt;/td&gt;
&lt;td&gt;14-day trial&lt;/td&gt;
&lt;td&gt;Desktop crawler with unlimited local crawls and traffic data overlaid on issues&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Disclosure again, since one row is mine: I work with SEOSage. Pick based on your OS, site size, and whether the free cap covers you — the checklist above is identical in all three.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your first-audit recap
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Crawl with defaults; note your baseline numbers.&lt;/li&gt;
&lt;li&gt;Fix 5xx, then 404s, then flatten redirect chains and loops.&lt;/li&gt;
&lt;li&gt;Remove accidental &lt;code&gt;noindex&lt;/code&gt; and robots blocks; sanity-check canonicals.&lt;/li&gt;
&lt;li&gt;Fix missing/duplicate titles and broken heading structure.&lt;/li&gt;
&lt;li&gt;Link or remove orphan pages; fix broken internal links.&lt;/li&gt;
&lt;li&gt;Clean the sitemap so it matches reality.&lt;/li&gt;
&lt;li&gt;Re-crawl and diff to prove it worked.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Run this once a quarter and after any site migration, redesign, or traffic drop you can't explain. The first pass takes an hour; later passes take twenty minutes because you're mostly reading the diff.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Have a step you always add to a first audit? I'd genuinely like to hear it in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
