Hash-based routing (/#/about) is invisible to every search crawler: the entire site is treated as a single URL because servers do not receive anything after the #. Query-string routing (/?page=about) is indexable but ambiguous — Google often merges parameterized URLs into one canonical, splits PageRank across permutations, and rate-limits crawling. Clean path-based URLs are also more shareable, more memorable, and easier to parse in analytics reports.
Low because modern frameworks default to clean URLs — only legacy SPAs and misconfigured custom routers trigger this.
Move to the framework's file-system router. In Next.js App Router, each folder under app/ with a page.tsx becomes a path segment — no config required. Delete client-side-only hash routers like HashRouter from react-router-dom and replace with BrowserRouter (for a standalone SPA) or the framework-native router.
app/
page.tsx -> /
about/page.tsx -> /about
blog/[slug]/page.tsx -> /blog/my-post
Add permanent redirects in next.config.js from the old hash URLs to the new paths to preserve any existing backlinks.
ID: seo-fundamentals.discoverability.clean-urls
Severity: low
What to look for: Examine the routing structure. Check that page URLs follow clean patterns (e.g., /about, /blog/my-post) rather than query-string-only routing (e.g., /?page=about) or hash-based routing (e.g., /#/about). Check for consistent trailing slash behavior.
Pass criteria: Enumerate all page route paths in the project. URLs must follow clean, hierarchical patterns with no more than 3 path segments (e.g., /blog/2024/my-post). No hash-based routing for primary pages. No query-string-only page routing. 100% of routes must use path-based routing.
Fail criteria: The site uses hash-based routing (e.g., /#/about) or query-string-only routing (e.g., /?page=about) for primary pages. Report: "X of Y routes use clean paths."
Skip (N/A) when: Never — clean URLs apply to all web projects.
Detail on fail: "Site uses hash-based routing (/#/about, /#/blog) — search engines cannot index individual pages" or "Primary pages use query string routing (?page=about) instead of clean paths"
Remediation: Modern frameworks provide clean URL routing by default. If you're using hash-based routing, switch to the framework's built-in file-system routing:
app/
page.tsx -> /
about/page.tsx -> /about
blog/[slug]/page.tsx -> /blog/my-post
Search engines treat hash fragments as part of the same page, so /#/about and /#/contact would be indexed as a single page.