MoveFast includes a complete SEO system, machine-readable public content, and optional Google Analytics integration. Public pages get canonical metadata, social sharing data, structured data, and deliberate crawl directives out of the box.
Metadata System
MoveFast uses Next.js built-in metadata API with a helper function that generates consistent SEO tags across all pages.
How It Works
The createMetadata() function in src/lib/seo/metadata.ts generates:
- Page title (with site name template)
- Meta description
- Keywords
- Canonical URL
- Open Graph tags (title, description, image, type)
- Twitter Card tags
- Robots directives (index/noindex)
- Google preview controls for large images and complete snippets
- RSS, Atom, and JSON Feed discovery links
Per-Page Metadata
Each page exports metadata using the helper:
import { createMetadata } from "@/lib/seo/metadata";
export const metadata = createMetadata({
title: "Your Page Title",
description: "A description for search engines and social sharing.",
path: "/your-page",
keywords: ["keyword1", "keyword2"],
});Available Options
interface SEOConfig {
title: string; // Page title
description: string; // Meta description
path?: string; // URL path (for canonical URL)
keywords?: readonly string[]; // SEO keywords
image?: string; // OG image URL (defaults to /og-image.svg)
noIndex?: boolean; // Set true to hide from search engines
type?: "website" | "article" | "profile"; // OG type
publishedTime?: string; // For blog articles
modifiedTime?: string; // For blog articles
authors?: string[]; // For blog articles
}Pre-Built Page Metadata
Common pages already have metadata configured via pageMetadata:
import { pageMetadata } from "@/lib/seo/metadata";
// Use in your page:
export const metadata = pageMetadata.pricing();
export const metadata = pageMetadata.blog();
export const metadata = pageMetadata.contact();Open Graph Image
The default OG image is at public/og-image.svg. This is the image shown when your site is shared on Twitter, LinkedIn, Facebook, etc.
To replace it:
- Create a 1200x630 image
- Save it as
public/og-image.svg(or any name) - If using a different filename, update
DEFAULT_OG_IMAGEinsrc/lib/seo/metadata.ts
Sitemap
MoveFast auto-generates a sitemap at /sitemap.xml. It includes:
- All public pages (home, pricing, contact, etc.)
- All published blog posts
- All published documentation pages
The sitemap is generated at build time by Next.js from src/app/sitemap.ts.
Only canonical, indexable pages belong in the sitemap. Private account routes and legal pages marked noIndex are intentionally excluded. Blog entries use their published date as lastModified; static pages do not claim a new modification date on every build.
Robots.txt
The robots.txt file at /robots.txt tells search engines what to crawl. It is generated from src/app/robots.ts and:
- Allows all crawlers on public pages
- Blocks crawling of admin, auth, profile, and billing routes
- Allows the public
/api/aisnapshot and Markdown content endpoints - Explicitly allows search and user-requested crawlers such as OAI-SearchBot and Claude-SearchBot
- Blocks the listed model-training crawlers by default; change the
TRAINING_BOTSrule if your policy is different - Points to the sitemap URL
Structured Data
MoveFast renders JSON-LD that matches visible page content:
- Organization and WebSite entities in the root layout
- WebPage, SoftwareApplication, and FAQPage entities on the home page
- CollectionPage and ItemList data on the blog index
- BlogPosting and BreadcrumbList data on each article
- TechArticle and BreadcrumbList data on documentation pages
The builders live in src/lib/seo/structured-data.ts. The JsonLd component escapes < characters before rendering JSON so content cannot break out of the script tag.
Keep structured data aligned with what a visitor can actually see. Do not add reviews, ratings, prices, or features that are not present on the corresponding page.
AI and Agent Discovery
The HTML pages remain the canonical source. The additional discovery endpoints make the same public information easier for agents and feed readers to retrieve:
| Endpoint | Purpose |
|---|---|
/llms.txt | Concise site identity and curated first-party content map |
/llms-full.txt | Combined public documentation and blog context |
/ai.txt | Retrieval, attribution, freshness, and restricted-route guidance |
/api/ai | Bounded JSON snapshot of public pages and recent content |
/api/md/docs/[slug] | Clean Markdown for a published documentation page |
/api/md/blogs/[slug] | Clean Markdown for a published blog article |
/.well-known/api-catalog | Machine-readable catalog of public discovery endpoints and feeds |
These files supplement normal SEO. They do not replace crawlable HTML, internal links, accurate metadata, or useful first-party content.
The global HTTP Link header in next.config.ts advertises the discovery files and feeds without adding route-specific client code.
Blog Feeds
Published blogs are available as:
- RSS at
/blogs/rss.xml - Atom at
/blogs/atom.xml - JSON Feed at
/blogs/feed.json
All three feeds are generated from the same MDX frontmatter used by the blog pages, so titles, dates, excerpts, authors, and canonical URLs stay synchronized.
Google Analytics
MoveFast supports Google Analytics 4 (GA4) through a dedicated component.
Setup
- Create a GA4 property at analytics.google.com
- Get your Measurement ID (starts with
G-) - Add it to your environment:
NEXT_PUBLIC_GA_MEASUREMENT_ID=G-XXXXXXXXXXThat is it. The analytics script loads automatically on all pages.
How It Works
The GoogleAnalytics component in src/components/analytics/GoogleAnalytics.tsx injects the GA4 script tag in the root layout. It only loads when NEXT_PUBLIC_GA_MEASUREMENT_ID is set and non-empty.
Disabling Analytics
To disable analytics (e.g., in development), simply do not set the NEXT_PUBLIC_GA_MEASUREMENT_ID variable, or leave it empty.
Page Titles
The root layout sets a title template:
title: {
default: "MoveFast",
template: "%s | MoveFast",
}This means:
- The home page title is just "MoveFast"
- Other pages are formatted as "Page Title | MoveFast"
To change the site name, update WEBSITE.NAME in src/constants/website.ts.
Legal Pages and noIndex
Legal pages (privacy policy, terms of service, cookie policy) are marked as noIndex: true so search engines do not index them. This keeps your search results clean and focused on product pages.
export const metadata = createMetadata({
title: "Privacy Policy",
description: "...",
noIndex: true, // Won't appear in search results
});Blog SEO
Blog posts get full article-type metadata and matching BlogPosting JSON-LD including:
- Published date
- Modified date
- Author name
- Article-specific OG type
- Featured image as OG image
This is handled automatically from the blog post frontmatter (title, description, date, author, image fields).
Tips
- Always set unique
titleanddescriptionfor every page. Duplicate metadata hurts rankings. - Keep descriptions concise, specific, and accurate; search engines may display a different snippet when it better answers the query.
- Use descriptive, keyword-rich titles but keep them natural.
- Replace the default OG image with something branded. It is the first thing people see when your link is shared.
- Submit your sitemap to Google Search Console after deploying for faster indexing.
- Keep
NEXT_PUBLIC_WEBSITE_URLset to the production origin so canonical URLs, feeds, and structured data never point to localhost.
