Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .vale/styles/FernStyles/Acronyms.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,4 @@ exceptions:
- MDN
- UUID
- WSS
- GEO
1 change: 1 addition & 0 deletions .vale/styles/FernStyles/Headings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,4 @@ exceptions:
- LaTeX
- MDN
- WSS
- GEO
2 changes: 2 additions & 0 deletions fern/products/docs/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,8 @@ navigation:
slug: seo
collapsed: true
contents:
- page: Overview
path: ./pages/seo/overview.mdx
- page: Setting SEO metadata
path: ./pages/seo/metadata.mdx
- page: Configuring slugs
Expand Down
267 changes: 229 additions & 38 deletions fern/products/docs/pages/seo/metadata.mdx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
---
title: Configure SEO metadata
description: Configure SEO metadata in Fern docs with page-level frontmatter and site-wide settings. Control titles, descriptions, and social media previews.
max-toc-depth: 2
max-toc-depth: 3
---

Fern automatically generates all SEO metadata for every page in your documentation site. Search engines and social media previews work out of the box with no configuration required.

When you do want to customize SEO settings, you can set defaults [at the site level](#website-metadata) or override them on [individual pages](#page-level-configuration). Keep titles between 50-60 characters and descriptions between 150-160 characters for optimal display.
When you want to customize how your pages appear in search results or social previews, you can set defaults [at the site level](#site-wide-defaults) or override them on [individual pages](#page-level-overrides).

<Note>
The metadata configurations on this page are for SEO and social tags that aren't visible to users. For visible footer links, see [footer links configuration](/learn/docs/configuration/site-level-settings#footer-links-configuration).
Expand All @@ -16,50 +14,243 @@ When you do want to customize SEO settings, you can set defaults [at the site le

Fern looks for metadata values in this order:

1. **Page frontmatter** - Custom SEO values for a specific page
2. **Site-level `docs.yml`** - Default SEO values for all pages
3. **Automatic defaults** - Generated from your page's existing title, description, etc.
1. **Page frontmatter** Custom SEO values for a specific page
2. **Site-level `docs.yml`** Default SEO values for all pages
3. **Automatic defaults** Generated from your page's existing `title`, `description`, `subtitle`, or `excerpt` fields

<Info title="Example">
<Info title="Example">
`og:image` is the image that appears in social media previews. If you don't set `og:image` in a page's frontmatter, Fern uses the site-wide `og:image` from `docs.yml`. If neither is configured, the tag is omitted entirely.
</Info>

## Site-wide defaults

Set default SEO metadata for your entire site in `docs.yml`. These apply to all pages unless overridden by page-specific metadata.

```yaml docs.yml
metadata:
# Core metadata
og:site_name: "Square Developer Documentation"
og:title: "Square Developer Platform | Payments, Commerce & Banking APIs"
og:description: "Build with Square's suite of APIs and SDKs. Accept payments, manage inventory, create loyalty programs, and access financial services."
og:url: "https://developer.squareup.com/docs"
og:locale: "en_US"
canonical-host: "developer.squareup.com"

# Social image
og:image: "https://developer.squareup.com/images/docs-social-card.png"
og:image:width: 1200
og:image:height: 630
og:logo: "https://developer.squareup.com/images/square-logo.png"

# Twitter / X
twitter:title: "Square Developer Platform Documentation"
twitter:description: "Integrate payments, point-of-sale, inventory, and financial services into your applications with Square's developer platform."
twitter:handle: "@SquareDev"
twitter:image: "https://developer.squareup.com/images/twitter-card.png"
twitter:site: "@Square"
twitter:card: "summary_large_image"
```

### Core metadata

Identity and descriptive fields used by search engines and shared across social platforms. Keep titles between 50–60 characters and descriptions between 150–160 characters for optimal display. Set `canonical-host` if your docs are accessible at multiple URLs (e.g., a custom domain and a `buildwithfern.com` subdomain) to tell search engines which URL is authoritative.

<ParamField path="metadata.og:site_name" type="string" required={false} toc={true}>
The name of your website for Open Graph tags.
</ParamField>

<ParamField path="metadata.og:title" type="string" required={false} toc={true}>
The title shown in social media previews.
</ParamField>

<ParamField path="metadata.og:description" type="string" required={false} toc={true}>
The description shown in social media previews.
</ParamField>

<ParamField path="metadata.og:url" type="string" required={false} toc={true}>
The canonical URL of your documentation.
</ParamField>

<ParamField path="metadata.og:locale" type="string" required={false} toc={true}>
The locale of your content (e.g., `en_US`).
</ParamField>

<ParamField path="metadata.canonical-host" type="string" required={false} toc={true}>
The host of your documentation website. Used to set the canonical URL for metadata tags and documents like the sitemap. Defaults to the URL defined in `instances`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 [vale] reported by reviewdog 🐶
[Microsoft.URLFormat] Use 'of' (not 'for') to describe the relationship of the word URL to a resource.

</ParamField>

### Social image

The image displayed when your docs are shared on LinkedIn, Slack, Discord, and other platforms. Use a 1200x630px image for the best display across platforms — this is the standard Open Graph size and will render correctly in most previews. Avoid embedding text in the image since it may be cropped on some platforms.

<ParamField path="metadata.og:image" type="string" required={false} toc={true}>
The image shown in social media previews. Recommended size is 1200x630 pixels.
</ParamField>

<ParamField path="metadata.og:image:width" type="number" required={false} toc={true}>
The width of your Open Graph image in pixels.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [vale] reported by reviewdog 🐶
[Microsoft.Units] Don't spell out the number in 'in pixels'.

</ParamField>

<ParamField path="metadata.og:image:height" type="number" required={false} toc={true}>
The height of your Open Graph image in pixels.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [vale] reported by reviewdog 🐶
[Microsoft.Units] Don't spell out the number in 'in pixels'.

</ParamField>

<ParamField path="metadata.og:logo" type="string" required={false} toc={true}>
URL to your company logo.
</ParamField>

### Twitter / X
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 [vale] reported by reviewdog 🐶
[FernStyles.Headings] 'Twitter / X' should use sentence-style capitalization.


Controls how your docs appear in Twitter Card previews when shared on X.

<ParamField path="metadata.twitter:title" type="string" required={false} toc={true}>
The title shown in Twitter Card previews.
</ParamField>

<ParamField path="metadata.twitter:description" type="string" required={false} toc={true}>
The description shown in Twitter Card previews.
</ParamField>

<ParamField path="metadata.twitter:handle" type="string" required={false} toc={true}>
Your company's Twitter handle.
</ParamField>

<ParamField path="metadata.twitter:image" type="string" required={false} toc={true}>
The image shown in Twitter Card previews.
</ParamField>

<ParamField path="metadata.twitter:site" type="string" required={false} toc={true}>
The Twitter handle for your website.
</ParamField>

<ParamField path="metadata.twitter:card" type="string" required={false} toc={true}>
The Twitter Card type. Options are `summary`, `summary_large_image`, `app`, or `player`.
</ParamField>

## Page-level overrides

Configure SEO metadata in your page's frontmatter to control how individual pages appear in search results and social shares. These settings override site-wide defaults.

<Info>
Only the documented SEO fields are added to the HTML `<head>` as meta tags. Custom frontmatter fields won't automatically appear in your page metadata. To add custom metadata, use [custom JavaScript](/learn/docs/customization/custom-css-js#custom-javascript).
</Info>

<CodeBlock title="plantstore-quickstart.mdx">
```mdx
---
title: PlantStore API Quick Start
headline: "Get Started with PlantStore API | Developer Documentation"
keywords: plants, garden, nursery
canonical-url: https://docs.plantstore.dev/welcome
og:image: https://plantstore.dev/images/api-docs-banner.png
og:image:width: 1200
og:image:height: 630
twitter:card: summary_large_image
twitter:site: "@PlantStoreAPI"
noindex: false
nofollow: false
---
```
</CodeBlock>

### Basic metadata

Page title, URL, and keyword fields used by search engines. Use `headline` when you need a different title for search engines than what appears as the visible page heading.

<ParamField path="headline" type="string" required={false} toc={true}>
When set, the `<title />` tag in the document head will use this value rather than the `title` property. For example, your `title` might be "Quickstart" (shown in the sidebar and as the H1), while `headline` could be "Quickstart | PlantStore API Docs" to give search engines more context. If not set, Fern uses `title` with your site name appended.
</ParamField>

<ParamField path="canonical-url" type="string" required={false} toc={true}>
Overrides the canonical URL for this page. Must be a full URL including the protocol (e.g., `https://buildwithfern.com/learn/docs/content/frontmatter`).
</ParamField>

<ParamField path="keywords" type="string" required={false} toc={true}>
Comma-separated keywords relevant to the page (e.g., `plants, garden, nursery`). Accepts only comma-separated strings, not arrays.
</ParamField>

### Open Graph

Controls how this page appears when shared on LinkedIn, Slack, Discord, and other platforms that support Open Graph. Keep titles between 50–60 characters and descriptions between 150–160 characters for optimal display.

<ParamField path="og:site_name" type="string" required={false} toc={true}>
The name of your website as it should appear when your content is shared.
</ParamField>

<ParamField path="og:title" type="string" required={false} toc={true}>
The title of your page as it should appear when your content is shared.
</ParamField>

<ParamField path="og:description" type="string" required={false} toc={true}>
The description of your page as it should appear when your content is shared.
</ParamField>

<ParamField path="og:url" type="string" required={false} toc={true}>
The URL of your page.
</ParamField>

<ParamField path="og:image" type="string" required={false} toc={true}>
The URL of the image displayed when your content is shared.
</ParamField>

<ParamField path="og:image:width" type="number" required={false} toc={true}>
The width of the image in pixels.
</ParamField>

<ParamField path="og:image:height" type="number" required={false} toc={true}>
The height of the image in pixels.
</ParamField>

<ParamField path="og:locale" type="string" required={false} toc={true}>
The locale of the page, typically in the format `language_TERRITORY` (e.g., `en_US`).
</ParamField>

<ParamField path="og:logo" type="string" required={false} toc={true}>
The URL of your logo image displayed when your content is shared.
</ParamField>

### Twitter / X

Controls how this page appears in Twitter Card previews when shared on X.

<ParamField path="twitter:title" type="string" required={false} toc={true}>
The title of your page as it should appear in a tweet.
</ParamField>

<ParamField path="twitter:description" type="string" required={false} toc={true}>
The description of your page as it should appear in a tweet.
</ParamField>

<ParamField path="twitter:handle" type="string" required={false} toc={true}>
The Twitter handle of the page creator or site.
</ParamField>

## What Fern automatically generates
<ParamField path="twitter:image" type="string" required={false} toc={true}>
The URL of the image displayed in a tweet.
</ParamField>

For every page, Fern creates these SEO tags in your HTML:
<ParamField path="twitter:site" type="string" required={false} toc={true}>
The Twitter handle for your website.
</ParamField>

<AccordionGroup>
<Accordion title="HTML meta tags">
- `<title>` tag with site-wide suffix (e.g., "Page Title | Your Site Name")
- Meta description (pulled from your `description`, `subtitle`, or `excerpt` fields)
- Meta keywords (when you provide them)
- Canonical URL (from your page slug or `canonical-url` override)
- Robots meta tags (`noindex`/`nofollow` when configured)
- Favicon link tag
</Accordion>
<Accordion title="Open Graph tags (for LinkedIn, Slack, Discord, etc.)">
- `og:title`, `og:description`, `og:image` - What appears in social previews
- `og:url` - Canonical URL of the page
- `og:site_name` - Your website name
- `og:locale` - Content language (e.g., "en_US")
- `og:image:width`, `og:image:height` - Image dimensions
</Accordion>
<Accordion title="Twitter Card tags">
- `twitter:title`, `twitter:description`, `twitter:image` - What appears in Twitter/X previews
- `twitter:site`, `twitter:creator` - Your Twitter handles
- `twitter:card` - Card type (e.g., "summary_large_image")
</Accordion>
</AccordionGroup>
<ParamField path="twitter:url" type="string" required={false} toc={true}>
The URL of your page.
</ParamField>

## Website metadata
<ParamField path="twitter:card" type="string" required={false} toc={true}>
The type of card used for sharing on Twitter. Options: `summary`, `summary_large_image`, `app`, `player`.
</ParamField>

Set default SEO metadata for your entire documentation site in [`docs.yml`](/docs/configuration/site-level-settings). These settings apply to all pages unless overridden by page-specific metadata.
### Indexing

<Markdown src="/snippets/seo-metadata-site.mdx" />
Control whether search engines index this page or follow its links. These are distinct: `noindex` removes the page from search results entirely, while `nofollow` keeps the page in results but tells search engines not to pass ranking credit through its links.

## Page-level configuration
Use `noindex` for internal-only pages, staging content, or pages you don't want surfaced in search. Use `nofollow` sparingly — it's rarely needed for documentation.

Configure SEO metadata in your page's [frontmatter](/docs/configuration/page-level-settings) to control how individual pages appear in search results and social media shares. These settings override site-wide settings.
<ParamField path="noindex" type="boolean" required={false} default={false} toc={true}>
If `true`, the page won't be indexed by search engines and will be excluded from [`llms.txt`](/learn/docs/ai-features/llms-txt) endpoints.
</ParamField>

<Markdown src="/snippets/seo-metadata-page.mdx" />
<ParamField path="nofollow" type="boolean" required={false} default={false} toc={true}>
If `true`, search engines won't follow any links on the page.
</ParamField>
20 changes: 20 additions & 0 deletions fern/products/docs/pages/seo/overview.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
title: Overview of SEO & GEO
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 [vale] reported by reviewdog 🐶
[FernStyles.Acronyms] 'GEO' has no definition.

description: Understand Fern's built-in features for search engine optimization (SEO) and generative engine optimization (GEO) to maximize the reach and discoverability of your documentation.
---

Fern optimizes your documentation for both traditional search engines and AI-powered tools out of the box. SEO ensures your pages rank well in Google, Bing, and other search engines, while GEO (Generative Engine Optimization) ensures AI tools like ChatGPT, Claude, and Cursor can efficiently consume and reference your content.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 [vale] reported by reviewdog 🐶
[FernStyles.Acronyms] 'GEO' has no definition.


Out of the box, Fern generates meta tags, social previews, canonical URLs, and clean slugs for every page — including AI-optimized content via [`llms.txt`](/learn/docs/ai-features/llms-txt). When you want more control, you can customize:

<CardGroup cols={3}>
<Card title="SEO metadata" icon="fa-duotone fa-tags" href="/learn/docs/seo/setting-seo-metadata">
Configure titles, descriptions, and social previews for search engines
</Card>
<Card title="Slugs" icon="fa-duotone fa-link" href="/learn/docs/seo/configuring-slugs">
Customize URL paths for clean, meaningful page addresses
</Card>
<Card title="Redirects" icon="fa-duotone fa-arrow-right-arrow-left" href="/learn/docs/seo/redirects">
Set up redirects to preserve SEO equity when pages move
</Card>
</CardGroup>
25 changes: 5 additions & 20 deletions fern/products/docs/pages/seo/redirects.mdx
Original file line number Diff line number Diff line change
@@ -1,26 +1,11 @@
---
title: Configure links and redirects for your site
subtitle: Learn how to configure redirects and external links in Fern Docs. Set up exact path redirects, regex patterns, and navigation links for your documentation site.
title: Configure redirects
subtitle: Learn how to configure redirects in Fern Docs. Set up exact path redirects and regex patterns to preserve SEO equity when pages move.
---

## Redirects

<Markdown src="/snippets/redirects.mdx" />

## Links

You can add a link to an external page within your sidebar navigation with the following configuration:

```yaml title="docs.yml"
navigation:
- section: Home
contents:
- page: Introduction
path: ./intro.mdx
- link: Our YouTube Channel
href: https://www.youtube.com/
```
<Tip>
To add external links to your sidebar navigation, see [Navigation](/learn/docs/configuration/navigation#links).
</Tip>

<Frame>
<img src="external-link.png" alt="An external link within navigation" />
</Frame>
Loading