Repository navigation
Fix SEO indexing: hreflang, canonicals, sitemap, trailing slash - #2193
Conversation
Google Search Console showed 380 not-indexed vs 86 indexed pages. Root causes: missing hreflang tags on rendered pages (only in sitemap), no canonical on homepage, inconsistent canonicals wiping parent hreflang, sitemap only listing English URLs, trailing slash duplicates, and _next/static chunks being crawled as pages. Changes: - Add buildAlternates() utility for consistent canonical + hreflang - Add hreflang tags to all pages via alternates.languages in metadata - Add self-referencing canonical URLs to every page (homepage had none) - Expand sitemap to emit separate entries for each locale - Add missing /docs/custom-commands to sitemap - Remove skipTrailingSlashRedirect to normalize trailing slashes - Block /_next/ in robots.txt to stop chunk crawling
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdded a shared SEO helper Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant EdgeMiddleware as middleware (web/proxy.ts)
participant IntlMiddleware as intlMiddleware
participant Origin as NextApp
Client->>EdgeMiddleware: Request /fr/privacy-policy
EdgeMiddleware->>EdgeMiddleware: detect trailing remainder "/privacy-policy"
EdgeMiddleware->>Client: 301 Redirect -> /privacy-policy
Note right of Client: Browser follows 301
Client->>EdgeMiddleware: Request /privacy-policy
EdgeMiddleware->>IntlMiddleware: pass-through to i18n middleware
IntlMiddleware->>Origin: render page (generateMetadata uses buildAlternates)
Origin-->>Client: HTML with alternates canonical metadata
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a2563d81c2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| alternates: { | ||
| canonical: "./", | ||
| }, | ||
| alternates: buildAlternates(locale, "/docs"), |
There was a problem hiding this comment.
Preserve per-page canonicals in docs layout
Setting alternates to buildAlternates(locale, "/docs") at the layout level makes every docs descendant (for example /docs/getting-started, /docs/api, etc.) emit canonical/hreflang URLs for /docs, because those pages do not define their own alternates. This causes multiple distinct docs pages to advertise the same canonical target, which can collapse indexing and undo the SEO fix for the docs section.
Useful? React with 👍 / 👎.
Greptile SummaryThis PR systematically addresses Google Search Console's 380 unindexed pages by adding Confidence Score: 3/5Safe to merge for most of the site, but the docs layout canonical bug means 8+ docs pages still won't have self-referencing canonicals — the primary goal of this PR. The new seo.ts utility, sitemap expansion, robots.txt fix, homepage canonical, and all leaf-page changes are correct. However, the docs layout sets canonical to /docs for all docs sub-pages that don't override it, which is directly contrary to the PR's stated goal of giving every page a correct self-referencing canonical. web/app/[locale]/docs/layout.tsx — and all docs sub-page files (getting-started, configuration, api, notifications, changelog, keyboard-shortcuts, browser-automation, concepts, custom-commands) which lack their own alternates. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
SEO["buildAlternates(locale, path)\nweb/i18n/seo.ts"]
SEO --> RootLayout["[locale]/layout.tsx\nbuildAlternates(locale, '')"]
SEO --> DocsLayout["docs/layout.tsx\nbuildAlternates(locale, '/docs')"]
SEO --> BlogLayout["blog/layout.tsx\nbuildAlternates(locale, '/blog')"]
SEO --> LeafPages["Leaf pages\n(legal, community, nightly, wall-of-love)"]
SEO --> BlogPosts["Blog post pages\nbuildAlternates(locale, '/blog/...')"]
DocsLayout -->|"inherited — no override"| DocsSub["docs/getting-started\ndocs/configuration\ndocs/api … etc.\n⚠️ canonical = /docs (wrong)"]
BlogLayout -->|"overridden by page"| BlogPosts
BlogPosts -->|"correct self-canonical"| OK1["✅ /blog/introducing-cmux etc."]
LeafPages -->|"correct self-canonical"| OK2["✅ /eula, /community, /nightly …"]
RootLayout -->|"correct self-canonical"| OK3["✅ / (homepage)"]
|
| alternates: { | ||
| canonical: "./", | ||
| }, | ||
| alternates: buildAlternates(locale, "/docs"), |
There was a problem hiding this comment.
Docs sub-pages inherit wrong canonical from layout
The docs layout sets alternates: buildAlternates(locale, "/docs"), which Next.js App Router will merge into any docs page that doesn't return its own alternates. Looking at the individual docs pages (getting-started/page.tsx, configuration/page.tsx, api/page.tsx, etc.), they each define generateMetadata returning only { title, description } — no alternates. Next.js shallow-merges metadata up the segment tree, so all those sub-pages will inherit canonical: "https://cmux.com/docs" instead of their own URL.
Before this PR the layout used canonical: "./", which resolved against metadataBase: "https://cmux.com" to the homepage — also wrong. This PR improves it (now points to /docs rather than /), but the sub-pages still don't get self-referencing canonicals, which was one of the primary goals listed in the PR description.
To fully fix this, each docs page's generateMetadata should include its own buildAlternates call:
// e.g. getting-started/page.tsx
alternates: buildAlternates(locale, "/docs/getting-started"),The same gap applies to concepts, configuration, api, notifications, changelog, keyboard-shortcuts, browser-automation, and custom-commands.
| alternates: { | ||
| canonical: "./", | ||
| }, | ||
| alternates: buildAlternates(locale, "/blog"), |
There was a problem hiding this comment.
Blog layout canonical collides with individual post metadata
The blog layout emits alternates: buildAlternates(locale, "/blog"). Because individual blog post pages do define their own alternates they correctly override this. The /blog list page will also be correct since it has no page-level generateMetadata. This is fine — just noting it here for contrast with the docs situation above, where sub-pages do not override the layout canonical.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
web/app/[locale]/layout.tsx (1)
11-11: Avoid duplicated canonical URL construction in metadata.You currently derive URL twice (
openGraph.urlandalternates). Consider deriving once frombuildAlternatesto prevent future drift.♻️ Suggested refactor
- const url = - locale === "en" ? "https://cmux.com" : `https://cmux.com/${locale}`; + const { canonical, languages } = buildAlternates(locale, ""); return { @@ openGraph: { title: t("title"), description: t("ogDescription"), - url, + url: canonical, siteName: "cmux", type: "website", }, @@ - alternates: buildAlternates(locale, ""), + alternates: { canonical, languages }, metadataBase: new URL("https://cmux.com"), };Also applies to: 65-65
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/app/`[locale]/layout.tsx at line 11, The metadata currently constructs the canonical URL in two places (openGraph.url and alternates); refactor to derive the canonical URL once from buildAlternates and reuse it for both openGraph.url and the alternates object to avoid drift. Locate where buildAlternates is imported/used and compute a single canonical variable (e.g., canonicalUrl = buildAlternates(...).canonical or extract the primary URL from buildAlternates result) then set openGraph.url = canonicalUrl and set alternates = buildAlternates(...) (or reuse the same result) so both values come from the same source; update any references in layout.tsx that currently build the URL twice to use this shared canonicalUrl.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@web/app/`[locale]/layout.tsx:
- Line 11: The metadata currently constructs the canonical URL in two places
(openGraph.url and alternates); refactor to derive the canonical URL once from
buildAlternates and reuse it for both openGraph.url and the alternates object to
avoid drift. Locate where buildAlternates is imported/used and compute a single
canonical variable (e.g., canonicalUrl = buildAlternates(...).canonical or
extract the primary URL from buildAlternates result) then set openGraph.url =
canonicalUrl and set alternates = buildAlternates(...) (or reuse the same
result) so both values come from the same source; update any references in
layout.tsx that currently build the URL twice to use this shared canonicalUrl.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: acbe5d93-f13e-4535-9706-26f204a0be1c
📒 Files selected for processing (17)
web/app/[locale]/(legal)/eula/page.tsxweb/app/[locale]/(legal)/privacy-policy/page.tsxweb/app/[locale]/(legal)/terms-of-service/page.tsxweb/app/[locale]/blog/cmd-shift-u/page.tsxweb/app/[locale]/blog/introducing-cmux/page.tsxweb/app/[locale]/blog/layout.tsxweb/app/[locale]/blog/show-hn-launch/page.tsxweb/app/[locale]/blog/zen-of-cmux/page.tsxweb/app/[locale]/community/page.tsxweb/app/[locale]/docs/layout.tsxweb/app/[locale]/layout.tsxweb/app/[locale]/nightly/page.tsxweb/app/[locale]/wall-of-love/page.tsxweb/app/robots.tsweb/app/sitemap.tsweb/i18n/seo.tsweb/next.config.ts
💤 Files with no reviewable changes (1)
- web/next.config.ts
Docs sub-pages and blog index only returned title/description in generateMetadata, so they inherited the parent layout's alternates (pointing to /docs or /blog). Now each page sets its own buildAlternates() with the correct path so canonical and hreflang point to the actual page URL.
Legal pages (privacy policy, TOS, EULA) are untranslated English content. Serving them under every locale creates 54 duplicate URLs. Now: - Middleware 301-redirects /ja/privacy-policy etc. to /privacy-policy - Sitemap only includes English URLs for legal pages (no locale variants) - Legal page metadata uses static English-only canonical
There was a problem hiding this comment.
🧹 Nitpick comments (1)
web/proxy.ts (1)
18-27: Clean implementation that aligns well with sitemap and page metadata.The logic correctly redirects locale-prefixed legal pages to their English canonical paths, consistent with the
englishOnlyset insitemap.tsand the canonical URLs declared in each legal page's metadata.Minor edge case: Paths with trailing slashes (e.g.,
/ja/privacy-policy/) won't match theendsWithcheck and will fall through tointlMiddleware. SinceskipTrailingSlashRedirectwas removed, Next.js should normalize these, but the redirect order may not guarantee the 301 to the bare path. If trailing slash requests are expected, consider:Optional: Handle trailing slash variants
for (const page of legalPages) { - if (pathname.endsWith(page) && pathname !== page) { + const normalizedPath = pathname.endsWith("/") ? pathname.slice(0, -1) : pathname; + if (normalizedPath.endsWith(page) && normalizedPath !== page) { const url = request.nextUrl.clone(); url.pathname = page; return NextResponse.redirect(url, 301); } }Since the canonical tags are still present on the pages, this is low-impact and can be deferred if trailing slash traffic is minimal.
,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/proxy.ts` around lines 18 - 27, The redirect logic for locale-prefixed legal pages (array legalPages checked against request.nextUrl.pathname) misses paths with trailing slashes like "/ja/privacy-policy/"; normalize the pathname before the loop (e.g., remove a trailing slash only for matching) or trim the pathname used in the endsWith and equality checks so pathname.endsWith(page) and pathname !== page work for both "/ja/privacy-policy" and "/ja/privacy-policy/"; update the code that constructs url.pathname (request.nextUrl.clone()) to set the canonical page value (page) when a match is found and continue to use NextResponse.redirect(..., 301) for the redirect.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@web/proxy.ts`:
- Around line 18-27: The redirect logic for locale-prefixed legal pages (array
legalPages checked against request.nextUrl.pathname) misses paths with trailing
slashes like "/ja/privacy-policy/"; normalize the pathname before the loop
(e.g., remove a trailing slash only for matching) or trim the pathname used in
the endsWith and equality checks so pathname.endsWith(page) and pathname !==
page work for both "/ja/privacy-policy" and "/ja/privacy-policy/"; update the
code that constructs url.pathname (request.nextUrl.clone()) to set the canonical
page value (page) when a match is found and continue to use
NextResponse.redirect(..., 301) for the redirect.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 208a2669-6bdb-4cce-8c5d-aa150c4d157d
📒 Files selected for processing (5)
web/app/[locale]/(legal)/eula/page.tsxweb/app/[locale]/(legal)/privacy-policy/page.tsxweb/app/[locale]/(legal)/terms-of-service/page.tsxweb/app/sitemap.tsweb/proxy.ts
✅ Files skipped from review due to trivial changes (3)
- web/app/[locale]/(legal)/privacy-policy/page.tsx
- web/app/[locale]/(legal)/terms-of-service/page.tsx
- web/app/[locale]/(legal)/eula/page.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- web/app/sitemap.ts
There was a problem hiding this comment.
3 issues found across 5 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="web/app/[locale]/(legal)/eula/page.tsx">
<violation number="1" location="web/app/[locale]/(legal)/eula/page.tsx:6">
P1: This metadata hardcodes an English canonical and omits hreflang alternates on a locale route, which can cause non-English EULA URLs to canonicalize incorrectly and lose locale signals.</violation>
</file>
<file name="web/app/[locale]/(legal)/terms-of-service/page.tsx">
<violation number="1" location="web/app/[locale]/(legal)/terms-of-service/page.tsx:6">
P1: This locale route now uses a single hardcoded canonical URL, which regresses locale-aware SEO signals. Generate metadata from `locale` and use `buildAlternates` so each locale has the correct canonical/hreflang set.</violation>
</file>
<file name="web/app/[locale]/(legal)/privacy-policy/page.tsx">
<violation number="1" location="web/app/[locale]/(legal)/privacy-policy/page.tsx:7">
P1: The new static `alternates` value removes locale-aware canonical/hreflang metadata for this `[locale]` route. This can cause locale pages to share one canonical and lose hreflang signals.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| title: "EULA — cmux", | ||
| description: "End-User License Agreement for cmux", | ||
| alternates: { canonical: "./" }, | ||
| alternates: { canonical: "https://cmux.com/eula" }, |
There was a problem hiding this comment.
P1: This metadata hardcodes an English canonical and omits hreflang alternates on a locale route, which can cause non-English EULA URLs to canonicalize incorrectly and lose locale signals.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At web/app/[locale]/(legal)/eula/page.tsx, line 6:
<comment>This metadata hardcodes an English canonical and omits hreflang alternates on a locale route, which can cause non-English EULA URLs to canonicalize incorrectly and lose locale signals.</comment>
<file context>
@@ -1,13 +1,10 @@
+export const metadata: Metadata = {
+ title: "EULA — cmux",
+ description: "End-User License Agreement for cmux",
+ alternates: { canonical: "https://cmux.com/eula" },
+};
</file context>
| title: "Terms of Service — cmux", | ||
| description: "Terms of service for cmux", | ||
| alternates: { canonical: "./" }, | ||
| alternates: { canonical: "https://cmux.com/terms-of-service" }, |
There was a problem hiding this comment.
P1: This locale route now uses a single hardcoded canonical URL, which regresses locale-aware SEO signals. Generate metadata from locale and use buildAlternates so each locale has the correct canonical/hreflang set.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At web/app/[locale]/(legal)/terms-of-service/page.tsx, line 6:
<comment>This locale route now uses a single hardcoded canonical URL, which regresses locale-aware SEO signals. Generate metadata from `locale` and use `buildAlternates` so each locale has the correct canonical/hreflang set.</comment>
<file context>
@@ -1,13 +1,10 @@
+export const metadata: Metadata = {
+ title: "Terms of Service — cmux",
+ description: "Terms of service for cmux",
+ alternates: { canonical: "https://cmux.com/terms-of-service" },
+};
</file context>
| title: "Privacy Policy — cmux", | ||
| description: "Privacy policy for cmux", | ||
| alternates: { canonical: "./" }, | ||
| alternates: { canonical: "https://cmux.com/privacy-policy" }, |
There was a problem hiding this comment.
P1: The new static alternates value removes locale-aware canonical/hreflang metadata for this [locale] route. This can cause locale pages to share one canonical and lose hreflang signals.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At web/app/[locale]/(legal)/privacy-policy/page.tsx, line 7:
<comment>The new static `alternates` value removes locale-aware canonical/hreflang metadata for this `[locale]` route. This can cause locale pages to share one canonical and lose hreflang signals.</comment>
<file context>
@@ -1,14 +1,11 @@
+export const metadata: Metadata = {
+ title: "Privacy Policy — cmux",
+ description: "Privacy policy for cmux",
+ alternates: { canonical: "https://cmux.com/privacy-policy" },
+};
</file context>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 991ecc3264
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const legalPages = ["/privacy-policy", "/terms-of-service", "/eula"]; | ||
| const { pathname } = request.nextUrl; | ||
| for (const page of legalPages) { | ||
| if (pathname.endsWith(page) && pathname !== page) { |
There was a problem hiding this comment.
Limit legal-page redirect to exact locale routes
The new redirect check uses pathname.endsWith(page), which also matches unrelated URLs like /foo/privacy-policy or /docs/eula and permanently redirects them to the legal page instead of returning a 404. This creates soft-404 behavior and can pollute crawl/indexing signals with unexpected 301s from typo or stale links. The redirect should only trigger for true localized legal routes (e.g. /<locale>/privacy-policy) rather than any path suffix match.
Useful? React with 👍 / 👎.
endsWith matched too broadly (e.g. /docs/eula). Now only redirects when the path after the first segment is an exact legal page match.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cc1aef4630
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (legalPages.has(rest)) { | ||
| const url = request.nextUrl.clone(); | ||
| url.pathname = rest; | ||
| return NextResponse.redirect(url, 301); |
There was a problem hiding this comment.
Prevent locale redirect loop on legal pages
This 301 strips locale prefixes from legal routes (e.g. /ja/privacy-policy → /privacy-policy), but createMiddleware(routing) is configured with localePrefix: "as-needed" and default locale detection behavior, so a non-English locale cookie/header can immediately redirect /privacy-policy back to /ja/privacy-policy. In that context users and crawlers can hit a permanent redirect loop on legal pages instead of reaching content; make this path bypass locale detection or handle legal-page localization in a way that cannot bounce between prefixed and unprefixed URLs.
Useful? React with 👍 / 👎.
Without this, a Japanese user hitting /privacy-policy could be redirected by next-intl to /ja/privacy-policy, which our middleware redirects back to /privacy-policy, creating a loop.
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="web/proxy.ts">
<violation number="1" location="web/proxy.ts:23">
P1: Returning `NextResponse.next()` for `/privacy-policy`, `/terms-of-service`, and `/eula` bypasses locale rewriting, but these pages only exist under `app/[locale]`, so canonical legal URLs can break.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
Pages live under app/[locale]/, so skipping next-intl entirely would break route resolution. Rewrite to /en/privacy-policy etc. so Next.js can resolve the [locale] segment correctly.
…flow-ai#2193) * Fix SEO indexing: add hreflang, canonicals, sitemap per-locale entries Google Search Console showed 380 not-indexed vs 86 indexed pages. Root causes: missing hreflang tags on rendered pages (only in sitemap), no canonical on homepage, inconsistent canonicals wiping parent hreflang, sitemap only listing English URLs, trailing slash duplicates, and _next/static chunks being crawled as pages. Changes: - Add buildAlternates() utility for consistent canonical + hreflang - Add hreflang tags to all pages via alternates.languages in metadata - Add self-referencing canonical URLs to every page (homepage had none) - Expand sitemap to emit separate entries for each locale - Add missing /docs/custom-commands to sitemap - Remove skipTrailingSlashRedirect to normalize trailing slashes - Block /_next/ in robots.txt to stop chunk crawling * Add per-page alternates to docs sub-pages and blog index Docs sub-pages and blog index only returned title/description in generateMetadata, so they inherited the parent layout's alternates (pointing to /docs or /blog). Now each page sets its own buildAlternates() with the correct path so canonical and hreflang point to the actual page URL. * Derive openGraph.url from buildAlternates to avoid drift * Redirect non-English legal pages to English, remove from sitemap Legal pages (privacy policy, TOS, EULA) are untranslated English content. Serving them under every locale creates 54 duplicate URLs. Now: - Middleware 301-redirects /ja/privacy-policy etc. to /privacy-policy - Sitemap only includes English URLs for legal pages (no locale variants) - Legal page metadata uses static English-only canonical * Fix legal page redirect to only match /<locale>/<page> paths endsWith matched too broadly (e.g. /docs/eula). Now only redirects when the path after the first segment is an exact legal page match. * Skip next-intl for legal pages to prevent locale redirect loop Without this, a Japanese user hitting /privacy-policy could be redirected by next-intl to /ja/privacy-policy, which our middleware redirects back to /privacy-policy, creating a loop. * Rewrite legal pages to /en/ instead of NextResponse.next() Pages live under app/[locale]/, so skipping next-intl entirely would break route resolution. Rewrite to /en/privacy-policy etc. so Next.js can resolve the [locale] segment correctly. --------- Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
Summary
buildAlternates()utility (i18n/seo.ts) that returns bothcanonicalandlanguages(hreflang) for a given locale and path, used by every page's metadata<link>tags)"./"were wiping parent hreflang)/docs/custom-commandsto sitemapskipTrailingSlashRedirect: truefromnext.config.tsso Next.js normalizes trailing slash duplicates/_next/inrobots.txtto stop ~200 JS/CSS chunk files from being crawled as pagesContext
Google Search Console reported 380 not-indexed pages vs 86 indexed. The coverage report at https://search.google.com/search-console/index?resource_id=sc-domain:cmux.com showed:
_next/staticchunks)"./")/docsredirect,cmux.devdomain redirect)Testing
npm run buildpassesnpx tsc --noEmitpasses<link rel="canonical">and<link rel="alternate" hreflang="...">tags appear in page sourceRelated
Summary by CodeRabbit
New Features
Improvements
Chores