From d33e1d1cf93b52add8659ec1ddea106f4aa032d0 Mon Sep 17 00:00:00 2001 From: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com> Date: Wed, 18 Mar 2026 03:22:58 -0700 Subject: [PATCH] SEO hardening: canonicals, sitemap x-default, legal dates (#1741) - Add canonical tags to community, nightly, wall-of-love, and all legal pages (prevents duplicate content with trailing slashes) - Add x-default hreflang to sitemap for all entries - Add legal pages (privacy-policy, terms-of-service, eula) to sitemap - Stabilize sitemap lastModified to fixed dates instead of new Date() (avoids noisy lastmod changes on every deploy) - Update legal page dates to March 18, 2026 (domain migration is a material change to the "Site" definition) - Update copyright year to 2026 Co-authored-by: Lawrence Chen --- web/app/[locale]/(legal)/eula/page.tsx | 3 +- .../[locale]/(legal)/privacy-policy/page.tsx | 3 +- .../(legal)/terms-of-service/page.tsx | 5 ++-- web/app/[locale]/community/page.tsx | 1 + web/app/[locale]/nightly/page.tsx | 1 + web/app/[locale]/wall-of-love/page.tsx | 1 + web/app/sitemap.ts | 30 +++++++++++-------- 7 files changed, 27 insertions(+), 17 deletions(-) diff --git a/web/app/[locale]/(legal)/eula/page.tsx b/web/app/[locale]/(legal)/eula/page.tsx index 85676b2d..ddc9ae0a 100644 --- a/web/app/[locale]/(legal)/eula/page.tsx +++ b/web/app/[locale]/(legal)/eula/page.tsx @@ -3,13 +3,14 @@ import type { Metadata } from "next"; export const metadata: Metadata = { title: "EULA — cmux", description: "End-User License Agreement for cmux", + alternates: { canonical: "./" }, }; export default function EulaPage() { return ( <>

EULA

-

Last updated: December 2, 2025

+

Last updated: March 18, 2026

Please read this End-User License Agreement carefully before diff --git a/web/app/[locale]/(legal)/privacy-policy/page.tsx b/web/app/[locale]/(legal)/privacy-policy/page.tsx index 98792851..d6b767db 100644 --- a/web/app/[locale]/(legal)/privacy-policy/page.tsx +++ b/web/app/[locale]/(legal)/privacy-policy/page.tsx @@ -4,13 +4,14 @@ import { Link } from "../../../../i18n/navigation"; export const metadata: Metadata = { title: "Privacy Policy — cmux", description: "Privacy policy for cmux", + alternates: { canonical: "./" }, }; export default function PrivacyPolicyPage() { return ( <>

Privacy Policy

-

Last updated: December 2, 2025

+

Last updated: March 18, 2026

Manaflow (the “Company”) is committed to maintaining robust diff --git a/web/app/[locale]/(legal)/terms-of-service/page.tsx b/web/app/[locale]/(legal)/terms-of-service/page.tsx index 76b3f48b..c02b8ab8 100644 --- a/web/app/[locale]/(legal)/terms-of-service/page.tsx +++ b/web/app/[locale]/(legal)/terms-of-service/page.tsx @@ -3,13 +3,14 @@ import type { Metadata } from "next"; export const metadata: Metadata = { title: "Terms of Service — cmux", description: "Terms of service for cmux", + alternates: { canonical: "./" }, }; export default function TermsOfServicePage() { return ( <>

Terms of Service

-

Last revised on: December 2, 2025

+

Last revised on: March 18, 2026

The website located at{" "} @@ -180,7 +181,7 @@ export default function TermsOfServicePage() {

- Copyright © 2025 Manaflow. All rights reserved. + Copyright © 2026 Manaflow. All rights reserved.

); diff --git a/web/app/[locale]/community/page.tsx b/web/app/[locale]/community/page.tsx index cce06e02..3742df3b 100644 --- a/web/app/[locale]/community/page.tsx +++ b/web/app/[locale]/community/page.tsx @@ -8,6 +8,7 @@ export async function generateMetadata({ params }: { params: Promise<{ locale: s return { title: t("metaTitle"), description: t("metaDescription"), + alternates: { canonical: "./" }, }; } diff --git a/web/app/[locale]/nightly/page.tsx b/web/app/[locale]/nightly/page.tsx index 35af11df..d3fb1a31 100644 --- a/web/app/[locale]/nightly/page.tsx +++ b/web/app/[locale]/nightly/page.tsx @@ -12,6 +12,7 @@ export async function generateMetadata({ return { title: t("metaTitle"), description: t("metaDescription"), + alternates: { canonical: "./" }, }; } diff --git a/web/app/[locale]/wall-of-love/page.tsx b/web/app/[locale]/wall-of-love/page.tsx index 5f26b0d8..c1ec7d41 100644 --- a/web/app/[locale]/wall-of-love/page.tsx +++ b/web/app/[locale]/wall-of-love/page.tsx @@ -9,6 +9,7 @@ export async function generateMetadata({ params }: { params: Promise<{ locale: s return { title: t("metaTitle"), description: t("metaDescription"), + alternates: { canonical: "./" }, }; } diff --git a/web/app/sitemap.ts b/web/app/sitemap.ts index 6705f4dc..ecc6e0bb 100644 --- a/web/app/sitemap.ts +++ b/web/app/sitemap.ts @@ -5,23 +5,26 @@ export default function sitemap(): MetadataRoute.Sitemap { const base = "https://cmux.com"; const paths = [ - { path: "", lastModified: new Date(), changeFrequency: "weekly" as const, priority: 1 }, - { path: "/blog", lastModified: new Date(), changeFrequency: "weekly" as const, priority: 0.8 }, + { path: "", lastModified: "2026-03-18", changeFrequency: "weekly" as const, priority: 1 }, + { path: "/blog", lastModified: "2026-03-18", changeFrequency: "weekly" as const, priority: 0.8 }, { path: "/blog/show-hn-launch", lastModified: "2026-02-21", changeFrequency: "monthly" as const, priority: 0.7 }, { path: "/blog/introducing-cmux", lastModified: "2026-02-12", changeFrequency: "monthly" as const, priority: 0.7 }, { path: "/blog/zen-of-cmux", lastModified: "2026-02-27", changeFrequency: "monthly" as const, priority: 0.7 }, { path: "/blog/cmd-shift-u", lastModified: "2026-03-04", changeFrequency: "monthly" as const, priority: 0.7 }, - { path: "/docs/getting-started", lastModified: new Date(), changeFrequency: "monthly" as const, priority: 0.9 }, - { path: "/docs/concepts", lastModified: new Date(), changeFrequency: "monthly" as const, priority: 0.8 }, - { path: "/docs/configuration", lastModified: new Date(), changeFrequency: "monthly" as const, priority: 0.8 }, - { path: "/docs/keyboard-shortcuts", lastModified: new Date(), changeFrequency: "monthly" as const, priority: 0.7 }, - { path: "/docs/api", lastModified: new Date(), changeFrequency: "monthly" as const, priority: 0.8 }, - { path: "/docs/notifications", lastModified: new Date(), changeFrequency: "monthly" as const, priority: 0.8 }, - { path: "/docs/changelog", lastModified: new Date(), changeFrequency: "weekly" as const, priority: 0.5 }, - { path: "/docs/browser-automation", lastModified: new Date(), changeFrequency: "monthly" as const, priority: 0.8 }, - { path: "/community", lastModified: new Date(), changeFrequency: "monthly" as const, priority: 0.5 }, - { path: "/wall-of-love", lastModified: new Date(), changeFrequency: "monthly" as const, priority: 0.5 }, - { path: "/nightly", lastModified: new Date(), changeFrequency: "weekly" as const, priority: 0.6 }, + { path: "/docs/getting-started", lastModified: "2026-03-18", changeFrequency: "monthly" as const, priority: 0.9 }, + { path: "/docs/concepts", lastModified: "2026-03-18", changeFrequency: "monthly" as const, priority: 0.8 }, + { path: "/docs/configuration", lastModified: "2026-03-18", changeFrequency: "monthly" as const, priority: 0.8 }, + { path: "/docs/keyboard-shortcuts", lastModified: "2026-03-18", changeFrequency: "monthly" as const, priority: 0.7 }, + { path: "/docs/api", lastModified: "2026-03-18", changeFrequency: "monthly" as const, priority: 0.8 }, + { path: "/docs/notifications", lastModified: "2026-03-18", changeFrequency: "monthly" as const, priority: 0.8 }, + { path: "/docs/changelog", lastModified: "2026-03-18", changeFrequency: "weekly" as const, priority: 0.5 }, + { path: "/docs/browser-automation", lastModified: "2026-03-18", changeFrequency: "monthly" as const, priority: 0.8 }, + { path: "/community", lastModified: "2026-03-18", changeFrequency: "monthly" as const, priority: 0.5 }, + { path: "/wall-of-love", lastModified: "2026-03-18", changeFrequency: "monthly" as const, priority: 0.5 }, + { path: "/nightly", lastModified: "2026-03-18", changeFrequency: "weekly" as const, priority: 0.6 }, + { path: "/privacy-policy", lastModified: "2026-03-18", changeFrequency: "yearly" as const, priority: 0.3 }, + { path: "/terms-of-service", lastModified: "2026-03-18", changeFrequency: "yearly" as const, priority: 0.3 }, + { path: "/eula", lastModified: "2026-03-18", changeFrequency: "yearly" as const, priority: 0.3 }, ]; const entries: MetadataRoute.Sitemap = []; @@ -32,6 +35,7 @@ export default function sitemap(): MetadataRoute.Sitemap { alternates[locale] = locale === "en" ? `${base}${path}` : `${base}/${locale}${path}`; } + alternates["x-default"] = `${base}${path}`; entries.push({ url: `${base}${path}`,