diff --git a/fern/products/docs/pages/changelog/2026-04-29.mdx b/fern/products/docs/pages/changelog/2026-04-29.mdx
new file mode 100644
index 0000000000..713d800000
--- /dev/null
+++ b/fern/products/docs/pages/changelog/2026-04-29.mdx
@@ -0,0 +1,23 @@
+---
+tags: ["seo", "configuration"]
+---
+
+## Redesigned dynamic OG images
+
+Dynamic OG images have a new layout with fine-grained control over the logo variant, text and background colors, and which elements appear (section, description, URL, gradient).
+
+```yaml docs.yml
+metadata:
+ og:dynamic: true
+ og:background-image: ./images/og-background.png
+ og:dynamic:text-color: "#1a1a1a"
+ og:dynamic:background-color: "#ffffff"
+ og:dynamic:logo-color: dark
+ og:dynamic:show-logo: true
+ og:dynamic:show-section: true
+ og:dynamic:show-description: true
+ og:dynamic:show-url: true
+ og:dynamic:show-gradient: true
+```
+
+
diff --git a/fern/products/docs/pages/seo/metadata.mdx b/fern/products/docs/pages/seo/metadata.mdx
index 878663261a..6d858b4368 100644
--- a/fern/products/docs/pages/seo/metadata.mdx
+++ b/fern/products/docs/pages/seo/metadata.mdx
@@ -1,7 +1,7 @@
---
title: Configure SEO metadata
description: Configure SEO metadata in Fern docs with page-level frontmatter and site-wide settings. Control titles, descriptions, social media previews, and sitemap timestamps.
-max-toc-depth: 3
+max-toc-depth: 4
---
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).
@@ -63,91 +63,135 @@ Identity and descriptive fields used by search engines and shared across social
The name of your website for Open Graph tags.
-
- The title shown in social media previews.
+
+ The title shown in social media previews. Falls back to the page's `title` when unset.
-
- The description shown in social media previews.
+
+ The description shown in social media previews. Falls back to the page's `description`, `subtitle`, or `excerpt` when unset.
-
- The canonical URL of your documentation.
+
+ The canonical URL of your documentation. Falls back to the page's resolved URL when unset.
- The locale of your content (e.g., `en_US`).
+ The locale of your content (e.g., `en_US`). No default; the tag is omitted when unset.
-
+
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`.
### 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.
+The image displayed when your docs are shared on LinkedIn, Slack, Discord, and other platforms. You can either set a single image that applies to every page, or have Fern dynamically generate a unique image per page.
+
+#### Manual
+
+Set one static image with `og:image` that applies to every page. 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.
- The image shown in social media previews. Recommended size is 1200x630 pixels.
+ The image shown in social media previews. Recommended size is 1200x630 pixels. No default; the tag is omitted when unset.
- The width of your Open Graph image in pixels.
+ The width of your Open Graph image in pixels. Only applied when `og:image` is set.
- The height of your Open Graph image in pixels.
+ The height of your Open Graph image in pixels. Only applied when `og:image` is set.
- URL to your company logo.
+ URL to your company logo. No default; the tag is omitted when unset.
-### Dynamic OG images [#dynamic-og-images]
+#### Dynamic [#dynamic-og-images]
-Instead of using a single static image for all pages, you can enable dynamic OG image generation. When enabled, Fern automatically generates a unique `og:image` for each page that doesn't have one [set in frontmatter](#open-graph).
+Instead of using a single static image for all pages, you can enable dynamic OG image generation. When enabled, Fern automatically generates a unique `og:image` for each page that doesn't have one [set in frontmatter](#open-graph). The `og:dynamic:*` sub-settings and `og:background-image` below are only read when `og:dynamic: true` — they're ignored otherwise. `fern check` surfaces warnings for conflicting settings so you can resolve them locally.
You can optionally provide a custom background image (`og:background-image`) for dynamically generated OG images.
```yaml docs.yml
metadata:
og:dynamic: true
- og:background-image: ./images/og-background.png # optional
+ og:background-image: ./images/og-background.png
+ og:dynamic:text-color: "#1a1a1a"
+ og:dynamic:background-color: "#ffffff"
+ og:dynamic:logo-color: dark
+ og:dynamic:show-logo: true
+ og:dynamic:show-section: true
+ og:dynamic:show-description: true
+ og:dynamic:show-url: true
+ og:dynamic:show-gradient: true
```
- When `true`, enables dynamic OG image generation for pages that don't have a custom `og:image` set.
+ When `true`, enables dynamic OG image generation for pages that don't have a custom `og:image` set. Any site-wide `og:image` and `twitter:image` still apply to the homepage; every other page uses the dynamically generated image.
- A custom background image for dynamically generated OG images. Can be a URL or a relative file path. Relative paths are resolved from the YAML file where this property is set (e.g., `docs.yml`). When set, this image is used as the background instead of a solid color.
+ A custom background image for dynamically generated OG images. Can be a URL or a relative file path. Relative paths are resolved from the YAML file where this property is set (e.g., `docs.yml`). When set, this image is used as the background instead of a solid color. No default; the dynamic OG image renders without a background image when unset.
+
+
+
+ Override the text color for dynamically generated OG images. Accepts any valid CSS color value (e.g., `"#1a1a1a"`). By default, Fern reads the text color from your theme (`grayScale[11]`). If no theme color is available, falls back to `#ffffff` for dark mode or `#1a1a1a` for light mode. Must differ from `og:dynamic:background-color` so the text remains visible.
+
+
+
+ Override the background color for dynamically generated OG images. Accepts any valid CSS color value (e.g., `"#ffffff"`). By default, Fern reads the background color from your theme. If no theme color is available, falls back to `#0A0A0A`.
+
+
+
+ Choose which logo variant to render in dynamically generated OG images. Accepts `dark` or `light`, matching the corresponding entry under the top-level [`logo:` setting](/learn/docs/getting-started/global-configuration#logo-configuration) in your `docs.yml`. If your `docs.yml` only defines one logo variant, that variant is used regardless of this setting. Has no effect when `og:dynamic:show-logo: false`.
+
+
+
+ Toggle visibility of the logo in dynamically generated OG images. Defaults to `true` when `og:dynamic` is enabled.
+
+
+
+ Toggle visibility of the section title in dynamically generated OG images. The section title is derived from the page's navigation breadcrumb. Defaults to `true` when `og:dynamic` is enabled.
+
+
+
+ Toggle visibility of the page description in dynamically generated OG images. The description is extracted from the page's frontmatter (`description`, `subtitle`, or `excerpt`). Defaults to `true` when `og:dynamic` is enabled.
+
+
+
+ Toggle visibility of the page URL in dynamically generated OG images. Defaults to `true` when `og:dynamic` is enabled.
+
+
+
+ Toggle visibility of the accent gradient overlay in dynamically generated OG images. The gradient uses your accent color. Defaults to `true` when `og:dynamic` is enabled.
### Twitter / X
Controls how your docs appear in Twitter Card previews when shared on X.
-
- The title shown in Twitter Card previews.
+
+ The title shown in Twitter Card previews. Falls back to `og:title` (and then to the page title) when unset.
-
- The description shown in Twitter Card previews.
+
+ The description shown in Twitter Card previews. Falls back to `og:description` (and then to the page description) when unset.
- Your company's Twitter handle.
+ Your company's Twitter handle. No default; the tag is omitted when unset.
-
- The image shown in Twitter Card previews.
+
+ The image shown in Twitter Card previews. Falls back to `og:image` when unset.
- The Twitter handle for your website.
+ The Twitter handle for your website. No default; the tag is omitted when unset.
-
+
The Twitter Card type. Options are `summary`, `summary_large_image`, `app`, or `player`.
@@ -181,87 +225,87 @@ nofollow: false
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.
-
+
When set, the `` 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.
-
- Overrides the canonical URL for this page. Must be a full URL including the protocol (e.g., `https://buildwithfern.com/learn/docs/content/frontmatter`).
+
+ Overrides the canonical URL for this page. Must be a full URL including the protocol (e.g., `https://buildwithfern.com/learn/docs/content/frontmatter`). Defaults to the page's resolved URL when unset.
- Comma-separated keywords relevant to the page (e.g., `plants, garden, nursery`). Accepts only comma-separated strings, not arrays.
+ Comma-separated keywords relevant to the page (e.g., `plants, garden, nursery`). Accepts only comma-separated strings, not arrays. No default; the tag is omitted when unset.
### 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.
-
- The name of your website as it should appear when your content is shared.
+
+ The name of your website as it should appear when your content is shared. Falls back to the site-wide `metadata.og:site_name` from `docs.yml`.
-
- The title of your page as it should appear when your content is shared.
+
+ The title of your page as it should appear when your content is shared. Falls back to the page's `title` when unset.
-
- The description of your page as it should appear when your content is shared.
+
+ The description of your page as it should appear when your content is shared. Falls back to the page's `description`, `subtitle`, or `excerpt` when unset.
-
- The URL of your page.
+
+ The URL of your page. Falls back to the page's resolved URL when unset.
-
- The URL of the image displayed when your content is shared.
+
+ The URL of the image displayed when your content is shared. Falls back to the site-wide `metadata.og:image` from `docs.yml`.
- The width of the image in pixels.
+ The width of the image in pixels. No default; only used when `og:image` is set.
- The height of the image in pixels.
+ The height of the image in pixels. No default; only used when `og:image` is set.
-
- The locale of the page, typically in the format `language_TERRITORY` (e.g., `en_US`).
+
+ The locale of the page, typically in the format `language_TERRITORY` (e.g., `en_US`). Falls back to the site-wide `metadata.og:locale` from `docs.yml`.
-
- The URL of your logo image displayed when your content is shared.
+
+ The URL of your logo image displayed when your content is shared. Falls back to the site-wide `metadata.og:logo` from `docs.yml`.
### Twitter / X
Controls how this page appears in Twitter Card previews when shared on X.
-
- The title of your page as it should appear in a tweet.
+
+ The title of your page as it should appear in a tweet. Falls back to `og:title` (and then to the page title) when unset.
-
- The description of your page as it should appear in a tweet.
+
+ The description of your page as it should appear in a tweet. Falls back to `og:description` (and then to the page description) when unset.
-
- The Twitter handle of the page creator or site.
+
+ The Twitter handle of the page creator or site. Falls back to the site-wide `metadata.twitter:handle` from `docs.yml`.
-
- The URL of the image displayed in a tweet.
+
+ The URL of the image displayed in a tweet. Falls back to `og:image` when unset.
-
- The Twitter handle for your website.
+
+ The Twitter handle for your website. Falls back to the site-wide `metadata.twitter:site` from `docs.yml`.
-
- The URL of your page.
+
+ The URL of your page. Falls back to `og:url` (and then to the page URL) when unset.
-
+
The type of card used for sharing on Twitter. Options: `summary`, `summary_large_image`, `app`, `player`.
diff --git a/fern/snippets/seo-metadata-site.mdx b/fern/snippets/seo-metadata-site.mdx
index 4ed3f89dab..519ad09112 100644
--- a/fern/snippets/seo-metadata-site.mdx
+++ b/fern/snippets/seo-metadata-site.mdx
@@ -17,6 +17,14 @@ metadata:
# Dynamic OG images (beta)
og:dynamic: true
og:background-image: "https://developer.squareup.com/images/og-background.png"
+ og:dynamic:text-color: "#1a1a1a"
+ og:dynamic:background-color: "#ffffff"
+ og:dynamic:logo-color: dark
+ og:dynamic:show-logo: true
+ og:dynamic:show-section: true
+ og:dynamic:show-description: true
+ og:dynamic:show-url: true
+ og:dynamic:show-gradient: true
# Twitter/X
twitter:title: "Square Developer Platform Documentation"
@@ -31,71 +39,103 @@ metadata:
The name of your website for Open Graph tags.
-
- The title shown in social media previews.
+
+ The title shown in social media previews. Falls back to the page's `title` when unset.
-
- The description shown in social media previews.
+
+ The description shown in social media previews. Falls back to the page's `description`, `subtitle`, or `excerpt` when unset.
-
- The canonical URL of your documentation.
+
+ The canonical URL of your documentation. Falls back to the page's resolved URL when unset.
- The image shown in social media previews. Recommended size is 1200x630 pixels.
+ The image shown in social media previews. Recommended size is 1200x630 pixels. No default; the tag is omitted when unset.
- The width of your Open Graph image in pixels.
+ The width of your Open Graph image in pixels. No default; only used when `og:image` is set.
- The height of your Open Graph image in pixels.
+ The height of your Open Graph image in pixels. No default; only used when `og:image` is set.
- The locale of your content (e.g., "en_US").
+ The locale of your content (e.g., "en_US"). No default; the tag is omitted when unset.
- URL to your company logo.
+ URL to your company logo. No default; the tag is omitted when unset.
-
- The title shown in Twitter Card previews.
+
+ The title shown in Twitter Card previews. Falls back to `og:title` (and then to the page title) when unset.
-
- The description shown in Twitter Card previews.
+
+ The description shown in Twitter Card previews. Falls back to `og:description` (and then to the page description) when unset.
- Your company's Twitter handle.
+ Your company's Twitter handle. No default; the tag is omitted when unset.
-
- The image shown in Twitter Card previews.
+
+ The image shown in Twitter Card previews. Falls back to `og:image` when unset.
- The Twitter handle for your website.
+ The Twitter handle for your website. No default; the tag is omitted when unset.
-
+
The Twitter Card type. Options are `summary`, `summary_large_image`, `app`, or `player`.
-
+
When `true`, enables dynamic OG image generation for pages that don't have a custom `og:image` set.
- A custom background image for dynamically generated OG images. Can be a URL or a relative file path. Relative paths are resolved from the YAML file where this property is set (e.g., `docs.yml`).
+ A custom background image for dynamically generated OG images. Can be a URL or a relative file path. Relative paths are resolved from the YAML file where this property is set (e.g., `docs.yml`). No default; the dynamic OG image renders without a background image when unset.
-
+
+ Override the text color for dynamically generated OG images. Accepts any valid CSS color value. Auto-detected from your theme; falls back to `#ffffff` (dark) or `#1a1a1a` (light).
+
+
+
+ Override the background color for dynamically generated OG images. Accepts any valid CSS color value. Auto-detected from your theme; falls back to `#0A0A0A`.
+
+
+
+ Choose which logo variant (`dark` or `light`) to render in dynamically generated OG images.
+
+
+
+ Toggle visibility of the logo in dynamically generated OG images.
+
+
+
+ Toggle visibility of the section title in dynamically generated OG images.
+
+
+
+ Toggle visibility of the page description in dynamically generated OG images.
+
+
+
+ Toggle visibility of the page URL in dynamically generated OG images.
+
+
+
+ Toggle visibility of the accent gradient overlay in dynamically generated OG images.
+
+
+
The host of your documentation website. This will be used to set the canonical URL for metadata tags and documents like the sitemap.
Defaults to the URL defined in the `instances` configuration.