
file:///Users/name/Sites/project/page.html, C:\Users\name\project\index.html, localhost, 127.0.0.1, or /Applications/MAMP/htdocs/.... It leaked into production HTML and is dead for every real visitor and every crawler, so find it and fix it at the content or database level, not just in the rendered page.What "link to local path" actually means
Every developer builds sites locally first. That means working URLs that look like file:///Users/jane/Sites/clientsite/about.html on a Mac, or C:\wamp64\www\clientsite\about.html on Windows, or http://localhost:8888/about.html, or http://127.0.0.1/about.html if you're running MAMP, XAMPP, WAMP, Local by Flywheel, or a Docker container. These paths are correct on the machine that built the site. They are meaningless everywhere else. When one of these values ends up hardcoded into a link, an image src, or a CSS/JS reference on the live, public version of the site, you have a link to local path issue.
It's a specific flavor of broken link. Most broken links happen because a page got deleted or a URL structure changed. This one happens because content was authored against the wrong base URL from the start and nobody caught it before publishing. The href or src never worked in production. It's not decay, it's a leftover.
How this actually happens
In practice it's rarely a developer manually typing a local path into a link field on purpose. It's almost always one of these:
- Copy-paste from a local build. Someone finishes a page locally, copies the finished HTML or rich text into the CMS, and the anchor tags or image tags still carry the local base URL because the content was authored and tested against
localhostor afile://preview. - WYSIWYG and page builder quirks. The classic WordPress editor, Gutenberg, and page builders (Elementor, Divi, WP Bakery, and similar) will sometimes insert whatever URL was in the browser address bar or clipboard at the moment an image or link was added. If that was a local dev URL, it gets baked into post content or a builder's JSON/meta field, not just a rendered preview.
- Search-and-replace failures after a site migration. Moving a site from a local environment or a staging subdomain to production usually involves a domain search-and-replace pass across the database. If that pass misses serialized data (common in WordPress because widget settings, page builder layouts, and some plugin options store PHP-serialized arrays where a naive text replace corrupts the string length and silently fails), some local URLs survive the move untouched.
- Staging environments left in content. Similar issue, different flavor: a link points to
staging.example.comor a Netlify/Vercel preview subdomain instead of the production domain because the staging URL was never swapped before launch. - Database export/import between environments. Pulling a database dump from local into staging into production, several times, across a project, multiplies the chances that one pass gets missed and a local reference survives all the way to launch.
Why it matters for SEO, crawling, and trust
A single dead local link on one page is not going to sink a domain. The problem is scale and signal. Sites that leak local paths usually leak more than one, because the root cause (a builder bug, a bad migration, a copy-paste habit) repeats across every page it touched. Screaming Frog crawls of migrated WordPress sites regularly turn up dozens or hundreds of these at once, all from the same root cause.
Three concrete costs:
- Crawl efficiency. Googlebot requests the URL, gets a connection failure or a DNS error (since localhost and 127.0.0.1 don't resolve to anything public, and file:// isn't even a fetchable HTTP scheme), and that's crawl budget spent on nothing. On large sites this compounds.
- User experience. A visitor who clicks a link expecting more content and lands on a browser error, or a broken image icon where a product photo should be, loses trust in that page immediately. If it's an image src rather than a link, it's worse because it's visible without any click at all.
- Site quality signal. Google's own Search Essentials documentation is explicit that a good user experience, including working links, is part of what they expect from sites that want to rank well. A page riddled with dead local links reads as unmaintained, and at scale that pattern looks like site neglect rather than a one-off typo.
None of this is an instant ranking penalty. It's a slow tax on crawl efficiency and user trust that shows up as fewer pages getting crawled promptly and worse engagement metrics on the affected pages.
How to detect it
You're looking for a small, specific set of string patterns. That makes this one of the easier technical issues to hunt down exhaustively:
- Screaming Frog. Run a crawl, then use Configuration > Custom > Search to add filters for
file://,localhost,127.0.0.1,C:\, and any known staging subdomain (likestaging.or.local). The Custom Search tab will list every page containing a match in the raw HTML, and you can pair it with the Internal tab filtered by protocol to catch file:// hrefs directly. - Sitebulb. Runs a similar crawl-based check and will flag internal links with non-HTTP(S) protocols under its Hyperlinks section, which surfaces file:// and other malformed schemes automatically.
- Google Search Console. The Page Indexing report and the old-style crawl error data won't show file:// links directly since Googlebot never even attempts a fetch on a scheme it can't handle, but a spike of "Not found (404)" entries pointing at odd paths, or a pattern where several URLs resolve to nothing meaningful, is a hint worth cross-checking with a crawl.
- Server log analysis. If real browsers are somehow generating requests for internal server paths (this can happen when a local absolute path accidentally resolves against your own domain, turning
/Applications/MAMP/htdocs/site/page.htmlinto a same-domain 404), your access logs will show the resulting 404 hits and referrer. - Direct database search in WordPress. A plugin like Better Search Replace, or direct SQL, lets you search
wp_posts,wp_postmeta, and any page-builder tables for the literal stringsfile://,localhost,127.0.0.1, and your known local/staging hostnames. This catches instances buried in serialized data that a crawler-based tool might miss if the link never rendered into visible HTML.
How to fix it, step by step
- Back up the database first. Any search-and-replace operation across a live WordPress database needs a full backup beforehand. This is not optional, a bad replace against serialized data can break far more than the link you're trying to fix.
- Inventory every match. Use the Screaming Frog custom search or a database search to get a complete list of pages and fields affected, not just the first one you noticed. Fix the root cause once you understand the pattern, not one link at a time.
- Use WP-CLI search-replace for serialized-safe fixes. The command
wp search-replace 'file:///Users/name/Sites/project' 'https://example.com' --all-tableshandles PHP-serialized data correctly, unlike a plain find-and-replace in phpMyAdmin, which will corrupt serialized array lengths and can break page builder layouts. Run it with--dry-runfirst to review the count of replacements before committing. - Fix at the content level, not just visually. If you manually edit a link in the WordPress editor and it looks fixed in the visual preview, check the actual saved href in the HTML or block source. Some page builders store the URL in more than one place (a visible link and a duplicate value in a JSON config), and fixing only the rendered one leaves the underlying data intact for the next export or migration to reintroduce it.
- Re-crawl to verify. Run Screaming Frog again with the same custom search filters and confirm zero matches. Also spot-check a handful of the previously broken URLs directly in a browser.
- Check Search Console after the fix. If any of the broken paths had been discovered and reported as errors, use the URL Inspection tool to confirm the corrected page is reachable, then move on. There's no need to force a reindex for a handful of internal link fixes, Google will pick it up on the next normal crawl.
What good looks like
Every internal link and image src on the production site resolves to a real, publicly reachable URL on your actual domain, using absolute or root-relative paths that don't depend on any developer's local file system or a staging hostname. Your deployment process includes a search-and-replace or environment-variable-based base URL swap as a checked step, not an afterthought, and a periodic Screaming Frog crawl with a custom search for file://, localhost, and known staging domains comes back clean. When it doesn't come back clean, you already know exactly where to look.
| Leak type | Typical cause | Risk level | Fix |
|---|---|---|---|
file:///Users/... or C:\... | Copy-paste from local editor into CMS | High, unusable link/image for all visitors | Database search, manual or WP-CLI replace |
localhost / 127.0.0.1 | Builder or editor grabbed the active browser URL | High, connection refused for every visitor | WP-CLI search-replace across all tables |
| staging subdomain (e.g. staging.example.com) | Staging URL never swapped before launch | Medium to high, may resolve but wrong content or noindex | Search-replace plus DNS/robots check on staging |
| local server path (e.g. /Applications/MAMP/htdocs/...) | Absolute path authored against local server root | Medium, may accidentally resolve to a real 404 on your domain | Content-level fix, verify with server logs |
| local path in image src | Same causes as link leaks, applied to media | High, visibly broken image with no click required | Re-upload to media library, fix src, verify render |
- Back up the database before any bulk search-and-replace.
- Use WP-CLI's search-replace command so serialized data stays intact.
- Inventory every affected page before fixing anything, so you fix the root cause once.
- Re-crawl with Screaming Frog after the fix to confirm zero matches remain.
- Check that the fix landed in the actual saved content, not just the visual preview.
- Don't run a plain text find-and-replace on a WordPress database with page builders installed, it will corrupt serialized fields.
- Don't assume one fixed link means the problem is isolated, check the whole site.
- Don't skip the dry-run flag on WP-CLI search-replace before committing changes.
- Don't leave staging subdomains live and linkable after launch.
- Don't copy-paste rich content straight from a local build into the CMS without checking the resulting hrefs.
FAQ
Can Google index a file:// link?
Why does a plain find-and-replace break my page builder?
Is a local path leak the same as a broken internal link?
Can this affect images, not just links?
How do I stop this from happening again after a migration?
Finding a client's live product pages full of localhost links because someone exported a local WordPress build straight into production is one of those bugs that's genuinely embarrassing to hand back to a client, but it's also a quick, mechanical fix once you know where to look. Don't let it sit.
Want a full technical crawl that catches leaked local paths, broken links, and every other invalid-link pattern across your whole site?
Claude Vincent is a technical SEO consultant focused on crawlability, rendering, and AI-search visibility. He writes the field guides and case studies at SEO ProCheck, with a bias toward the durable, unglamorous work that decides whether search engines and AI answer engines can actually read and cite a site.
About SEO ProCheck
Technical SEO consulting and GEO strategy with 20 years of enterprise experience. Case studies, resources, and tools for search and AI visibility.
Work With Me
Technical SEO audits, GEO strategy, site migrations, and international SEO. Hourly consulting for teams who need hands-on support, not just reports.







