<?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: Sandeep Singh</title>
    <description>The latest articles on DEV Community by Sandeep Singh (@sandeepsingh_uchik).</description>
    <link>https://dev.to/sandeepsingh_uchik</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%2Fuser%2Fprofile_image%2F4192364%2F8c1c4592-3fa5-47df-865c-f4a21525e309.png</url>
      <title>DEV Community: Sandeep Singh</title>
      <link>https://dev.to/sandeepsingh_uchik</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sandeepsingh_uchik"/>
    <language>en</language>
    <item>
      <title>Automating Website Monitoring: What to Check Daily vs Weekly vs Monthly</title>
      <dc:creator>Sandeep Singh</dc:creator>
      <pubDate>Sun, 18 Oct 2026 15:59:46 +0000</pubDate>
      <link>https://dev.to/sandeepsingh_uchik/automating-website-monitoring-what-to-check-daily-vs-weekly-vs-monthly-bd3</link>
      <guid>https://dev.to/sandeepsingh_uchik/automating-website-monitoring-what-to-check-daily-vs-weekly-vs-monthly-bd3</guid>
      <description>&lt;p&gt;Most websites aren't monitored at all. Or they're "monitored" by whoever happens to notice something odd, which usually means a customer emailing to say the checkout doesn't work, a week after it stopped working.&lt;/p&gt;

&lt;p&gt;The opposite problem is just as real. Teams that set up alerts for everything soon learn to ignore them, and an ignored alert is no better than no alert.&lt;/p&gt;

&lt;p&gt;The fix is a schedule that matches the &lt;strong&gt;frequency of each check&lt;/strong&gt; to two questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;How fast can this break?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How much does it cost while it's broken?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A site going completely down can happen any minute and costs everything while it lasts, so you check it constantly. A domain renewal can only fail once a year and gives you weeks of warning, so you check it monthly. Everything else sits somewhere in between.&lt;/p&gt;

&lt;p&gt;Here's a practical schedule for a small business, blog, store or SaaS marketing site, with what to automate at each level and a few small scripts to get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continuous (every few minutes): is it up?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What:&lt;/strong&gt; Does the homepage, and your most important page (checkout, booking, sign-up, login), return a 200 quickly?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this often:&lt;/strong&gt; An outage is total. Every minute down means every visitor is lost, and it can happen at any time from a host failure, a bad deploy, an expired certificate or a DNS mistake.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to automate:&lt;/strong&gt; An uptime monitoring service that requests a URL every few minutes from outside your network and alerts you (email, SMS, chat) when it fails. Many offer free tiers for a handful of URLs. Check that the monitor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Checks from outside your hosting provider (a monitor on the same server goes down with it)&lt;/li&gt;
&lt;li&gt;Looks for expected text on the page, not just a status code, because an error page can still return 200&lt;/li&gt;
&lt;li&gt;Requires a couple of consecutive failures before alerting, to avoid false alarms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep this list short: two to five URLs. This level is for "the site is down", not for every page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Daily: is anything broken?
&lt;/h2&gt;

&lt;p&gt;These are problems that don't take the site down but quietly cost visitors and sales. They can appear at any time (after an update, a content edit, a third-party change), and every day they go unnoticed costs you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Broken links and missing images
&lt;/h3&gt;

&lt;p&gt;Pages get edited, products get removed, external sites change, and links break. A daily crawl catches a broken "Buy now" button the day after someone deletes a product, not at the end of the quarter.&lt;/p&gt;

&lt;p&gt;What to check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Internal links returning 4xx/5xx&lt;/li&gt;
&lt;li&gt;Missing images (404s on &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; sources)&lt;/li&gt;
&lt;li&gt;New redirect chains or loops&lt;/li&gt;
&lt;li&gt;Links to key conversion pages (cart, checkout, booking, pricing, contact) still resolving&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I walked through doing this by hand for one platform in &lt;a href="https://dev.to/sandeepsingh_uchik/how-to-find-and-fix-broken-links-on-a-shopify-store-33ll"&gt;How to Find and Fix Broken Links on a Shopify Store&lt;/a&gt;. The daily version is the same checks, automated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Certificate validity
&lt;/h3&gt;

&lt;p&gt;Certificates are meant to renew automatically, but renewals do fail. Let's Encrypt certificates are valid for 90 days by default, and renewal is recommended every 60 days (&lt;a href="https://letsencrypt.org/docs/faq/" rel="noopener noreferrer"&gt;Let's Encrypt FAQ&lt;/a&gt;). A daily check that warns when fewer than about 20 days remain gives you plenty of time to fix a stuck renewal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# cert-check.sh: warn if a certificate expires within N days&lt;/span&gt;
&lt;span class="nv"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;:?usage:&lt;span class="p"&gt; cert-check.sh example.com [days]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;days&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;20&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;cert&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; | openssl s_client &lt;span class="nt"&gt;-servername&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-connect&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt;:443"&lt;/span&gt; 2&amp;gt;/dev/null&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl x509 &lt;span class="nt"&gt;-noout&lt;/span&gt; &lt;span class="nt"&gt;-enddate&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$cert&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-f2&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; openssl x509 &lt;span class="nt"&gt;-noout&lt;/span&gt; &lt;span class="nt"&gt;-checkend&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;days&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="m"&gt;86400&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$cert&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"WARNING: &lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt; certificate expires &lt;/span&gt;&lt;span class="nv"&gt;$end&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi
&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"OK: &lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt; certificate valid until &lt;/span&gt;&lt;span class="nv"&gt;$end&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Backups completed
&lt;/h3&gt;

&lt;p&gt;Not "are backups configured", but "did last night's backup finish?" Most backup tools can email on failure. Make sure that's turned on and goes to someone who reads it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key-page smoke test
&lt;/h3&gt;

&lt;p&gt;A tiny script that requests your critical URLs and checks for the expected content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# smoke.sh: each line of urls.txt is "&amp;lt;url&amp;gt; &amp;lt;text that must appear&amp;gt;"&lt;/span&gt;
&lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; url expect&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-sL&lt;/span&gt; &lt;span class="nt"&gt;--max-time&lt;/span&gt; 20 &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s1"&gt;'\n%{http_code}'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-n1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;"200"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$expect&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FAIL &lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="s2"&gt; (missing: &lt;/span&gt;&lt;span class="nv"&gt;$expect&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
  &lt;span class="k"&gt;fi
done&lt;/span&gt; &amp;lt; urls.txt
&lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="nv"&gt;$fail&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One caution: &lt;strong&gt;don't automate form submissions or test purchases on a live site&lt;/strong&gt; unless your platform provides a proper test mode. You'll fill your CRM with junk, trigger real emails or create real orders. Test forms by hand (weekly, below).&lt;/p&gt;

&lt;h3&gt;
  
  
  Running it on a schedule
&lt;/h3&gt;

&lt;p&gt;Any scheduler works: cron on a server you control, your host's scheduled tasks, or a CI service. With GitHub Actions, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;daily-site-checks&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;10&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;   &lt;span class="c1"&gt;# 10:00 UTC daily&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;check&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bash smoke.sh &amp;amp;&amp;amp; bash cert-check.sh example.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub's documentation notes that scheduled workflows run on the default branch, can be delayed during periods of high load (particularly at the start of each hour), and in public repositories are automatically disabled after 60 days without repository activity (&lt;a href="https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows" rel="noopener noreferrer"&gt;Events that trigger workflows&lt;/a&gt;). Pick an odd minute, and don't rely on this alone for time-critical alerts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Weekly: the human checks
&lt;/h2&gt;

&lt;p&gt;Some things need a person, or are slow-moving enough that weekly is fine.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Test every contact path by hand:&lt;/strong&gt; submit the contact form, try the booking flow, tap the phone link on mobile. Contact forms often fail silently after plugin updates or email configuration changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apply updates&lt;/strong&gt; (CMS core, plugins, themes, dependencies), then re-run the daily checks and re-test forms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Glance at Google Search Console.&lt;/strong&gt; It emails about new critical issues, but a weekly look at &lt;strong&gt;Indexing → Pages&lt;/strong&gt; for rising 404 or server-error counts catches slower trends.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read the week's daily reports&lt;/strong&gt; and fix anything still open.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Monthly: performance, content and access
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Core Web Vitals.&lt;/strong&gt; Search Console's Core Web Vitals report "shows how your pages perform, based on real world usage data" (&lt;a href="https://support.google.com/webmasters/answer/9205520" rel="noopener noreferrer"&gt;Core Web Vitals report&lt;/a&gt;). Because it reflects real visitors over time, it moves slowly, so monthly is the right cadence. Google's targets are LCP within 2.5 s, INP under 200 ms and CLS under 0.1 (&lt;a href="https://developers.google.com/search/docs/appearance/core-web-vitals" rel="noopener noreferrer"&gt;Core Web Vitals&lt;/a&gt;). Use PageSpeed Insights to diagnose any template that's slipping.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content accuracy:&lt;/strong&gt; prices, hours, staff, service areas, promotions that should have ended.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outbound links on your most-visited pages&lt;/strong&gt;, opened by hand, to check they still say what you linked them for. A status-code checker can't tell when a page changed content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access review:&lt;/strong&gt; remove accounts for people who no longer need them (CMS, hosting, registrar, analytics).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business listings:&lt;/strong&gt; check that the website URL on your Google Business Profile and other directories still points at a working page.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Yearly: renewals and recovery
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Domain renewal.&lt;/strong&gt; Registrars of generic top-level domains must send at least two expiry reminders, about one month and about one week before expiry, under ICANN's &lt;a href="https://www.icann.org/resources/pages/errp-2013-02-28-en" rel="noopener noreferrer"&gt;Expired Registration Recovery Policy&lt;/a&gt;. That only helps if the contact email is current. Turn on auto-renew and confirm the payment card.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Restore test:&lt;/strong&gt; restore a backup somewhere safe and confirm the site works.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation:&lt;/strong&gt; who owns the domain, hosting, DNS, email and each account, and when each renews.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility and SEO review&lt;/strong&gt; of key templates.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a non-technical version of this list, see &lt;a href="https://dev.to/sandeepsingh_uchik/the-website-maintenance-checklist-for-small-business-websites-5eg0"&gt;The Website Maintenance Checklist for Small Business Websites&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alerts versus reports
&lt;/h2&gt;

&lt;p&gt;One last design decision makes the difference between monitoring people use and monitoring they mute:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Alerts&lt;/strong&gt; (immediate, interruptive) are only for things that need action &lt;em&gt;now&lt;/em&gt;: site down, checkout down, certificate expiring within days.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reports&lt;/strong&gt; (daily or weekly digests) are for everything else: broken links, missing images, redirect chains, slow templates. Nobody needs a 2 a.m. page about a broken link in a blog post from 2021, but they do need to see it in tomorrow's report.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If an alert fires and the right response is "I'll look at it later", it should have been a report.&lt;/p&gt;

&lt;p&gt;Disclosure: I build Uchik, which handles the daily report layer. &lt;a href="https://uchik.com/?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;Uchik&lt;/a&gt; crawls your site once a day with read-only requests (it never submits forms or places orders) and emails a report of broken links, missing images, redirect chains, mixed content and basic SEO gaps, each tied to the exact page and HTML element. &lt;a href="https://uchik.com/how-it-works?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;How it works&lt;/a&gt; explains the crawl, the &lt;a href="https://uchik.com/features?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;features page&lt;/a&gt; lists the checks, and the &lt;a href="https://uchik.com/sample-report?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;sample report&lt;/a&gt; shows what arrives in your inbox. It isn't an uptime monitor and it doesn't measure Core Web Vitals, so pair it with the continuous and monthly checks above. Links added only by JavaScript may be missed. You can &lt;a href="https://uchik.com/signup?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;sign up for free&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The schedule on one page
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cadence&lt;/th&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Automate?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Every few minutes&lt;/td&gt;
&lt;td&gt;Homepage + critical page up, expected text present&lt;/td&gt;
&lt;td&gt;Yes: uptime monitor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Daily&lt;/td&gt;
&lt;td&gt;Broken links, missing images, redirects&lt;/td&gt;
&lt;td&gt;Yes: crawler&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Daily&lt;/td&gt;
&lt;td&gt;Certificate expiry &amp;gt; ~20 days&lt;/td&gt;
&lt;td&gt;Yes: script or monitor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Daily&lt;/td&gt;
&lt;td&gt;Backup succeeded&lt;/td&gt;
&lt;td&gt;Yes: backup tool alerts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Daily&lt;/td&gt;
&lt;td&gt;Critical URLs return expected content&lt;/td&gt;
&lt;td&gt;Yes: smoke script&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weekly&lt;/td&gt;
&lt;td&gt;Forms, booking, phone links&lt;/td&gt;
&lt;td&gt;No: test by hand&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weekly&lt;/td&gt;
&lt;td&gt;Updates applied, then re-tested&lt;/td&gt;
&lt;td&gt;Partly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weekly&lt;/td&gt;
&lt;td&gt;Search Console indexing trends&lt;/td&gt;
&lt;td&gt;Email alerts + quick look&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monthly&lt;/td&gt;
&lt;td&gt;Core Web Vitals (field data)&lt;/td&gt;
&lt;td&gt;Report; review by hand&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monthly&lt;/td&gt;
&lt;td&gt;Content accuracy, outbound links, access, listings&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Yearly&lt;/td&gt;
&lt;td&gt;Domain renewal, restore test, documentation&lt;/td&gt;
&lt;td&gt;Auto-renew + calendar&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Start with the first two rows this week. Together they cover most of what quietly costs small sites visitors and sales.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>monitoring</category>
      <category>webdev</category>
      <category>automation</category>
    </item>
    <item>
      <title>Broken Links and Core Web Vitals: What Actually Affects Rankings</title>
      <dc:creator>Sandeep Singh</dc:creator>
      <pubDate>Sun, 18 Oct 2026 15:59:30 +0000</pubDate>
      <link>https://dev.to/sandeepsingh_uchik/broken-links-and-core-web-vitals-what-actually-affects-rankings-fpa</link>
      <guid>https://dev.to/sandeepsingh_uchik/broken-links-and-core-web-vitals-what-actually-affects-rankings-fpa</guid>
      <description>&lt;p&gt;Ask in any web forum whether broken links hurt SEO and you'll get confident answers in every direction. "Every 404 is a ranking penalty." "Google doesn't care about 404s at all." "Fix your Core Web Vitals or you'll never rank." "Core Web Vitals don't matter."&lt;/p&gt;

&lt;p&gt;Most of these are partly true and mostly unhelpful. This article sticks to what Google's own documentation says, quotes it directly, and separates three different questions that usually get blurred together:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Do broken links affect &lt;strong&gt;rankings&lt;/strong&gt;?&lt;/li&gt;
&lt;li&gt;Do Core Web Vitals affect &lt;strong&gt;rankings&lt;/strong&gt;?&lt;/li&gt;
&lt;li&gt;What do both cost you &lt;strong&gt;regardless of rankings&lt;/strong&gt;?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That third question is the one people skip, and it's often where the real losses are.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: What Google says about 404s and broken links
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A 404 on its own is not a penalty
&lt;/h3&gt;

&lt;p&gt;Google's Search Central blog answers this directly: "404 errors are a perfectly normal part of the web", and "If some URLs on your site 404, this fact alone does not hurt you or count against you in Google's search results." It goes further: the fact that some URLs return 404 "does not affect how your site's other URLs (the ones that return 200 (Success) status codes) perform in our search results" (&lt;a href="https://developers.google.com/search/blog/2011/05/do-404s-hurt-my-site" rel="noopener noreferrer"&gt;Do 404 errors hurt my site?&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Google actually &lt;em&gt;prefers&lt;/em&gt; a proper 404 or 410 for content you've removed, rather than a fake success page.&lt;/p&gt;

&lt;h3&gt;
  
  
  But a 404 on a page that matters is a real loss
&lt;/h3&gt;

&lt;p&gt;The same post adds the important caveat: "if some of the pages that 404 are pages you actually care about, you should look into why." And Google's HTTP status documentation explains what happens to an indexed page that starts returning 4xx: "the indexing pipeline removes the URL from the index if it was previously indexed" (&lt;a href="https://developers.google.com/search/docs/crawling-indexing/http-network-errors" rel="noopener noreferrer"&gt;HTTP status codes&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;So:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A random old URL returning 404 → normal, no penalty.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your ranking product page, service page or popular post&lt;/strong&gt; returning 404 → it drops out of search results. That isn't a "penalty", but the effect on your traffic is the same.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Internal links are how Google finds your pages
&lt;/h3&gt;

&lt;p&gt;Broken &lt;em&gt;internal&lt;/em&gt; links matter for a different reason: discovery. Google's link guidance says links are used to find new pages to crawl, and that "every page you care about should have a link from at least one other page on your site" (&lt;a href="https://developers.google.com/search/docs/crawling-indexing/links-crawlable" rel="noopener noreferrer"&gt;Link best practices&lt;/a&gt;). If the only link to a page is broken, or points through a JavaScript handler instead of a real &lt;code&gt;&amp;lt;a href&amp;gt;&lt;/code&gt;, that page is harder for Google to discover.&lt;/p&gt;

&lt;h3&gt;
  
  
  Soft 404s and homepage redirects are worse than honest 404s
&lt;/h3&gt;

&lt;p&gt;Google warns about two patterns: serving a "not found" page with a 200 status, and redirecting "any unknown URLs to their home page instead of returning 404 errors". Both "can have negative effects on our understanding and indexing" of your site (&lt;a href="https://developers.google.com/search/blog/2011/05/do-404s-hurt-my-site" rel="noopener noreferrer"&gt;Do 404 errors hurt my site?&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Broken outbound links
&lt;/h3&gt;

&lt;p&gt;I couldn't find any Google documentation saying broken links to &lt;em&gt;other&lt;/em&gt; sites lower your rankings, so I won't claim they do. What they clearly do is make your content less useful and less trustworthy to readers, which is a good enough reason to fix them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: What Google says about Core Web Vitals
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The metrics and thresholds
&lt;/h3&gt;

&lt;p&gt;Google's documentation defines three Core Web Vitals and the targets for a good experience (&lt;a href="https://developers.google.com/search/docs/appearance/core-web-vitals" rel="noopener noreferrer"&gt;Core Web Vitals&lt;/a&gt;):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Measures&lt;/th&gt;
&lt;th&gt;Good&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Largest Contentful Paint (LCP)&lt;/td&gt;
&lt;td&gt;Loading&lt;/td&gt;
&lt;td&gt;within 2.5 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interaction to Next Paint (INP)&lt;/td&gt;
&lt;td&gt;Responsiveness&lt;/td&gt;
&lt;td&gt;less than 200 milliseconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cumulative Layout Shift (CLS)&lt;/td&gt;
&lt;td&gt;Visual stability&lt;/td&gt;
&lt;td&gt;less than 0.1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;web.dev adds how these are assessed: a good threshold to measure is "the 75th percentile of page loads, segmented across mobile and desktop devices" (&lt;a href="https://web.dev/articles/vitals" rel="noopener noreferrer"&gt;Web Vitals&lt;/a&gt;). In other words, most of your real visitors need a good experience, not just the developer on fast office Wi-Fi.&lt;/p&gt;

&lt;h3&gt;
  
  
  Yes, they're used in ranking, but they aren't decisive
&lt;/h3&gt;

&lt;p&gt;Google's page experience documentation says: "Core Web Vitals are used by our ranking systems." In the same section it adds two important qualifications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Getting good results in reports like Search Console's Core Web Vitals report or third-party tools doesn't guarantee that your pages will rank at the top of Google Search results."&lt;/li&gt;
&lt;li&gt;"Google Search always seeks to show the most relevant content, even if the page experience is sub-par. But for many queries, there is lots of helpful content available. Having a great page experience can contribute to success in Search, in such cases."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(&lt;a href="https://developers.google.com/search/docs/appearance/page-experience" rel="noopener noreferrer"&gt;Understanding page experience&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;So the accurate summary is that Core Web Vitals are a real signal that can make a difference when competing pages are similarly relevant. They won't make an unhelpful page rank, and chasing a perfect score isn't worthwhile. Google says there is "no single signal" for page experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lab scores versus field data
&lt;/h3&gt;

&lt;p&gt;Lighthouse and PageSpeed Insights' lab results are diagnostic tools: one simulated load, on one simulated device. Search Console's Core Web Vitals report is different: it "shows how your pages perform, based on real world usage data (sometimes called field data)" (&lt;a href="https://support.google.com/webmasters/answer/9205520" rel="noopener noreferrer"&gt;Core Web Vitals report&lt;/a&gt;). If you want to know how real visitors experience your site, the field data is what counts. Use Lighthouse to find out &lt;em&gt;why&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The rest of page experience
&lt;/h3&gt;

&lt;p&gt;Google's page experience page lists more than Core Web Vitals. It asks whether pages are "served in a secure fashion", display well on mobile, avoid excessive distracting ads and intrusive interstitials, and make the main content easy to distinguish. That "secure fashion" point is where HTTPS problems like mixed content come in. I covered fixing those in &lt;a href="https://dev.to/sandeepsingh_uchik/mixed-content-and-missing-images-a-practical-fix-guide-for-store-owners-5g90"&gt;Mixed Content and Missing Images: A Practical Fix Guide for Store Owners&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 3: Where broken links and Core Web Vitals overlap
&lt;/h2&gt;

&lt;p&gt;They're usually discussed separately, but several "link health" problems are also performance problems:&lt;/p&gt;

&lt;h3&gt;
  
  
  Redirect chains slow every page load
&lt;/h3&gt;

&lt;p&gt;Every redirect is another network round trip before the page can even start loading. Lighthouse says this "can delay the loading of the resource by hundreds of milliseconds" and fails a page with two or more redirects (&lt;a href="https://developer.chrome.com/docs/lighthouse/performance/redirects" rel="noopener noreferrer"&gt;Avoid multiple page redirects&lt;/a&gt;). web.dev's LCP guide makes the connection explicit: Time to First Byte includes redirect time, a high TTFB "can make achieving a 2.5 second LCP challenging, or even impossible", and "a common cause of a slow TTFB for an otherwise fast site is visitors arriving through multiple redirects" (&lt;a href="https://web.dev/articles/optimize-lcp" rel="noopener noreferrer"&gt;Optimize LCP&lt;/a&gt;). Visitors arriving from old internal links, ads or emails pay that cost. Updating internal links to point directly at final URLs is both a link fix and a speed fix.&lt;/p&gt;

&lt;h3&gt;
  
  
  Images without dimensions cause layout shift
&lt;/h3&gt;

&lt;p&gt;web.dev lists "images without dimensions" first among the most common causes of poor CLS (&lt;a href="https://web.dev/articles/optimize-cls" rel="noopener noreferrer"&gt;Optimize CLS&lt;/a&gt;). Broken image references and slow-loading images often come together on older templates, so when you're fixing missing images, add &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes (or CSS &lt;code&gt;aspect-ratio&lt;/code&gt;) at the same time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Broken resources waste requests
&lt;/h3&gt;

&lt;p&gt;A page that requests a missing script, stylesheet, font or image still makes the request and waits for the 404. Removing references to resources that no longer exist is free performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 4: The costs that have nothing to do with rankings
&lt;/h2&gt;

&lt;p&gt;Even where Google says something "does not hurt you" in search, it can still cost you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A visitor who hits a 404 on a product, booking or sign-up page&lt;/strong&gt; is a lost conversion today, whatever your rankings are.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A slow or jumpy page&lt;/strong&gt; frustrates visitors who already found you. Core Web Vitals exist because these metrics reflect real user experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Broken links in content&lt;/strong&gt; make readers trust your recommendations less.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Links from other sites to your dead pages&lt;/strong&gt; stop sending referral visitors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the strongest argument for fixing link problems: not that Google punishes them, but that people do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 5: A sensible priority order
&lt;/h2&gt;

&lt;p&gt;Based on all of the above, here's how I'd prioritise:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Important pages returning errors.&lt;/strong&gt; Ranking pages, money pages and pages with backlinks that return 404/5xx. Restore them or 301 them to the correct replacement. &lt;em&gt;(Direct loss of indexing and conversions.)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Broken internal links to live content.&lt;/strong&gt; Fix at the source. &lt;em&gt;(Discovery and user experience.)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Homepage-redirect catch-alls and soft 404s.&lt;/strong&gt; Return honest 404s or targeted redirects. &lt;em&gt;(Google explicitly warns about these.)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redirect chains in internal links and navigation.&lt;/strong&gt; Point links at final URLs. &lt;em&gt;(Speed and crawl efficiency.)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Core Web Vitals issues in field data,&lt;/strong&gt; starting with templates that affect many pages. &lt;em&gt;(A ranking signal and a user-experience issue.)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mixed content and HTTPS problems.&lt;/strong&gt; &lt;em&gt;(Part of page experience, plus browser warnings.)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Broken outbound links.&lt;/strong&gt; &lt;em&gt;(Trust and usefulness.)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Old, unlinked URLs returning 404.&lt;/strong&gt; Usually nothing to do. That's normal.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Part 6: Monitoring both
&lt;/h2&gt;

&lt;p&gt;The tools are complementary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Search Console:&lt;/strong&gt; Page indexing (404s Google sees), Core Web Vitals (field data), HTTPS report.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PageSpeed Insights / Lighthouse:&lt;/strong&gt; diagnose &lt;em&gt;why&lt;/em&gt; a page is slow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A crawler&lt;/strong&gt; (Screaming Frog's free tier handles up to 500 URLs; &lt;a href="https://www.screamingfrog.co.uk/seo-spider/" rel="noopener noreferrer"&gt;limits&lt;/a&gt;): every broken link, redirect and missing image, with the page it's on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For personal and small sites, &lt;a href="https://dev.to/sandeepsingh_uchik/seo-health-basics-for-personal-websites-and-portfolios-54hp"&gt;SEO Health Basics for Personal Websites and Portfolios&lt;/a&gt; turns this into a short routine.&lt;/p&gt;

&lt;p&gt;Disclosure: I build Uchik, which covers the crawling side. &lt;a href="https://uchik.com/?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;Uchik&lt;/a&gt; checks your site daily and emails a report of broken links, missing images, redirect chains, mixed content and basic on-page SEO gaps, each tied to the exact page and HTML element. &lt;a href="https://uchik.com/how-it-works?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;How it works&lt;/a&gt; explains the method, and the &lt;a href="https://uchik.com/features?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;features page&lt;/a&gt; lists what it checks. It doesn't measure Core Web Vitals; use Search Console and PageSpeed Insights for that. The &lt;a href="https://uchik.com/faq?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;FAQ&lt;/a&gt; covers other limits, including that links added only by JavaScript may be missed. You can &lt;a href="https://uchik.com/signup?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;sign up for free&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A 404 on its own isn't a ranking penalty, but a 404 on a page that ranked removes it from the index.&lt;/li&gt;
&lt;li&gt;Broken internal links hurt discovery, and homepage catch-all redirects are explicitly discouraged.&lt;/li&gt;
&lt;li&gt;Core Web Vitals are used by ranking systems, but relevance comes first and good scores don't guarantee top rankings.&lt;/li&gt;
&lt;li&gt;Redirect chains and images without dimensions are both link-health and performance problems.&lt;/li&gt;
&lt;li&gt;The biggest cost of broken links is usually visitors, not rankings.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>seo</category>
      <category>webperf</category>
      <category>webdev</category>
      <category>corewebvitals</category>
    </item>
    <item>
      <title>How to Audit Internal Links on a WordPress Site</title>
      <dc:creator>Sandeep Singh</dc:creator>
      <pubDate>Sun, 18 Oct 2026 15:53:30 +0000</pubDate>
      <link>https://dev.to/sandeepsingh_uchik/how-to-audit-internal-links-on-a-wordpress-site-149b</link>
      <guid>https://dev.to/sandeepsingh_uchik/how-to-audit-internal-links-on-a-wordpress-site-149b</guid>
      <description>&lt;p&gt;Internal links are the roads inside your website. They're how visitors move from a blog post to a product or service page, how they find related content, and how search engines discover and understand your pages. Google's own guidance says it plainly: "Every page you care about should have a link from at least one other page on your site" (&lt;a href="https://developers.google.com/search/docs/crawling-indexing/links-crawlable" rel="noopener noreferrer"&gt;Link best practices&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;WordPress sites are especially prone to internal link problems because they grow over years. Posts get updated, slugs change, categories get reorganised, plugins come and go, themes get swapped, and the site gets moved between hosts or from staging to production. Each of those leaves some links pointing somewhere they shouldn't.&lt;/p&gt;

&lt;p&gt;The result is lost traffic you never see: a reader following "read my full guide" hits a 404 and leaves, a high-converting landing page has no links pointing to it so nobody finds it, and search engines spend their time on redirects instead of your content.&lt;/p&gt;

&lt;p&gt;This guide walks through a full internal link audit using free tools, then shows how to fix problems at the source rather than piling up redirects.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you're looking for
&lt;/h2&gt;

&lt;p&gt;An internal link audit checks for six things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Broken internal links:&lt;/strong&gt; links to pages on your own site that return 404 or another error.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redirected internal links:&lt;/strong&gt; links that work but go through one or more redirects first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orphan pages:&lt;/strong&gt; published pages that no other page links to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deeply buried pages:&lt;/strong&gt; important pages that take many clicks to reach from the homepage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weak anchor text:&lt;/strong&gt; "click here" and "read more" instead of descriptive text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leftover URLs:&lt;/strong&gt; links to your staging domain, &lt;code&gt;http://&lt;/code&gt; versions or old domain.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;You need a full list of every internal link: the page it's on, where it points and what status that target returns. Some free options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Screaming Frog SEO Spider&lt;/strong&gt; (free up to 500 URLs; &lt;a href="https://www.screamingfrog.co.uk/seo-spider/" rel="noopener noreferrer"&gt;limits&lt;/a&gt;). Enter your homepage and crawl. Use &lt;strong&gt;Response Codes&lt;/strong&gt; to filter internal URLs by status, and the &lt;strong&gt;Inlinks&lt;/strong&gt; tab at the bottom to see every page that links to a selected URL, with anchor text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Broken Link Checker plugin&lt;/strong&gt; (&lt;a href="https://wordpress.org/plugins/broken-link-checker/" rel="noopener noreferrer"&gt;WordPress.org&lt;/a&gt;) checks links from inside WordPress and lets you edit or unlink from its dashboard. Plugin-based checkers use your server's resources, so check its settings on shared hosting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Search Console's Links report&lt;/strong&gt; shows your most internally linked pages from Google's point of view. It won't show broken links directly, but it's a useful sanity check.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A crawler that starts from your homepage only finds pages reachable by links. That's exactly what you want for steps 2–5, and it's why orphan pages need a separate check in Step 4.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Fix broken internal links
&lt;/h2&gt;

&lt;p&gt;Filter the crawl for internal URLs returning &lt;strong&gt;4xx&lt;/strong&gt; and &lt;strong&gt;5xx&lt;/strong&gt;. For each one, open &lt;strong&gt;Inlinks&lt;/strong&gt; to see which posts or pages contain the bad link.&lt;/p&gt;

&lt;p&gt;Common causes on WordPress:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A post slug was changed.&lt;/strong&gt; WordPress core tries to rescue some of these: its &lt;code&gt;wp_old_slug_redirect()&lt;/code&gt; function attempts to find a post's current slug from past slugs and redirect (&lt;a href="https://developer.wordpress.org/reference/functions/wp_old_slug_redirect/" rel="noopener noreferrer"&gt;WordPress developer reference&lt;/a&gt;). That doesn't cover every case, such as pages, custom post types on some setups, or posts that were deleted and recreated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The permalink structure was changed&lt;/strong&gt; in &lt;strong&gt;Settings → Permalinks&lt;/strong&gt; (&lt;a href="https://wordpress.org/documentation/article/customize-permalinks/" rel="noopener noreferrer"&gt;WordPress docs&lt;/a&gt;). Links hard-coded in old content keep the old format.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A page was deleted or unpublished.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A plugin that created pages was removed:&lt;/strong&gt; shop, events, forums, landing page builders.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Category or tag base changed,&lt;/strong&gt; breaking every category link in old posts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Typos in manually entered links.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fix the link &lt;strong&gt;in the content&lt;/strong&gt; where it appears: edit the post, menu or widget and point it at the correct current URL. If the destination genuinely no longer exists, either link to the best replacement or remove the link.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Update redirected internal links
&lt;/h2&gt;

&lt;p&gt;Next, filter for internal links returning &lt;strong&gt;3xx&lt;/strong&gt;. These work, but every redirect is an extra request before the page loads. Lighthouse notes each redirect can delay a page "by hundreds of milliseconds" (&lt;a href="https://developer.chrome.com/docs/lighthouse/performance/redirects" rel="noopener noreferrer"&gt;Avoid multiple page redirects&lt;/a&gt;), and chains make it worse.&lt;/p&gt;

&lt;p&gt;Typical WordPress sources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Links to &lt;code&gt;http://&lt;/code&gt; versions of your own pages, redirected to &lt;code&gt;https://&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Links to &lt;code&gt;www&lt;/code&gt; when the site lives on the bare domain (or the reverse)&lt;/li&gt;
&lt;li&gt;Links missing the trailing slash, redirected to add it&lt;/li&gt;
&lt;li&gt;Old slugs being rescued by a redirect plugin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Redirects are the right tool for &lt;em&gt;external&lt;/em&gt; links and old bookmarks. For your own internal links, update the link to the final URL so visitors and crawlers get there directly. If you're seeing chains or loops, I covered fixing those in &lt;a href="https://sandeepsingh-uchik.hashnode.dev/redirect-chains-and-loops-what-they-cost-an-ecommerce-site-and-how-to-fix-them" rel="noopener noreferrer"&gt;Redirect Chains and Loops: What They Cost an Ecommerce Site and How to Fix Them&lt;/a&gt;, and &lt;a href="https://dev.to/sandeepsingh_uchik/mixed-content-and-missing-images-a-practical-fix-guide-for-store-owners-5g90"&gt;Mixed Content and Missing Images: A Practical Fix Guide for Store Owners&lt;/a&gt; covers the related &lt;code&gt;http://&lt;/code&gt; asset problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bulk-fixing domain and protocol changes
&lt;/h3&gt;

&lt;p&gt;If thousands of links point at an old domain or &lt;code&gt;http://&lt;/code&gt;, editing posts by hand isn't realistic. WP-CLI's search-replace handles it, including serialized data in options and widgets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Always preview first, and take a database backup&lt;/span&gt;
wp search-replace &lt;span class="s1"&gt;'http://example.com'&lt;/span&gt; &lt;span class="s1"&gt;'https://example.com'&lt;/span&gt; &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
wp search-replace &lt;span class="s1"&gt;'https://staging.example.com'&lt;/span&gt; &lt;span class="s1"&gt;'https://example.com'&lt;/span&gt; &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remove &lt;code&gt;--dry-run&lt;/code&gt; only after checking the counts look right. Many hosts and migration plugins offer a similar search-and-replace tool if you don't have shell access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Find orphan pages
&lt;/h2&gt;

&lt;p&gt;An orphan page is published but not linked from anywhere on the site. A link-following crawler can't find it, and visitors are unlikely to either.&lt;/p&gt;

&lt;p&gt;To find them, compare &lt;strong&gt;what you've published&lt;/strong&gt; with &lt;strong&gt;what the crawler found&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get the list of published URLs from your XML sitemap. Since WordPress 5.5, core generates a sitemap index at &lt;code&gt;/wp-sitemap.xml&lt;/code&gt; (&lt;a href="https://make.wordpress.org/core/2020/07/22/new-xml-sitemaps-functionality-in-wordpress-5-5/" rel="noopener noreferrer"&gt;Make WordPress Core&lt;/a&gt;); SEO plugins often replace it with their own, usually at &lt;code&gt;/sitemap_index.xml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Export the list of HTML URLs your crawler found by following links.&lt;/li&gt;
&lt;li&gt;Anything in the sitemap but not in the crawl is an orphan.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A spreadsheet works for this: paste both lists into separate columns and use a lookup to flag sitemap URLs missing from the crawl.&lt;/p&gt;

&lt;p&gt;For each orphan, decide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Still valuable?&lt;/strong&gt; Link to it from relevant posts, a category page or a hub page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outdated or thin?&lt;/strong&gt; Update it, merge it into a stronger page (and redirect), or unpublish it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intentionally hidden&lt;/strong&gt; (a thank-you page or a campaign landing page)? Consider whether it should be in the sitemap at all, or whether it should carry &lt;code&gt;noindex&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 5: Check click depth for important pages
&lt;/h2&gt;

&lt;p&gt;Most crawlers report &lt;strong&gt;crawl depth&lt;/strong&gt;: how many clicks from the homepage each page is. Your most important pages (key services, best guides, top products) shouldn't be buried at depth 5 behind pagination.&lt;/p&gt;

&lt;p&gt;Ways to bring them closer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Link to them from the main menu or a footer section&lt;/li&gt;
&lt;li&gt;Create a hub or "start here" page linking to your best content&lt;/li&gt;
&lt;li&gt;Add contextual links from related, popular posts&lt;/li&gt;
&lt;li&gt;Use breadcrumbs (many themes and SEO plugins provide them)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 6: Improve anchor text
&lt;/h2&gt;

&lt;p&gt;Google says good anchor text "is descriptive, reasonably concise, and relevant to the page that it's on and to the page it links to", and that it helps "both people and Google make sense of your site" (&lt;a href="https://developers.google.com/search/docs/crawling-indexing/links-crawlable" rel="noopener noreferrer"&gt;Link best practices&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;In the crawl's &lt;strong&gt;Inlinks&lt;/strong&gt; or &lt;strong&gt;All anchor text&lt;/strong&gt; export, look for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generic text: "click here", "read more", "this post", "here"&lt;/li&gt;
&lt;li&gt;Empty anchors, such as image links with no alt text&lt;/li&gt;
&lt;li&gt;The same exact keyword phrase used for every link to a page, which reads awkwardly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rewrite them as natural descriptions: "see our guide to [choosing a running shoe]" rather than "[click here] for our guide".&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Check your theme and page builder output
&lt;/h2&gt;

&lt;p&gt;Two WordPress-specific issues to verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Links must be real &lt;code&gt;&amp;lt;a href&amp;gt;&lt;/code&gt; elements.&lt;/strong&gt; Google says it can generally only crawl links that are &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; elements with an &lt;code&gt;href&lt;/code&gt; attribute (&lt;a href="https://developers.google.com/search/docs/crawling-indexing/links-crawlable" rel="noopener noreferrer"&gt;Link best practices&lt;/a&gt;). Some page builders and theme widgets render buttons or "clickable boxes" with JavaScript &lt;code&gt;onclick&lt;/code&gt; handlers instead. View the source of a few pages and check that menus, buttons and cards are real links.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Related-posts and widget links.&lt;/strong&gt; These are generated automatically and can point at drafts, trashed posts or attachment pages. Check them in the crawl, too.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 8: Make it a habit
&lt;/h2&gt;

&lt;p&gt;A one-off audit fixes today's problems. WordPress sites keep changing, so links keep breaking. A sustainable routine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;After every significant change&lt;/strong&gt; (theme switch, permalink change, plugin removal, migration): crawl and fix.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monthly:&lt;/strong&gt; a quick crawl filtered for 4xx and 3xx internal links.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quarterly:&lt;/strong&gt; the orphan-page and anchor-text review.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://dev.to/sandeepsingh_uchik/the-website-maintenance-checklist-for-small-business-websites-5eg0"&gt;The Website Maintenance Checklist for Small Business Websites&lt;/a&gt; puts internal link checks in context alongside backups, updates and renewals.&lt;/p&gt;

&lt;p&gt;Disclosure: I build Uchik, which automates the recurring part. &lt;a href="https://uchik.com/?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;Uchik&lt;/a&gt; crawls your site every day and emails a report of broken internal and external links, missing images, redirect chains and HTTPS problems, each with the source page and the exact HTML element to fix. It runs as an external crawler, so there's no plugin to install or keep updated. The &lt;a href="https://uchik.com/features?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;features page&lt;/a&gt; lists every check, the &lt;a href="https://uchik.com/sample-report?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;sample report&lt;/a&gt; shows the output, and the &lt;a href="https://uchik.com/faq?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;FAQ&lt;/a&gt; explains its limits, including that links added only by JavaScript may be missed. It doesn't do the orphan-page comparison in Step 4; keep that in your quarterly review. You can &lt;a href="https://uchik.com/signup?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;sign up for free&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Full crawl from the homepage&lt;/li&gt;
&lt;li&gt;[ ] Broken internal links fixed at the source&lt;/li&gt;
&lt;li&gt;[ ] Redirected internal links updated to final URLs&lt;/li&gt;
&lt;li&gt;[ ] Old domain, staging and &lt;code&gt;http://&lt;/code&gt; links bulk-replaced (with backup and dry run)&lt;/li&gt;
&lt;li&gt;[ ] Sitemap vs crawl compared; orphans linked, merged or removed&lt;/li&gt;
&lt;li&gt;[ ] Important pages within a few clicks of the homepage&lt;/li&gt;
&lt;li&gt;[ ] Generic anchor text rewritten&lt;/li&gt;
&lt;li&gt;[ ] Menus, buttons and cards confirmed as real &lt;code&gt;&amp;lt;a href&amp;gt;&lt;/code&gt; links&lt;/li&gt;
&lt;li&gt;[ ] Recurring check scheduled or automated&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Internal links are the one part of your site's linking you fully control. A few hours of auditing keeps readers and crawlers moving to the pages that matter.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>seo</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>404 Errors After a Site Migration or Redesign: A Recovery Checklist</title>
      <dc:creator>Sandeep Singh</dc:creator>
      <pubDate>Sun, 18 Oct 2026 15:52:35 +0000</pubDate>
      <link>https://dev.to/sandeepsingh_uchik/404-errors-after-a-site-migration-or-redesign-a-recovery-checklist-1lf0</link>
      <guid>https://dev.to/sandeepsingh_uchik/404-errors-after-a-site-migration-or-redesign-a-recovery-checklist-1lf0</guid>
      <description>&lt;p&gt;The new site launches. It looks better, it's faster, the team is happy. Then, a week or two later, someone notices: organic traffic is down, a few customers have emailed about "page not found" errors, and the Search Console Page indexing report shows a growing pile of 404s.&lt;/p&gt;

&lt;p&gt;This is the most common way a redesign or platform migration goes wrong. The new pages are fine. The problem is that &lt;strong&gt;the old URLs, the ones Google, other websites, bookmarks, old newsletters and social posts all point to, now go nowhere.&lt;/strong&gt; Every one of those is a visitor who arrived with intent and left with an error page.&lt;/p&gt;

&lt;p&gt;The good news is that this is usually recoverable. Below is the checklist I'd work through, in order, whether you moved from WordPress to a headless setup, changed your Shopify theme and URL handles, or just reorganised your blog's categories.&lt;/p&gt;

&lt;h2&gt;
  
  
  First: what Google actually says about 404s
&lt;/h2&gt;

&lt;p&gt;It helps to know what you're fixing, and what you're not.&lt;/p&gt;

&lt;p&gt;Google's own Search Central blog is clear that 404s on their own aren't a penalty: "If some URLs on your site 404, this fact alone does not hurt you or count against you in Google's search results", and those 404s don't affect how your &lt;em&gt;other&lt;/em&gt; working URLs perform (&lt;a href="https://developers.google.com/search/blog/2011/05/do-404s-hurt-my-site" rel="noopener noreferrer"&gt;Do 404 errors hurt my site?&lt;/a&gt;). Google's HTTP status documentation adds that when a previously indexed URL returns a 4xx, "the indexing pipeline removes the URL from the index" (&lt;a href="https://developers.google.com/search/docs/crawling-indexing/http-network-errors" rel="noopener noreferrer"&gt;HTTP status codes&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Put those together and the real cost of migration 404s is clear:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pages that used to rank drop out of the index&lt;/strong&gt;, and the new equivalents have to earn their place from scratch instead of inheriting the old URL's signals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Links from other sites now point to dead pages&lt;/strong&gt;, so the value of those links, and the referral traffic they bring, is lost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;People who click hit a dead end.&lt;/strong&gt; That's the immediate, measurable loss: leads, sales, sign-ups, readers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So the goal isn't "zero 404s". It's &lt;strong&gt;every old URL that had value now lands on its correct new home in one step&lt;/strong&gt;, and anything genuinely gone returns an honest 404 or 410.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Rebuild the list of old URLs
&lt;/h2&gt;

&lt;p&gt;You can't redirect what you can't list. If you didn't save a crawl before launch (most people don't), reconstruct it from several sources, because each one sees different URLs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Search Console → Indexing → Pages → Not found (404).&lt;/strong&gt; Export the examples. These are URLs Google knows about that now fail.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search Console → Performance.&lt;/strong&gt; Set the date range to &lt;em&gt;before&lt;/em&gt; the migration and export the top pages. These are the URLs that were actually earning clicks, so they're your priority list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search Console → Links → Top linked pages.&lt;/strong&gt; URLs other sites link to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your analytics tool.&lt;/strong&gt; Landing pages from the months before launch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The old sitemap&lt;/strong&gt;, if you still have it, or the Wayback Machine's capture of it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server or CDN logs&lt;/strong&gt; showing 404 responses since launch, if you have access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your own old content:&lt;/strong&gt; newsletters, social posts, PDFs, documentation and email templates that hard-coded links.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Combine these into one spreadsheet, remove duplicates, and keep a column for where each URL came from.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Check each old URL's current status
&lt;/h2&gt;

&lt;p&gt;Run the whole list through a crawler in list mode. &lt;strong&gt;Screaming Frog SEO Spider&lt;/strong&gt; does this in &lt;strong&gt;Mode → List&lt;/strong&gt; (free up to 500 URLs; &lt;a href="https://www.screamingfrog.co.uk/seo-spider/" rel="noopener noreferrer"&gt;limits&lt;/a&gt;). For a quick script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; url&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\t%s\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s1"&gt;'%{http_code} %{num_redirects} %{url_effective}'&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt; &amp;lt; old-urls.txt &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; status.tsv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives you the final status, the number of redirect hops and the final URL for each one. Sort into buckets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;404/410:&lt;/strong&gt; needs a redirect, or confirmation it's really gone&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redirects to the homepage:&lt;/strong&gt; probably wrong (see below)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2+ hops:&lt;/strong&gt; works, but slow and should be flattened&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;200 at the right place:&lt;/strong&gt; done&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: Map old URLs to new URLs
&lt;/h2&gt;

&lt;p&gt;Google's site move guide calls this step out explicitly: "Prepare a URL mapping from the current URLs to their corresponding new format" (&lt;a href="https://developers.google.com/search/docs/crawling-indexing/site-move-with-url-changes" rel="noopener noreferrer"&gt;Site moves with URL changes&lt;/a&gt;). For each old URL, decide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Same content, new address&lt;/strong&gt; → 301 to the new URL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content merged into another page&lt;/strong&gt; → 301 to the page that now covers it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content deliberately removed, no equivalent&lt;/strong&gt; → let it return 404 or 410. Google's guide says that for deleted or merged content, make sure "those URLs correctly return an HTTP 404 or 410 error response code".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Look for patterns. Migrations usually change URLs systematically, such as &lt;code&gt;/blog/2023/05/post-name/&lt;/code&gt; becoming &lt;code&gt;/posts/post-name&lt;/code&gt;, or &lt;code&gt;/products/&lt;/code&gt; becoming &lt;code&gt;/shop/&lt;/code&gt;. One pattern-based rule can cover hundreds of URLs. Handle the exceptions individually.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don't redirect everything to the homepage
&lt;/h3&gt;

&lt;p&gt;It's tempting to catch every unknown URL and send it to &lt;code&gt;/&lt;/code&gt;. Google warns against exactly this: a site that "redirects any unknown URLs to their home page instead of returning 404 errors" is treated as a soft 404 case, which "can have negative effects on our understanding and indexing" of the site (&lt;a href="https://developers.google.com/search/blog/2011/05/do-404s-hurt-my-site" rel="noopener noreferrer"&gt;Do 404 errors hurt my site?&lt;/a&gt;). It's also bad for visitors, who land on the homepage with no idea why. Redirect to a genuinely relevant page or return an honest 404 with helpful navigation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Implement redirects properly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use permanent, server-side redirects (301 or 308)&lt;/strong&gt; for moved content. Google's redirect documentation explains that permanent redirects signal the target should be shown in search results, while temporary ones (302, 307) keep the old URL (&lt;a href="https://developers.google.com/search/docs/crawling-indexing/301-redirects" rel="noopener noreferrer"&gt;Redirects and Google Search&lt;/a&gt;). Server-side redirects are the most reliably understood; JavaScript redirects are a last resort.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redirect in one hop.&lt;/strong&gt; If the old site already had redirects, update them to point straight at the final URL. Each hop adds a network round trip, which Lighthouse says can delay loading "by hundreds of milliseconds", and it fails pages with two or more redirects (&lt;a href="https://developer.chrome.com/docs/lighthouse/performance/redirects" rel="noopener noreferrer"&gt;Lighthouse: Avoid multiple page redirects&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use your platform's redirect tool:&lt;/strong&gt; Shopify's URL redirects, WordPress's Redirection plugin, &lt;code&gt;_redirects&lt;/code&gt; files on static hosts, or rules at your web server or CDN.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep them.&lt;/strong&gt; Google recommends keeping redirects "for as long as possible, generally at least 1 year", and suggests that from users' perspective you consider keeping them indefinitely.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you moved to a new domain, also submit a &lt;strong&gt;Change of Address&lt;/strong&gt; in Search Console for the old site. Google says this is only needed for domain or subdomain changes, not for HTTP→HTTPS or path changes within the same domain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Fix internal links at the source
&lt;/h2&gt;

&lt;p&gt;Redirects rescue &lt;em&gt;external&lt;/em&gt; traffic. Your own site shouldn't depend on them. After a migration it's common for menus, footers, in-content links, related-post widgets and image references to still point at old URLs, especially if content was imported with hard-coded absolute links.&lt;/p&gt;

&lt;p&gt;Crawl the &lt;strong&gt;new&lt;/strong&gt; site and check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Internal links returning 4xx (fix the link)&lt;/li&gt;
&lt;li&gt;Internal links that redirect (update them to the final URL)&lt;/li&gt;
&lt;li&gt;Images returning 404 (re-upload or fix paths, as media paths often change in migrations)&lt;/li&gt;
&lt;li&gt;Links still pointing at the staging domain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I walked through doing this on a store in &lt;a href="https://dev.to/sandeepsingh_uchik/how-to-find-and-fix-broken-links-on-a-shopify-store-33ll"&gt;How to Find and Fix Broken Links on a Shopify Store&lt;/a&gt;. The same approach works on any platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Check the things migrations quietly break
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;noindex&lt;/code&gt; left on from staging.&lt;/strong&gt; It's the classic launch-day mistake. View source on key templates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;robots.txt&lt;/code&gt; still blocking everything.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Canonical tags pointing at old or staging URLs.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTPS and mixed content:&lt;/strong&gt; new templates loading old &lt;code&gt;http://&lt;/code&gt; assets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sitemap:&lt;/strong&gt; make sure the new sitemap lists only new, working URLs, and submit it in Search Console.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Titles and meta descriptions&lt;/strong&gt; that didn't migrate and fell back to a template default.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your site is small, &lt;a href="https://dev.to/sandeepsingh_uchik/seo-health-basics-for-personal-websites-and-portfolios-54hp"&gt;SEO Health Basics for Personal Websites and Portfolios&lt;/a&gt; covers how to check each of these quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Confirm the recovery
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Re-run your old URL list&lt;/strong&gt; from Step 2. Every URL should now be either a single-hop 301 to the right page or a deliberate 404/410.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use URL Inspection&lt;/strong&gt; in Search Console on your most important old and new URLs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch the Page indexing report.&lt;/strong&gt; The count of "Not found (404)" URLs Google reports may take a while to change because Google recrawls old URLs gradually. What matters is that the URLs you care about are redirected correctly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compare Performance data&lt;/strong&gt; for your top pre-migration pages against their new URLs over the following weeks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch referral traffic&lt;/strong&gt; from sites that linked to you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Be patient with search recovery. Google has to recrawl old URLs to see the redirects, and that happens over time, not overnight.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8: Keep watching
&lt;/h2&gt;

&lt;p&gt;The weeks after a migration are when new problems appear: a redirect rule gets overwritten by a plugin update, a CMS editor changes a slug, an image CDN path changes. A one-off audit catches what's broken today. Ongoing monitoring catches what breaks next week.&lt;/p&gt;

&lt;p&gt;Disclosure: I build Uchik, which is meant for that ongoing part. &lt;a href="https://uchik.com/?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;Uchik&lt;/a&gt; crawls your site every day with read-only requests and emails a report of broken links, missing images, redirect chains and loops, and HTTPS problems, each with the page and HTML element that caused it. &lt;a href="https://uchik.com/how-it-works?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;How it works&lt;/a&gt; explains how it follows redirects hop by hop, the &lt;a href="https://uchik.com/features?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;features page&lt;/a&gt; lists every check, and the &lt;a href="https://uchik.com/sample-report?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;sample report&lt;/a&gt; shows what a redirect-chain finding looks like. It checks the HTML the server sends, so links added only by JavaScript may be missed, and it crawls the live site rather than your old URL list, so Step 2 still needs a list-mode check. You can &lt;a href="https://uchik.com/signup?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;sign up for free&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Old URL list rebuilt (Search Console, analytics, old sitemap, logs, backlinks)&lt;/li&gt;
&lt;li&gt;[ ] Every old URL's current status checked&lt;/li&gt;
&lt;li&gt;[ ] Old → new URL map built, using patterns where possible&lt;/li&gt;
&lt;li&gt;[ ] No blanket redirects to the homepage&lt;/li&gt;
&lt;li&gt;[ ] Permanent, server-side, single-hop redirects in place&lt;/li&gt;
&lt;li&gt;[ ] Change of Address submitted (domain moves only)&lt;/li&gt;
&lt;li&gt;[ ] Internal links, images and menus updated to final URLs&lt;/li&gt;
&lt;li&gt;[ ] No stray &lt;code&gt;noindex&lt;/code&gt;, &lt;code&gt;robots.txt&lt;/code&gt; blocks or staging canonicals&lt;/li&gt;
&lt;li&gt;[ ] New sitemap submitted&lt;/li&gt;
&lt;li&gt;[ ] Old URL list re-checked after the fix&lt;/li&gt;
&lt;li&gt;[ ] Ongoing monitoring in place for the months after launch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A migration doesn't end at launch. It ends when every link people relied on still takes them somewhere useful.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>migration</category>
      <category>devops</category>
    </item>
    <item>
      <title>The Website Maintenance Checklist for Small Business Websites</title>
      <dc:creator>Sandeep Singh</dc:creator>
      <pubDate>Sun, 18 Oct 2026 15:41:15 +0000</pubDate>
      <link>https://dev.to/sandeepsingh_uchik/the-website-maintenance-checklist-for-small-business-websites-5eg0</link>
      <guid>https://dev.to/sandeepsingh_uchik/the-website-maintenance-checklist-for-small-business-websites-5eg0</guid>
      <description>&lt;p&gt;For most small businesses, the website isn't the product. It's the front door. People find you on Google or Maps, open the site, check you're legitimate, and then call, book or fill in a form. If any step in that path is broken, the lead doesn't complain. It goes to the next business in the search results.&lt;/p&gt;

&lt;p&gt;The tricky part is that websites rarely break all at once. A contact form stops sending after a plugin update. A "Book now" button points at a scheduling page the old booking tool deleted. A menu PDF moves and the link goes dead. The site still &lt;em&gt;looks&lt;/em&gt; fine, so nobody notices until someone mentions that the phone has been quiet.&lt;/p&gt;

&lt;p&gt;This checklist is for owners and office managers who aren't web developers. It's split into weekly, monthly and yearly tasks, and for each one says why it matters and how to check it with free tools.&lt;/p&gt;




&lt;h2&gt;
  
  
  Weekly (about 15 minutes)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  â˜ 1. Test every way a customer can contact you
&lt;/h3&gt;

&lt;p&gt;This is the most important check on the list.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Submit your own contact form&lt;/strong&gt; using a personal email address. Did the confirmation appear? Did the message arrive in the business inbox, not spam? Contact forms fail silently more often than any other part of a small business site, usually because a plugin update, hosting change or email setting broke delivery.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tap the phone number on your phone.&lt;/strong&gt; Does it open the dialer with the right number? (On many sites the number is a &lt;code&gt;tel:&lt;/code&gt; link, and a typo there doesn't show on screen.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Click the email link,&lt;/strong&gt; the WhatsApp or chat button, and the map/directions link.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Try the booking or quote tool&lt;/strong&gt; through to the last step before submitting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If anything fails, fix it before anything else on this list.&lt;/p&gt;

&lt;h3&gt;
  
  
  â˜ 2. Click through the pages that bring in business
&lt;/h3&gt;

&lt;p&gt;Open the homepage, your main services pages, pricing (if you publish it), "About" and "Contact" in a private browser window, on desktop and on a phone. You're looking for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Links or buttons that lead to error pages&lt;/li&gt;
&lt;li&gt;Missing images (empty boxes or broken-image icons)&lt;/li&gt;
&lt;li&gt;Out-of-date information: old hours, old prices, staff who've left, last year's holiday notice&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  â˜ 3. Check last night's backup
&lt;/h3&gt;

&lt;p&gt;Log in to your hosting or backup tool and confirm a backup completed recently. If your site is on a hosted builder (Squarespace, Wix and similar), know what the platform backs up and what it doesn't, especially form submissions and uploaded files.&lt;/p&gt;




&lt;h2&gt;
  
  
  Monthly (about 45 minutes)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  â˜ 4. Scan the whole site for broken links and missing images
&lt;/h3&gt;

&lt;p&gt;Clicking around only covers the pages you think of. A crawler checks them all.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Screaming Frog SEO Spider&lt;/strong&gt; is a free desktop app for up to 500 URLs (&lt;a href="https://www.screamingfrog.co.uk/seo-spider/" rel="noopener noreferrer"&gt;limits&lt;/a&gt;), which covers most small business sites. After the crawl, check &lt;strong&gt;Response Codes â†’ Client Error (4xx)&lt;/strong&gt;, then use the &lt;strong&gt;Inlinks&lt;/strong&gt; tab to see which page contains each broken link.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WordPress sites&lt;/strong&gt; can use a plugin such as &lt;a href="https://wordpress.org/plugins/broken-link-checker/" rel="noopener noreferrer"&gt;Broken Link Checker&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Search Console&lt;/strong&gt; (below) also lists URLs Google found broken.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fix links at the source: edit the page or menu so it points to the right live page. If a page was deleted or renamed and other sites or old emails link to it, add a redirect from the old address to the closest current page.&lt;/p&gt;

&lt;h3&gt;
  
  
  â˜ 5. Look at Google Search Console
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://search.google.com/search-console/about" rel="noopener noreferrer"&gt;Google Search Console&lt;/a&gt; is free and is the only place Google tells you directly about problems it has with your site. Once a month, check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Indexing â†’ Pages:&lt;/strong&gt; a rise in "Not found (404)" or "Server error (5xx)" usually means something broke.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security issues&lt;/strong&gt; and &lt;strong&gt;Manual actions:&lt;/strong&gt; both should say no issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance:&lt;/strong&gt; which searches bring people to your site. A sudden drop for your main service plus your town ("plumber Leeds") is worth investigating.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  â˜ 6. Check your Google Business Profile matches your website
&lt;/h3&gt;

&lt;p&gt;For local businesses, the Business Profile on Search and Maps is often seen before the website. Confirm the &lt;strong&gt;website link&lt;/strong&gt; goes to a working page (not an old domain or deleted page), and that your hours, phone and address match the site. Google's help page explains how to &lt;a href="https://support.google.com/business/answer/3039617" rel="noopener noreferrer"&gt;edit your Business Profile&lt;/a&gt;. Do the same for any other directories you rely on, such as industry listings or review sites.&lt;/p&gt;

&lt;h3&gt;
  
  
  â˜ 7. Apply updates, carefully
&lt;/h3&gt;

&lt;p&gt;If your site runs on WordPress or another self-hosted system, apply core, theme and plugin updates monthly at least (security updates sooner). After updating, &lt;strong&gt;repeat check #1&lt;/strong&gt;, because updates are the most common cause of broken forms. If your host offers a staging copy, update there first.&lt;/p&gt;

&lt;h3&gt;
  
  
  â˜ 8. Check speed and mobile experience
&lt;/h3&gt;

&lt;p&gt;Run your homepage and main service page through &lt;a href="https://pagespeed.web.dev/" rel="noopener noreferrer"&gt;PageSpeed Insights&lt;/a&gt;. You don't need a perfect score. Look for big new problems, such as a huge uncompressed image someone uploaded or a new chat widget slowing the page down.&lt;/p&gt;

&lt;h3&gt;
  
  
  â˜ 9. Review who has access
&lt;/h3&gt;

&lt;p&gt;Remove logins for former staff, freelancers and agencies you no longer work with, on the website, hosting, domain registrar and Google accounts.&lt;/p&gt;




&lt;h2&gt;
  
  
  Yearly (an hour or two)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  â˜ 10. Domain name renewal
&lt;/h3&gt;

&lt;p&gt;An expired domain takes your website &lt;em&gt;and your email&lt;/em&gt; offline. Registrars of generic domains (.com, .net and similar) are required by ICANN to send at least two reminders before expiry, one about a month before and one about a week before (&lt;a href="https://www.icann.org/resources/pages/errp-2013-02-28-en" rel="noopener noreferrer"&gt;ICANN Expired Registration Recovery Policy&lt;/a&gt;). Those reminders go to the contact email on the registration, which is often an old address or a former employee's. So:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check the expiry date at your registrar.&lt;/li&gt;
&lt;li&gt;Turn on &lt;strong&gt;auto-renew&lt;/strong&gt; and make sure the payment card on file is current.&lt;/li&gt;
&lt;li&gt;Update the registrant contact email to an address someone actually reads.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  â˜ 11. SSL certificate
&lt;/h3&gt;

&lt;p&gt;The padlock in the browser depends on a valid certificate. Many hosts use free certificates from Let's Encrypt, which are valid for 90 days by default and are meant to be renewed automatically (&lt;a href="https://letsencrypt.org/docs/faq/" rel="noopener noreferrer"&gt;Let's Encrypt FAQ&lt;/a&gt;). Automatic renewal usually works, but not always, for example after DNS changes. Click the padlock and check the expiry date now and then. An expired certificate shows visitors a full-page security warning, and most will leave.&lt;/p&gt;

&lt;h3&gt;
  
  
  â˜ 12. Content review
&lt;/h3&gt;

&lt;p&gt;Read every main page as if you were a new customer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are services, prices and service areas current?&lt;/li&gt;
&lt;li&gt;Are team photos and bios up to date?&lt;/li&gt;
&lt;li&gt;Are testimonials still accurate and still permitted by the people who gave them?&lt;/li&gt;
&lt;li&gt;Do your &lt;strong&gt;page titles&lt;/strong&gt; and &lt;strong&gt;meta descriptions&lt;/strong&gt; describe each page clearly? These often appear as the headline and text in Google results. Google's guidance covers &lt;a href="https://developers.google.com/search/docs/appearance/title-link" rel="noopener noreferrer"&gt;title links&lt;/a&gt; and &lt;a href="https://developers.google.com/search/docs/appearance/snippet" rel="noopener noreferrer"&gt;snippets&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  â˜ 13. Accessibility basics
&lt;/h3&gt;

&lt;p&gt;Make sure images have meaningful alt text, text has enough contrast, buttons are labelled and the site works with a keyboard. The W3C's &lt;a href="https://www.w3.org/WAI/fundamentals/accessibility-intro/" rel="noopener noreferrer"&gt;introduction to web accessibility&lt;/a&gt; is a clear starting point. Accessible sites work better for everyone, including older customers on small screens.&lt;/p&gt;

&lt;h3&gt;
  
  
  â˜ 14. Test a restore
&lt;/h3&gt;

&lt;p&gt;Restore a backup to a test location once a year. A backup that has never been restored is a hope, not a plan.&lt;/p&gt;

&lt;h3&gt;
  
  
  â˜ 15. Write down who owns what
&lt;/h3&gt;

&lt;p&gt;Keep one document listing the domain registrar, hosting provider, website platform, email provider, who has admin access, renewal dates and support contacts. When something breaks at 6pm on a Friday, this document saves hours.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this protects
&lt;/h2&gt;

&lt;p&gt;Every item above protects one of four things:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Risk&lt;/th&gt;
&lt;th&gt;What it costs&lt;/th&gt;
&lt;th&gt;Checks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A lead can't reach you&lt;/td&gt;
&lt;td&gt;Lost enquiries and bookings, silently&lt;/td&gt;
&lt;td&gt;1, 2, 4, 7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Customers don't trust the site&lt;/td&gt;
&lt;td&gt;Visitors leave for a competitor&lt;/td&gt;
&lt;td&gt;2, 8, 11, 12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google can't find or show you&lt;/td&gt;
&lt;td&gt;Fewer people find you at all&lt;/td&gt;
&lt;td&gt;4, 5, 6, 12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The site goes offline&lt;/td&gt;
&lt;td&gt;Website &lt;em&gt;and&lt;/em&gt; email down&lt;/td&gt;
&lt;td&gt;3, 10, 11, 14, 15&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Making the routine stick
&lt;/h2&gt;

&lt;p&gt;The checks that matter most (contact paths, broken links, missing images) are also the ones people skip when they're busy. Some ways to keep them from slipping:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Put it in the calendar&lt;/strong&gt; as a recurring 15-minute appointment, and assign it to a named person.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep a log&lt;/strong&gt;: a spreadsheet with the date, what was checked and what was fixed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use alerts where they exist&lt;/strong&gt;: uptime monitors that email you when the site is down, your registrar's renewal emails, Search Console's email notifications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automate the crawl.&lt;/strong&gt; Broken links and missing images can be checked by software every day, so a problem that appears on Tuesday is in your inbox on Wednesday, not discovered at the end of the month.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disclosure: I build Uchik, which does that last part. &lt;a href="https://uchik.com/?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;Uchik&lt;/a&gt; crawls your website every day with read-only requests (it never submits your forms) and emails a short report of broken links, missing images, redirect problems, HTTPS warnings and basic SEO gaps such as missing page titles, each with the exact page and HTML element to fix. &lt;a href="https://uchik.com/how-it-works?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;How it works&lt;/a&gt; explains the method in plain language, and the &lt;a href="https://uchik.com/sample-report?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;sample report&lt;/a&gt; shows what lands in your inbox. You can &lt;a href="https://uchik.com/signup?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;sign up for free&lt;/a&gt;, no credit card needed. It doesn't replace check #1: no crawler can confirm your contact form actually delivers email, so keep testing that by hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Printable summary
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Weekly:&lt;/strong&gt; test contact paths Â· click through key pages Â· confirm backup&lt;br&gt;
&lt;strong&gt;Monthly:&lt;/strong&gt; crawl for broken links/images Â· Search Console Â· Business Profile Â· updates (then re-test forms) Â· speed Â· access review&lt;br&gt;
&lt;strong&gt;Yearly:&lt;/strong&gt; domain renewal Â· SSL Â· content review Â· accessibility Â· restore test Â· ownership document&lt;/p&gt;

&lt;p&gt;Fifteen minutes a week is a small price for making sure every customer who finds you can actually reach you.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>smallbusiness</category>
    </item>
    <item>
      <title>Mixed Content and Missing Images: A Practical Fix Guide for Store Owners</title>
      <dc:creator>Sandeep Singh</dc:creator>
      <pubDate>Sun, 18 Oct 2026 15:40:27 +0000</pubDate>
      <link>https://dev.to/sandeepsingh_uchik/mixed-content-and-missing-images-a-practical-fix-guide-for-store-owners-5g90</link>
      <guid>https://dev.to/sandeepsingh_uchik/mixed-content-and-missing-images-a-practical-fix-guide-for-store-owners-5g90</guid>
      <description>&lt;p&gt;Two problems turn up on almost every store that has been around for a few years: &lt;strong&gt;mixed content&lt;/strong&gt; (insecure &lt;code&gt;http://&lt;/code&gt; files loaded on a secure &lt;code&gt;https://&lt;/code&gt; page) and &lt;strong&gt;missing images&lt;/strong&gt; (product photos, banners or icons that return an error, leaving an empty box or a broken-image icon).&lt;/p&gt;

&lt;p&gt;They often share a root cause, usually a migration, an HTTPS switch, or media copied from another site, and they're fixed with similar tools, so it makes sense to tackle them together. This guide explains what's going on in plain terms and gives you fixes for Shopify, WooCommerce and everything else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: Mixed content
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What it is
&lt;/h3&gt;

&lt;p&gt;Your page loads over HTTPS, which means the connection is encrypted. If that page then pulls in an image, script, stylesheet, font or iframe over plain &lt;code&gt;http://&lt;/code&gt;, that file travels unencrypted. MDN's definition: mixed content means "securely loaded web pages that use resources to be fetched via HTTP or another insecure protocol" (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Security/Mixed_content" rel="noopener noreferrer"&gt;MDN: Mixed content&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  What browsers do about it today
&lt;/h3&gt;

&lt;p&gt;This is where a lot of older advice is out of date. According to MDN, modern browsers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Auto-upgrade&lt;/strong&gt; images, video and audio (for example an &lt;code&gt;&amp;lt;img src="http://â€¦"&amp;gt;&lt;/code&gt;) to &lt;code&gt;https://&lt;/code&gt;. If the file exists at the HTTPS address, it loads. If it doesn't, it fails and you get a missing image.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Block&lt;/strong&gt; almost everything else outright: scripts, stylesheets, web fonts, iframes, &lt;code&gt;fetch()&lt;/code&gt; calls, and images set through &lt;code&gt;srcset&lt;/code&gt; or &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Block even upgradable types&lt;/strong&gt; when the URL uses an IP address instead of a domain name.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a store, that means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;code&gt;http://&lt;/code&gt; &lt;strong&gt;script&lt;/strong&gt; (an old tracking pixel, a reviews widget, a chat embed) is blocked, so that feature silently stops working.&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;http://&lt;/code&gt; &lt;strong&gt;stylesheet or font&lt;/strong&gt; is blocked, so parts of the page lose their styling.&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;http://&lt;/code&gt; &lt;strong&gt;image on a server without HTTPS&lt;/strong&gt; fails after the auto-upgrade, so a product photo disappears.&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;http://&lt;/code&gt; &lt;strong&gt;iframe&lt;/strong&gt; (an embedded size chart, video or map) is blocked and shows a blank box.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So mixed content is no longer mainly a "Not secure" padlock warning. It's a &lt;strong&gt;broken features&lt;/strong&gt; problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to find it
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;In the browser (any platform):&lt;/strong&gt; open the page, press F12, and look at the &lt;strong&gt;Console&lt;/strong&gt;. Chrome and Firefox log a warning for every mixed-content request, saying whether it was upgraded or blocked, and with the exact URL. Check your homepage, a product page, a collection/category page, the cart and a blog post, since each uses a different template.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With Lighthouse (built into Chrome DevTools):&lt;/strong&gt; run the &lt;strong&gt;Best practices&lt;/strong&gt; category. The "Uses HTTPS" audit lists insecure requests it found on that page (&lt;a href="https://developer.chrome.com/docs/lighthouse/best-practices/is-on-https" rel="noopener noreferrer"&gt;Chrome for Developers&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Across the whole site:&lt;/strong&gt; a crawler checks every page rather than the five you happened to open. Screaming Frog SEO Spider's free version (up to 500 URLs, &lt;a href="https://www.screamingfrog.co.uk/seo-spider/" rel="noopener noreferrer"&gt;limits&lt;/a&gt;) reports mixed content under its &lt;strong&gt;Security&lt;/strong&gt; tab. Note the source page for each hit so you know where to fix it.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to fix it
&lt;/h3&gt;

&lt;p&gt;The rule is simple: &lt;strong&gt;every resource on your site should be requested over HTTPS.&lt;/strong&gt; How you get there depends on where the &lt;code&gt;http://&lt;/code&gt; reference lives.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Your own files:&lt;/strong&gt; change &lt;code&gt;http://yourstore.com/...&lt;/code&gt; references to &lt;code&gt;https://&lt;/code&gt; or to relative paths (&lt;code&gt;/wp-content/uploads/...&lt;/code&gt;, &lt;code&gt;/cdn/shop/files/...&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Other people's files:&lt;/strong&gt; change &lt;code&gt;http://&lt;/code&gt; to &lt;code&gt;https://&lt;/code&gt; if the provider supports it. Paste the HTTPS version into a browser tab to check it loads. If they don't support HTTPS, host the file yourself or find a different provider. An embed that can't load securely shouldn't be on a checkout-adjacent page anyway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Where the references hide, by platform:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;WooCommerce / WordPress&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Most mixed content on WordPress comes from &lt;strong&gt;old URLs saved in the database&lt;/strong&gt; before the switch to HTTPS, in post content, product descriptions, widgets and page-builder data.&lt;/li&gt;
&lt;li&gt;First, check &lt;strong&gt;Settings â†’ General&lt;/strong&gt;: both &lt;em&gt;WordPress Address&lt;/em&gt; and &lt;em&gt;Site Address&lt;/em&gt; should start with &lt;code&gt;https://&lt;/code&gt; (see WordPress's &lt;a href="https://developer.wordpress.org/advanced-administration/security/https/" rel="noopener noreferrer"&gt;HTTPS guidance&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Then do a database search-and-replace from &lt;code&gt;http://yourstore.com&lt;/code&gt; to &lt;code&gt;https://yourstore.com&lt;/code&gt; with a tool that handles WordPress's serialized data, such as the free &lt;a href="https://wordpress.org/plugins/better-search-replace/" rel="noopener noreferrer"&gt;Better Search Replace&lt;/a&gt; plugin. &lt;strong&gt;Take a full backup first&lt;/strong&gt;, and run it as a dry run before the real thing.&lt;/li&gt;
&lt;li&gt;Check theme options, header/footer script boxes and any "custom HTML" widgets by hand. These often contain pasted embed codes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Shopify&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shopify serves storefronts over HTTPS, so mixed content almost always comes from &lt;strong&gt;pasted code&lt;/strong&gt;: old embed snippets in theme files, custom Liquid sections, product descriptions written in HTML view, or apps that inject &lt;code&gt;http://&lt;/code&gt; assets.&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;Online Store â†’ Themes â†’ â€¦ â†’ Edit code&lt;/strong&gt;, use the code editor's search to look for &lt;code&gt;http://&lt;/code&gt; across theme files.&lt;/li&gt;
&lt;li&gt;In product descriptions and pages, switch the rich-text editor to HTML (&lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt;) and search for &lt;code&gt;http://&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If an uninstalled app left code behind, remove its snippet references. App developers usually document which files they touched.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Any platform&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;Content-Security-Policy: upgrade-insecure-requests&lt;/code&gt; header tells browsers to upgrade &lt;em&gt;all&lt;/em&gt; requests to HTTPS. It's a useful safety net, but it doesn't help if the HTTPS version of a file doesn't exist, so still fix the source.&lt;/li&gt;
&lt;li&gt;If you use a CDN, its "automatic HTTPS rewrites" option can rewrite links on the fly. Again, treat that as a backstop.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Part 2: Missing images
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why images go missing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deleted from the media library or Files&lt;/strong&gt; while still used in a product description, banner or blog post.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Migrations&lt;/strong&gt; where image paths changed (&lt;code&gt;/images/&lt;/code&gt; â†’ &lt;code&gt;/wp-content/uploads/2026/10/&lt;/code&gt; or Shopify's CDN) but old content still references the old path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hot-linked images&lt;/strong&gt; pulled from a supplier's or another site's server, which later moved or blocked hot-linking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-upgrade failures&lt;/strong&gt;, the mixed-content case above: &lt;code&gt;http://&lt;/code&gt; image, no HTTPS version, nothing loads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Missing resized versions.&lt;/strong&gt; WordPress generates several sizes for each upload and references them in &lt;code&gt;srcset&lt;/code&gt;. After a theme change or migration, some sizes may not exist, so certain screen widths show a broken image while others look fine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Case and character mismatches.&lt;/strong&gt; &lt;code&gt;Product-Photo.JPG&lt;/code&gt; and &lt;code&gt;product-photo.jpg&lt;/code&gt; are different files on most Linux servers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lazy-loading or optimisation plugins&lt;/strong&gt; that rewrite image URLs. If the plugin is removed or misconfigured, the rewritten URLs can point nowhere.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;Quick check:&lt;/strong&gt; open DevTools â†’ &lt;strong&gt;Network&lt;/strong&gt;, filter by &lt;strong&gt;Img&lt;/strong&gt;, reload the page and sort by &lt;strong&gt;Status&lt;/strong&gt;. Anything with 404 (or 403) is a missing image. Do this on desktop and in the device toolbar at a phone width, because &lt;code&gt;srcset&lt;/code&gt; picks different files for different screens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Whole site:&lt;/strong&gt; in a crawler, look at image URLs with 4xx responses, then use the "inlinks" or "source" view to find which pages reference each one. Fix at the source page, not just the file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Also worth checking while you're there:&lt;/strong&gt; images with &lt;strong&gt;missing alt text&lt;/strong&gt;. Alt text is how screen-reader users understand product photos, and Google uses it, along with surrounding content, to understand images (&lt;a href="https://developers.google.com/search/docs/appearance/google-images" rel="noopener noreferrer"&gt;Google Search Central: image SEO&lt;/a&gt;). Describe the product plainly ("Navy linen shirt, front view"). Don't stuff keywords.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to fix them
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Re-upload the file&lt;/strong&gt; to your own media library (WordPress) or &lt;strong&gt;Content â†’ Files&lt;/strong&gt; (Shopify) and update the reference to the new URL. Don't hot-link.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regenerate thumbnails&lt;/strong&gt; on WordPress after a theme change, using a regenerate-thumbnails plugin or WP-CLI (&lt;code&gt;wp media regenerate&lt;/code&gt;), so every &lt;code&gt;srcset&lt;/code&gt; size exists.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix paths in bulk&lt;/strong&gt; after a migration with a search-and-replace on the old path prefix (WordPress), or a bulk product CSV export, edit and import (Shopify).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remove or replace&lt;/strong&gt; images you no longer have rights to or can't recover. An empty space is better than a broken-image icon on a product page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If an image URL was shared externally&lt;/strong&gt; (Pinterest, ads, marketplaces), add a redirect from the old image URL to the new one where your platform allows it.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A 15-minute routine to keep both under control
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;After any &lt;strong&gt;theme change, migration, app removal or bulk import&lt;/strong&gt;: open the homepage, one product, one collection, the cart and one blog post with the Console and Network tabs open.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monthly:&lt;/strong&gt; crawl the site and export mixed-content and image-4xx lists.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Before pasting any embed code&lt;/strong&gt;, check that every URL in it starts with &lt;code&gt;https://&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep product images in your own store's media&lt;/strong&gt;, never on a supplier's server.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Automating the check
&lt;/h2&gt;

&lt;p&gt;These problems usually appear right after a change, which is exactly when nobody is looking. A scheduled crawl catches them sooner.&lt;/p&gt;

&lt;p&gt;Disclosure: I build Uchik. &lt;a href="https://uchik.com/?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;Uchik&lt;/a&gt; is a hosted monitor that crawls your store daily with read-only requests and emails a report of mixed content, missing images, broken links and redirect chains, each with the source page and the exact HTML tag. The &lt;a href="https://uchik.com/features?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;features page&lt;/a&gt; explains how it reads &lt;code&gt;src&lt;/code&gt; and &lt;code&gt;srcset&lt;/code&gt; attributes on images, and the &lt;a href="https://uchik.com/sample-report?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;sample report&lt;/a&gt; includes an &lt;code&gt;http://&lt;/code&gt; image flagged on a checkout page. You can &lt;a href="https://uchik.com/signup?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;sign up for free&lt;/a&gt;. It reads the HTML your server sends, so images injected only by JavaScript still need the DevTools check above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Likely cause&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Widget or embed stopped working&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;http://&lt;/code&gt; script or iframe blocked&lt;/td&gt;
&lt;td&gt;Switch to HTTPS version or replace the provider&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Page partly unstyled&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;http://&lt;/code&gt; stylesheet or font blocked&lt;/td&gt;
&lt;td&gt;Update the reference to HTTPS/relative&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blank product photo&lt;/td&gt;
&lt;td&gt;Image 404, or auto-upgrade to missing HTTPS file&lt;/td&gt;
&lt;td&gt;Re-upload to your own media; update reference&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Photo broken only on phones&lt;/td&gt;
&lt;td&gt;Missing &lt;code&gt;srcset&lt;/code&gt; size&lt;/td&gt;
&lt;td&gt;Regenerate thumbnails&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Console full of warnings after HTTPS move&lt;/td&gt;
&lt;td&gt;Old &lt;code&gt;http://&lt;/code&gt; URLs in database&lt;/td&gt;
&lt;td&gt;Backup, then search-and-replace&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Serve everything over HTTPS, host your own images, and check the console after every change. That covers almost every case.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>ecommerce</category>
    </item>
    <item>
      <title>SEO Health Basics for Personal Websites and Portfolios</title>
      <dc:creator>Sandeep Singh</dc:creator>
      <pubDate>Sun, 18 Oct 2026 15:29:01 +0000</pubDate>
      <link>https://dev.to/sandeepsingh_uchik/seo-health-basics-for-personal-websites-and-portfolios-54hp</link>
      <guid>https://dev.to/sandeepsingh_uchik/seo-health-basics-for-personal-websites-and-portfolios-54hp</guid>
      <description>&lt;p&gt;A personal website does a specific job. When a recruiter, client, conference organiser or potential collaborator searches your name, it should come up, look professional and lead them to your best work. You don't need to rank for competitive keywords. You need to be &lt;strong&gt;findable for your name and your niche&lt;/strong&gt;, and you need the site to &lt;strong&gt;work&lt;/strong&gt; when someone arrives.&lt;/p&gt;

&lt;p&gt;That second part gets overlooked. Portfolios are built once, often in a weekend, and then left alone for years while the things they link to change underneath them: demo apps on free hosting tiers get shut down, repos get renamed or archived, client sites get redesigned, conference talk pages disappear. The person reviewing your work doesn't know any of that. They just see a broken link next to your name.&lt;/p&gt;

&lt;p&gt;This guide is a health check, not a growth hack. It covers what to set up once, and what to check regularly so the site keeps doing its job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: Can Google find and index your site?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Verify in Search Console
&lt;/h3&gt;

&lt;p&gt;Add your site to &lt;a href="https://search.google.com/search-console/about" rel="noopener noreferrer"&gt;Google Search Console&lt;/a&gt;. It's free, and it's the only direct source of truth about how Google sees your site. After verification:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;URL Inspection&lt;/strong&gt; on your homepage. It tells you whether the page is indexed and, if not, why.&lt;/li&gt;
&lt;li&gt;Check &lt;strong&gt;Indexing â†’ Pages&lt;/strong&gt; for pages excluded by &lt;code&gt;noindex&lt;/code&gt;, redirects or errors.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Check you haven't hidden the site by accident
&lt;/h3&gt;

&lt;p&gt;A common portfolio problem is a &lt;code&gt;noindex&lt;/code&gt; left over from development, or a theme setting like WordPress's "Discourage search engines from indexing this site" left ticked. Google's documentation is explicit: when it finds the &lt;code&gt;noindex&lt;/code&gt; rule, it will "drop that page entirely from Google Search results, regardless of whether other sites link to it" (&lt;a href="https://developers.google.com/search/docs/crawling-indexing/block-indexing" rel="noopener noreferrer"&gt;Block Search indexing with noindex&lt;/a&gt;). View the page source and search for &lt;code&gt;noindex&lt;/code&gt;, and check response headers for &lt;code&gt;X-Robots-Tag&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sI&lt;/span&gt; https://yourname.dev | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; x-robots-tag
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also check &lt;code&gt;robots.txt&lt;/code&gt; isn't blocking everything (&lt;code&gt;Disallow: /&lt;/code&gt;). Note that the same Google page warns that if &lt;code&gt;robots.txt&lt;/code&gt; blocks a page, Google can't see its &lt;code&gt;noindex&lt;/code&gt; rule at all, so don't combine the two.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do you need a sitemap?
&lt;/h3&gt;

&lt;p&gt;Probably not urgently. Google says you might not need a sitemap if your site is "small", about 500 pages or fewer, and comprehensively linked internally (&lt;a href="https://developers.google.com/search/docs/crawling-indexing/sitemaps/overview" rel="noopener noreferrer"&gt;Sitemaps overview&lt;/a&gt;). Most portfolios qualify. If your static site generator or CMS produces one automatically, though, submitting it in Search Console doesn't hurt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: Make your links crawlable
&lt;/h2&gt;

&lt;p&gt;This one catches a lot of developer portfolios, especially single-page apps.&lt;/p&gt;

&lt;p&gt;Google's link guidance says that, generally, Google "can only crawl your link if it's an &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; HTML element ... with an &lt;code&gt;href&lt;/code&gt; attribute", and that most other formats won't be parsed (&lt;a href="https://developers.google.com/search/docs/crawling-indexing/links-crawlable" rel="noopener noreferrer"&gt;Link best practices&lt;/a&gt;). So if your navigation is built from &lt;code&gt;&amp;lt;div onClick&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; elements that change routes in JavaScript, crawlers may never discover your project pages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Crawlable --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/projects/weather-app"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Weather app&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Not reliably crawlable --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"router.push('/projects/weather-app')"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Weather app&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"goTo('weather')"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Weather app&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most frameworks' router link components (&lt;code&gt;&amp;lt;Link&amp;gt;&lt;/code&gt; in Next.js, &lt;code&gt;&amp;lt;router-link&amp;gt;&lt;/code&gt; in Vue, and so on) render a real &lt;code&gt;&amp;lt;a href&amp;gt;&lt;/code&gt;, so use those rather than click handlers. A quick check: disable JavaScript in your browser and see whether you can still navigate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 3: Titles and descriptions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Page titles
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; is usually the clickable headline in search results. Google's guidance asks for titles that are descriptive and concise, unique to each page, and free of keyword stuffing (&lt;a href="https://developers.google.com/search/docs/appearance/title-link" rel="noopener noreferrer"&gt;Title links&lt;/a&gt;). For a portfolio:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Homepage: &lt;code&gt;Ana Rivera, Frontend Developer in Lisbon&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Project page: &lt;code&gt;Weather App (React, Mapbox) | Ana Rivera&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Blog post: the post's actual title, plus your name if it fits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The commonest problem on portfolios is every page sharing the same title, like "Portfolio" or "Home", because the template was never changed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Meta descriptions
&lt;/h3&gt;

&lt;p&gt;Google says snippets are primarily created from the page content, but it "sometimes uses the meta description HTML element if it might give users a more accurate description of the page" (&lt;a href="https://developers.google.com/search/docs/appearance/snippet" rel="noopener noreferrer"&gt;Snippets&lt;/a&gt;). Write a unique, plain-English description for at least the homepage and key projects. One or two sentences on who you are, what you do and what's on the page is enough.&lt;/p&gt;

&lt;h3&gt;
  
  
  Duplicate URLs
&lt;/h3&gt;

&lt;p&gt;If your site responds on both &lt;code&gt;www&lt;/code&gt; and non-&lt;code&gt;www&lt;/code&gt;, or on both &lt;code&gt;http&lt;/code&gt; and &lt;code&gt;https&lt;/code&gt;, pick one version and redirect the others to it with a single 301. You can also add a &lt;code&gt;rel="canonical"&lt;/code&gt; tag pointing at the preferred URL. Google treats canonical tags as a strong signal for choosing which duplicate to show, but not as a guarantee (&lt;a href="https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls" rel="noopener noreferrer"&gt;Consolidate duplicate URLs&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 4: The links that actually matter, to your work
&lt;/h2&gt;

&lt;p&gt;Here's where personal sites lose the most value. A portfolio is a set of claims ("I built this", "I spoke here", "I wrote this") backed by links. When the links die, the claims look unverifiable.&lt;/p&gt;

&lt;p&gt;Link rot is not a fringe problem. Pew Research Center found that 38% of webpages that existed in 2013 were no longer accessible a decade later, and even of pages collected in 2021, about one in five were gone two years later (&lt;a href="https://www.pewresearch.org/data-labs/2024/05/17/when-online-content-disappears/" rel="noopener noreferrer"&gt;Pew Research Center, 2024&lt;/a&gt;). A portfolio that links out to many projects, employers and talks is exposed to all of that.&lt;/p&gt;

&lt;p&gt;Common culprits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live demos&lt;/strong&gt; on free hosting tiers that sleep, expire or were deleted when you cleaned up your account&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub repos&lt;/strong&gt; that were renamed, made private or moved to an organisation (GitHub redirects renamed repos, but not deleted or private ones)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client and employer sites&lt;/strong&gt; that were redesigned, so the specific page you built no longer exists&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Talks and articles&lt;/strong&gt; on event or publication sites that reorganised their archives&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your own old URLs&lt;/strong&gt; after you moved from one static site generator or host to another&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to check
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Crawl your own site&lt;/strong&gt; with Screaming Frog SEO Spider (free for up to 500 URLs; &lt;a href="https://www.screamingfrog.co.uk/seo-spider/" rel="noopener noreferrer"&gt;limits&lt;/a&gt;). Enable external link checking, then look at &lt;strong&gt;Response Codes â†’ Client Error (4xx)&lt;/strong&gt; and &lt;strong&gt;Server Error (5xx)&lt;/strong&gt;, and use &lt;strong&gt;Inlinks&lt;/strong&gt; to find which page holds each broken link.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Or script it.&lt;/strong&gt; For a small site, a short script that pulls every &lt;code&gt;href&lt;/code&gt; and requests each one is a fine weekend exercise. Treat timeouts and 5xx errors as "check again later" rather than definitely broken.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Look past status codes.&lt;/strong&gt; A deleted demo on some hosts returns a 200 with a generic "app not found" page. Open your most important links by hand now and then.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to fix
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Update the link to the new location.&lt;/li&gt;
&lt;li&gt;For a dead demo, replace it with a short screen recording or screenshots, and say the live version is offline.&lt;/li&gt;
&lt;li&gt;For a deleted article or talk page, link to an archived copy in the &lt;a href="https://archive.org/help/wayback_api.php" rel="noopener noreferrer"&gt;Wayback Machine&lt;/a&gt; if one exists.&lt;/li&gt;
&lt;li&gt;If you changed your own URL structure, redirect old paths to the new ones so links from other people's sites keep working.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 5: Images, HTTPS and speed
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Images
&lt;/h3&gt;

&lt;p&gt;Portfolios are image-heavy, and missing images are the most visible kind of breakage: a gallery of broken-image icons. After any move or rebuild, check every project page. For the images that work, add meaningful alt text. Google calls alt text "the most important attribute when it comes to providing more metadata for an image", and it also helps people using screen readers (&lt;a href="https://developers.google.com/search/docs/appearance/google-images" rel="noopener noreferrer"&gt;Image SEO best practices&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTPS and mixed content
&lt;/h3&gt;

&lt;p&gt;Serve everything over HTTPS. If an HTTPS page loads assets over plain HTTP, browsers treat that as mixed content. Some images, video and audio are automatically upgraded to HTTPS, and scripts, stylesheets and iframes are blocked outright (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Security/Mixed_content" rel="noopener noreferrer"&gt;MDN: Mixed content&lt;/a&gt;). Old embeds and hard-coded &lt;code&gt;http://&lt;/code&gt; image URLs are the usual cause. Search your source for &lt;code&gt;http://&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Speed
&lt;/h3&gt;

&lt;p&gt;Run your homepage and a heavy project page through &lt;a href="https://pagespeed.web.dev/" rel="noopener noreferrer"&gt;PageSpeed Insights&lt;/a&gt; or Lighthouse in Chrome DevTools. On portfolios the big wins are almost always oversized images (export at display size, use modern formats) and unnecessary third-party scripts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 6: A maintenance routine that fits a side project
&lt;/h2&gt;

&lt;p&gt;You won't audit your personal site every week, and you don't need to. A light routine:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After every change (deploy, redesign, host move):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click through every page with JavaScript disabled&lt;/li&gt;
&lt;li&gt;Check for &lt;code&gt;noindex&lt;/code&gt; and &lt;code&gt;robots.txt&lt;/code&gt; surprises&lt;/li&gt;
&lt;li&gt;Confirm old URLs redirect in one hop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Monthly (10 minutes):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Glance at Search Console for new errors&lt;/li&gt;
&lt;li&gt;Open your three most important project links by hand&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Quarterly:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full crawl with external link checking&lt;/li&gt;
&lt;li&gt;Fix or replace dead demos, repos and article links&lt;/li&gt;
&lt;li&gt;Update titles and descriptions if your role or focus has changed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Automate what's tedious.&lt;/strong&gt; Link and image checks are the part that's easy to forget and easy for software to do. An automated daily check means a demo that dies the week before you apply for a job shows up as an email, not as a recruiter's silent impression.&lt;/p&gt;

&lt;p&gt;Disclosure: I build Uchik, a tool for that last step. &lt;a href="https://uchik.com/?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;Uchik&lt;/a&gt; crawls your site every day and emails a short report of broken internal and external links, missing images, redirect chains, HTTPS problems and basic SEO gaps such as missing titles, meta descriptions and canonical tags, each with the page and HTML element to fix. The &lt;a href="https://uchik.com/features?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;features page&lt;/a&gt; lists the checks, and the &lt;a href="https://uchik.com/faq?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;FAQ&lt;/a&gt; covers what it does and doesn't do. One limit is relevant here: links that only exist after JavaScript runs may be missed, which is one more reason to use real &lt;code&gt;&amp;lt;a href&amp;gt;&lt;/code&gt; links. You can &lt;a href="https://uchik.com/signup?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;sign up for free&lt;/a&gt;, no credit card needed. Screaming Frog's free tier and a quarterly reminder in your calendar also work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Site verified in Search Console; homepage indexed&lt;/li&gt;
&lt;li&gt;[ ] No stray &lt;code&gt;noindex&lt;/code&gt;, &lt;code&gt;X-Robots-Tag&lt;/code&gt; or &lt;code&gt;Disallow: /&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Navigation uses real &lt;code&gt;&amp;lt;a href&amp;gt;&lt;/code&gt; links&lt;/li&gt;
&lt;li&gt;[ ] Unique, descriptive &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; on every page&lt;/li&gt;
&lt;li&gt;[ ] Meta descriptions on homepage and key projects&lt;/li&gt;
&lt;li&gt;[ ] One canonical version of the domain (HTTPS, www or not)&lt;/li&gt;
&lt;li&gt;[ ] No broken links to demos, repos, employers, talks or articles&lt;/li&gt;
&lt;li&gt;[ ] No missing images; alt text on project images&lt;/li&gt;
&lt;li&gt;[ ] No mixed content&lt;/li&gt;
&lt;li&gt;[ ] Routine scheduled or automated&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your personal site is often the first piece of your work someone sees. Keeping it findable and unbroken is a small, regular job, and it's worth it.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to Find and Fix Broken Links on a Shopify Store</title>
      <dc:creator>Sandeep Singh</dc:creator>
      <pubDate>Sun, 18 Oct 2026 15:28:10 +0000</pubDate>
      <link>https://dev.to/sandeepsingh_uchik/how-to-find-and-fix-broken-links-on-a-shopify-store-33ll</link>
      <guid>https://dev.to/sandeepsingh_uchik/how-to-find-and-fix-broken-links-on-a-shopify-store-33ll</guid>
      <description>&lt;p&gt;A broken link on a store costs more than one on a blog. A dead link in a blog post loses a reader. A dead link in your main menu, in a "Shop the look" block or on a cart upsell loses an order, and Shopify won't tell you about it. Products get deleted, collections get renamed, apps get uninstalled, themes get swapped, and every one of those changes can leave behind links that now lead to "Page not found."&lt;/p&gt;

&lt;p&gt;This guide shows a repeatable way to find those links with free tools and fix them properly. You don't need a developer or a paid app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where broken links come from on Shopify
&lt;/h2&gt;

&lt;p&gt;Knowing the usual causes tells you where to look first:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deleted or drafted products.&lt;/strong&gt; A product that is deleted, set to Draft or removed from the Online Store channel returns a 404. Every link to it from a collection description, blog post, menu or "related products" block now breaks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Changed URL handles.&lt;/strong&gt; If you rename a product or collection and edit its handle, the old URL stops working unless a redirect was created.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Menu items pointing at things that no longer exist.&lt;/strong&gt; Menus (Content â†’ Menus in the Shopify admin) often link to seasonal collections or pages that were removed months ago.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hard-coded links in theme sections and rich text.&lt;/strong&gt; Banners, slideshows and "image with text" blocks often have full URLs pasted in by hand. Typos and old handles hide here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;External links.&lt;/strong&gt; Links to suppliers, size guides on other sites, social profiles or affiliate partners break when &lt;em&gt;their&lt;/em&gt; sites change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Images.&lt;/strong&gt; An image deleted from Files, or a hot-linked image on another server, leaves an empty box where a product photo should be.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Check what Google has already found (Google Search Console)
&lt;/h2&gt;

&lt;p&gt;If you haven't connected &lt;a href="https://search.google.com/search-console/about" rel="noopener noreferrer"&gt;Google Search Console&lt;/a&gt; yet, verify your domain and submit your sitemap (&lt;code&gt;yourstore.com/sitemap.xml&lt;/code&gt;; Shopify generates it automatically).&lt;/p&gt;

&lt;p&gt;Then open &lt;strong&gt;Indexing â†’ Pages&lt;/strong&gt; and look under "Why pages aren't indexed" for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Not found (404).&lt;/strong&gt; URLs Google tried to crawl that no longer exist.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redirect error.&lt;/strong&gt; Redirects that loop or go nowhere.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click into each list to see example URLs. The &lt;strong&gt;URL Inspection&lt;/strong&gt; tool tells you where Google first discovered a URL, which often points to the page holding the bad link.&lt;/p&gt;

&lt;p&gt;Know the limits. Google crawls on its own schedule, so the report lags behind your changes. It only shows URLs Google cares to crawl, so it won't list a broken link in your footer if Google hasn't recrawled that page yet. And a 404 isn't always a problem: Google's documentation says URLs that return 4xx codes are dropped from the index over time (&lt;a href="https://developers.google.com/search/docs/crawling-indexing/http-network-errors" rel="noopener noreferrer"&gt;Google: how HTTP status codes affect crawling&lt;/a&gt;). That's fine for a product you truly retired. What you need to fix are the &lt;em&gt;links&lt;/em&gt; that still point to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Crawl your own store
&lt;/h2&gt;

&lt;p&gt;A crawler visits your pages the way a visitor would and reports every link that returns an error, along with the page that contains it. That second part is what makes it useful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Free options:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Screaming Frog SEO Spider (free version).&lt;/strong&gt; A desktop app for Windows, macOS and Linux. The free version crawls up to 500 URLs per crawl, which covers many small stores. Saving crawls and most advanced settings need the paid licence (&lt;a href="https://www.screamingfrog.co.uk/seo-spider/" rel="noopener noreferrer"&gt;Screaming Frog pricing and limits&lt;/a&gt;). After a crawl, filter &lt;strong&gt;Response Codes â†’ Client Error (4xx)&lt;/strong&gt;, select a URL, and open the &lt;strong&gt;Inlinks&lt;/strong&gt; tab at the bottom to see every page that links to it, with the anchor text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free online checkers&lt;/strong&gt; such as Dead Link Checker or W3C's Link Checker are fine for a quick look at a small site. They usually report less about &lt;em&gt;where&lt;/em&gt; the link lives.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tips for crawling a Shopify store:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start from your homepage and let the crawler follow internal links. Your main navigation and footer are on every page, so a broken menu link shows up on every page of the report. Fix it once and the whole list shrinks.&lt;/li&gt;
&lt;li&gt;Exclude URLs you don't care about: &lt;code&gt;/cart&lt;/code&gt;, &lt;code&gt;/account&lt;/code&gt;, &lt;code&gt;/search?&lt;/code&gt; and filter or sort parameters such as &lt;code&gt;?sort_by=&lt;/code&gt; and &lt;code&gt;?filter.&lt;/code&gt;. Those create many near-duplicate URLs and eat your 500-URL allowance.&lt;/li&gt;
&lt;li&gt;Crawl gently. Most desktop crawlers let you limit requests per second. One or two is plenty for a small store.&lt;/li&gt;
&lt;li&gt;Crawl after every big change: a theme switch, a bulk product import, an app removal or a menu rebuild.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 3: Check the pages that make money, by hand
&lt;/h2&gt;

&lt;p&gt;Crawlers follow links in the HTML. Some Shopify themes and apps inject buttons, upsells or recommendations with JavaScript, and crawlers that read only server HTML can miss them. So once a month, walk the purchase path yourself:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your homepage in a private window.&lt;/li&gt;
&lt;li&gt;Click each main menu item and each homepage banner.&lt;/li&gt;
&lt;li&gt;Open a best-selling product, add it to the cart, and continue to the checkout page. Stop before paying.&lt;/li&gt;
&lt;li&gt;Open the browser developer tools (F12) â†’ &lt;strong&gt;Network&lt;/strong&gt; tab, reload, and sort by &lt;strong&gt;Status&lt;/strong&gt;. Anything red (404, 500) is a resource or link that failed.&lt;/li&gt;
&lt;li&gt;Do the same on your phone. Mobile menus are often separate markup.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This takes about ten minutes and catches problems no crawler sees.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Fix each broken link the right way
&lt;/h2&gt;

&lt;p&gt;For each broken URL you'll make one of three fixes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix A: Update the link at its source (best)
&lt;/h3&gt;

&lt;p&gt;If the link is under your control (a menu item, a banner, a product description), edit it to point straight at the right live URL. A direct link is always better than a link that relies on a redirect.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Menus:&lt;/strong&gt; Content â†’ Menus â†’ open the menu â†’ click the broken item â†’ choose the new collection, product or page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Theme sections:&lt;/strong&gt; Online Store â†’ Themes â†’ Customize â†’ find the section â†’ update the link field.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rich text (descriptions, pages, blog posts):&lt;/strong&gt; open the item, select the link, and edit it. Switch to the HTML view (&lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt;) if the link is buried.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Fix B: Add a URL redirect (for URLs other people link to)
&lt;/h3&gt;

&lt;p&gt;If the old URL is in emails, ads, social posts or other sites' backlinks, you can't edit those links. Add a 301 redirect so visitors land somewhere useful:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Content â†’ Menus â†’ View URL redirects â†’ Create URL redirect&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;Redirect from&lt;/strong&gt;, enter the old path (e.g. &lt;code&gt;/products/blue-summer-dress&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;Redirect to&lt;/strong&gt;, enter the closest live match: the replacement product, or the parent collection. Avoid sending everything to the homepage; it frustrates visitors.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A few Shopify rules worth knowing, all from &lt;a href="https://help.shopify.com/en/manual/online-store/menus-and-links/url-redirect" rel="noopener noreferrer"&gt;Shopify's URL redirect documentation&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A redirect only works if the "from" URL is actually broken. If a page still loads there, the redirect is ignored.&lt;/li&gt;
&lt;li&gt;You can't redirect from reserved paths such as &lt;code&gt;/cart&lt;/code&gt;, &lt;code&gt;/orders&lt;/code&gt; or &lt;code&gt;/apps&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;When you hide a product or collection, then redirect its URL, and later make it visible again, Shopify deletes that redirect automatically.&lt;/li&gt;
&lt;li&gt;Redirects can be exported and imported as CSV. That's handy for bulk fixes after a migration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you change a product or collection handle in the "Search engine listing" section, Shopify offers to create the redirect for you. Leave that box ticked.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix C: Remove the link
&lt;/h3&gt;

&lt;p&gt;If the destination is gone for good and there is no sensible replacement (an expired partner offer, a discontinued external guide), remove the link or replace it with plain text.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Fix external links and images
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;External links:&lt;/strong&gt; open each one. If the page has moved, update to the new URL. If it's gone, link to a different source or remove it. For affiliate links, check that the link still goes to the right product, not just that it loads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Images:&lt;/strong&gt; in the crawler, filter by images with a 4xx response. Re-upload missing images to &lt;strong&gt;Content â†’ Files&lt;/strong&gt; and update the reference. Don't hot-link images from other domains; when those servers change, your images break.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 6: Prevent the next batch
&lt;/h2&gt;

&lt;p&gt;Most broken links are created during routine admin work, so a few habits prevent most of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Before deleting a product,&lt;/strong&gt; search your store admin and theme for its handle, and decide where its URL should redirect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the redirect box ticked&lt;/strong&gt; whenever you edit a handle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use relative links&lt;/strong&gt; (&lt;code&gt;/collections/sale&lt;/code&gt;) in theme settings instead of full URLs. They survive domain changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;After uninstalling an app,&lt;/strong&gt; check the pages where it showed widgets. Leftover blocks or snippets can point to app URLs that no longer exist.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Re-crawl on a schedule.&lt;/strong&gt; Monthly for small stores, weekly if you publish or change products often.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Automating the check
&lt;/h2&gt;

&lt;p&gt;The manual routine works, but it relies on you remembering to run it, and a broken link created on Tuesday can sit there for weeks. If you'd rather have it run on its own, there are scheduled options: Screaming Frog's paid licence can schedule crawls, several Shopify apps monitor 404s, and hosted crawlers will email you results.&lt;/p&gt;

&lt;p&gt;Disclosure: I build Uchik, a hosted option of this kind. &lt;a href="https://uchik.com/?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;Uchik&lt;/a&gt; crawls a store daily with read-only GET requests and emails a list of broken links, missing images and redirect problems. The &lt;a href="https://uchik.com/features?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;features page&lt;/a&gt; lists every check it runs, and each issue comes with the page and the exact HTML tag that caused it, as you can see in this &lt;a href="https://uchik.com/sample-report?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;sample ecommerce report&lt;/a&gt;. You can &lt;a href="https://uchik.com/signup?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;sign up for free&lt;/a&gt;, no credit card needed. It reads server-delivered HTML (&lt;a href="https://uchik.com/faq?utm_source=devto&amp;amp;utm_medium=content&amp;amp;utm_campaign=oct26-1k" rel="noopener noreferrer"&gt;the FAQ&lt;/a&gt; explains what that means for JavaScript-added links), so the manual checkout walk-through in Step 3 is still worth doing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Search Console connected, sitemap submitted&lt;/li&gt;
&lt;li&gt;[ ] Indexing â†’ Pages â†’ "Not found (404)" reviewed&lt;/li&gt;
&lt;li&gt;[ ] Store crawled with cart, account and filter URLs excluded&lt;/li&gt;
&lt;li&gt;[ ] Every 4xx link traced to its source page via Inlinks&lt;/li&gt;
&lt;li&gt;[ ] Links fixed at source; redirects added for externally shared URLs&lt;/li&gt;
&lt;li&gt;[ ] Purchase path walked by hand on desktop and mobile&lt;/li&gt;
&lt;li&gt;[ ] Next crawl date in the calendar&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Broken links rarely appear all at once. They pile up one admin change at a time, and a short, regular check is the easiest way to keep them under control.&lt;/p&gt;

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