Platform specific output formatting skill
Adapt blog output to each platform's requirements.
by AgriciDaniel·MIT license·★ 2,219 Stars on the repo·GitHub ↗
Files of Platform specific output formatting
AgriciDaniel/
Show the full text1136 lines
Platform-Specific Output Formatting
Adapt blog output to each platform's requirements. Detect the platform
from project structure (see SKILL.md Platform Detection table) and apply
the corresponding format rules below.
Contents
- Next.js / MDX
- Astro
- Hugo
- Jekyll
- WordPress
- Ghost
- 11ty (Eleventy)
- Gatsby
- HTML / Static
- Platform Selection Quick Reference
Next.js / MDX
Frontmatter Format
---
title: "How Does AI Search Impact Organic Traffic in 2026?"
description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize for Google rankings and AI citations in 2026."
date: "2026-02-18"
lastUpdated: "2026-02-18"
author: "Author Name"
tags: ["ai-search", "seo", "traffic"]
coverImage: "https://cdn.pixabay.com/photo/2024/01/15/12/00/ai-search.jpg"
coverImageAlt: "Marketing dashboard showing AI search traffic metrics and citation rates"
ogImage: "https://cdn.pixabay.com/photo/2024/01/15/12/00/ai-search.jpg"
---
Supported frontmatter fields: title, description, date, lastUpdated, author,
tags, coverImage, coverImageAlt, ogImage. Adapt field names to match the
project's existing convention (some use image instead of coverImage).
Image Embedding

For projects using next/image component:
import Image from 'next/image'
<Image
src="https://cdn.pixabay.com/photo/.../image.jpg"
alt="Marketing team analyzing search traffic on a dashboard"
width={1200}
height={630}
priority={false}
/>
next.config.ts Image Domains (Required)
// next.config.ts
const nextConfig = {
images: {
remotePatterns: [
{ protocol: 'https', hostname: 'cdn.pixabay.com' },
{ protocol: 'https', hostname: 'images.unsplash.com' },
{ protocol: 'https', hostname: 'images.pexels.com' },
],
},
}
Without these entries, next/image will reject external image URLs at build time.
Chart / SVG Embedding (JSX-Compatible)
All SVG attributes must use camelCase in MDX files. HTML-style attributes cause compilation errors.
<figure className="chart-container" style={{margin: '2.5rem 0', textAlign: 'center', padding: '1.5rem', borderRadius: '12px'}}>
<svg
viewBox="0 0 560 380"
style={{maxWidth: '100%', height: 'auto', fontFamily: "'Inter', system-ui, sans-serif"}}
role="img"
aria-label="Chart showing AIO organic CTR rebound from 1.3% to about 2.4%"
>
<title>AIO Organic CTR Rebound</title>
<desc>Bar chart comparing the December 2025 AIO CTR floor to the February 2026 rebound</desc>
<text x="280" y="30" textAnchor="middle" fontSize="16" fontWeight="700" fill="currentColor">
AIO Organic CTR Rebound
</text>
<rect x="100" y="152" width="160" height="108" rx="6" fill="#f97316" />
<text x="180" y="212" textAnchor="middle" fontSize="14" fontWeight="800" fill="white">
1.3%
</text>
<rect x="300" y="60" width="160" height="200" rx="6" fill="#38bdf8" />
<text x="380" y="165" textAnchor="middle" fontSize="14" fontWeight="800" fill="white">
~2.4%
</text>
<text x="280" y="372" textAnchor="middle" fontSize="10" fill="currentColor" opacity="0.35">
Source: Seer Interactive (Apr 2026)
</text>
</svg>
</figure>
JSX attribute conversion reference:
| HTML Attribute | JSX Attribute |
|---|---|
stroke-width |
strokeWidth |
stroke-dasharray |
strokeDasharray |
stroke-linecap |
strokeLinecap |
text-anchor |
textAnchor |
font-size |
fontSize |
font-weight |
fontWeight |
font-family |
fontFamily |
class |
className |
style="..." |
style={{...}} |
fill-opacity |
fillOpacity |
stop-color |
stopColor |
clip-path |
clipPath |
MDX Component Imports for Custom Charts
import { BarChart } from '@/components/charts/BarChart'
import { FAQSchema } from '@/components/FAQSchema'
<BarChart data={chartData} title="AIO Organic CTR Rebound" />
<FAQSchema faqs={[{ question: "...", answer: "..." }]} />
Check the project's components/ directory for available chart components
before inlining SVG. Use project components when they exist.
generateStaticParams for SSG (Critical for AI Crawlers)
AI crawlers (GPTBot, ClaudeBot, PerplexityBot) cannot execute JavaScript. Pages must be statically generated or server-rendered. Never use client-only rendering for blog content.
// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
const posts = getAllPosts()
return posts.map((post) => ({
slug: post.slug,
}))
}
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { slug } = await params
const post = getPostBySlug(slug)
return {
title: post.title,
description: post.description,
openGraph: {
title: post.title,
description: post.description,
images: [post.ogImage],
type: 'article',
publishedTime: post.date,
modifiedTime: post.lastUpdated,
},
}
}
Key Configuration Notes
- MDX files require
@next/mdxornext-mdx-remotepackage - Verify
mdx-components.tsxexists at project root for custom element mapping - Use
export const metadataorgenerateMetadatafor per-page SEO - JSON-LD schema should be rendered in the page component, not injected client-side
- Sitemap: use
app/sitemap.tswithMetadataRoute.Sitemaptype
Astro
Frontmatter Format
---
title: "How Does AI Search Impact Organic Traffic in 2026?"
description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize."
pubDate: 2026-02-18
updatedDate: 2026-02-18
author: "Author Name"
tags: ["ai-search", "seo", "traffic"]
heroImage: "/images/ai-search-cover.jpg"
heroImageAlt: "Marketing dashboard showing AI search metrics"
---
Astro uses pubDate and updatedDate (Date objects) instead of date
and lastUpdated (strings). Adapt to match the project's content schema.
Content Collections (src/content/blog/)
Astro 4+ uses type-safe content collections with Zod schema validation:
// src/content/config.ts
import { defineCollection, z } from 'astro:content'
const blog = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.coerce.date(),
updatedDate: z.coerce.date().optional(),
author: z.string().optional(),
tags: z.array(z.string()).optional(),
heroImage: z.string().optional(),
heroImageAlt: z.string().optional(),
}),
})
export const collections = { blog }
Place blog posts in src/content/blog/ as .md or .mdx files.
Image Embedding

Using astro:assets for optimization:
---
import { Image } from 'astro:assets'
import searchDashboard from '../assets/search-dashboard.jpg'
---
<Image src={searchDashboard} alt="Marketing team analyzing search data" />
For remote images, configure astro.config.mjs:
export default defineConfig({
image: {
domains: ['cdn.pixabay.com', 'images.unsplash.com', 'images.pexels.com'],
},
})
Chart / SVG Embedding
Standard SVG works directly in .md files. For .astro component wrappers:
---
// src/components/Chart.astro
const { title, ariaLabel } = Astro.props
---
<figure class="chart-container">
<slot />
<figcaption>{title}</figcaption>
</figure>
Use standard HTML attributes (not camelCase) in .astro and .md files:
<svg viewBox="0 0 560 380" role="img" aria-label="AIO CTR rebound chart">
<text x="280" y="30" text-anchor="middle" font-size="16" fill="currentColor">
Chart Title
</text>
</svg>
Key Configuration Notes
- Static output by default (SSG): ideal for AI crawlers without JS execution
- Markdown files support raw HTML/SVG natively (no unsafe config needed)
- For MDX support: add
@astrojs/mdxintegration - Sitemap: add
@astrojs/sitemapintegration withsiteconfig - RSS: add
@astrojs/rssfor feed generation - View Transitions: built-in via
<ViewTransitions />component
Hugo
Frontmatter Format (YAML)
---
title: "How Does AI Search Impact Organic Traffic in 2026?"
description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize."
date: 2026-02-18
lastmod: 2026-02-18
author: "Author Name"
tags: ["ai-search", "seo", "traffic"]
categories: ["SEO Strategy"]
series: ["AI Search Optimization"]
images:
- "/images/ai-search-cover.jpg"
draft: false
---
Frontmatter Format (TOML)
+++
title = "How Does AI Search Impact Organic Traffic in 2026?"
description = "AI Overview CTR gap narrowed to about 38%."
date = 2026-02-18
lastmod = 2026-02-18
author = "Author Name"
tags = ["ai-search", "seo", "traffic"]
categories = ["SEO Strategy"]
series = ["AI Search Optimization"]
images = ["/images/ai-search-cover.jpg"]
draft = false
+++
Hugo uses lastmod instead of lastUpdated. Supports both YAML (---)
and TOML (+++) frontmatter delimiters.
Taxonomy Structure
Hugo supports three built-in taxonomies:
- categories: Broad topic groupings (content pillars)
- tags: Specific topic labels (keywords)
- series: Multi-part content sequences
Configure in hugo.toml:
[taxonomies]
category = "categories"
tag = "tags"
series = "series"
Image Embedding

Hugo processes images from static/images/ or page bundles (content/blog/post-name/images/).
Chart / SVG Embedding via Shortcodes
Create a custom shortcode for trusted, sanitized inline SVG only. Do not pass
user-derived or generated text through safeHTML unless it has been sanitized
with a strict SVG allowlist.
<!-- layouts/shortcodes/chart.html -->
<figure class="chart-container" style="margin: 2.5rem 0; text-align: center;">
{{ .Inner | safeHTML }}
{{ with .Get "caption" }}<figcaption>{{ . }}</figcaption>{{ end }}
</figure>
Usage in markdown:
{{< chart caption="Source: Seer Interactive (Apr 2026)" >}}
<svg viewBox="0 0 560 380" role="img" aria-label="AIO CTR rebound chart">
<!-- SVG content -->
</svg>
{{< /chart >}}
Goldmark Renderer Config (Required for SVG)
Hugo's default Goldmark renderer escapes raw HTML. Enable unsafe rendering only for trusted authored SVG/HTML after sanitization:
# hugo.toml
[markup.goldmark.renderer]
unsafe = true
Without this setting, all <svg>, <figure>, and other HTML tags in markdown
files will be stripped from the output. If authors or external systems can
provide markup, prefer a shortcode that sanitizes SVG and rejects scripts,
event-handler attributes, foreignObject, external resources, and unsafe URLs.
Custom Archetypes
<!-- archetypes/blog.md -->
---
title: "{{ replace .Name "-" " " | title }}"
description: ""
date: {{ .Date }}
lastmod: {{ .Date }}
author: ""
tags: []
categories: []
images: []
draft: true
---
## Introduction
[Hook with statistic]
Create new posts with: hugo new blog/my-post-title.md
Key Configuration Notes
- Posts go in
content/blog/orcontent/posts/(check project convention) - Page bundles (
content/blog/post-name/index.md) co-locate images with content - Use
{{ .Params.lastmod }}in templates for freshness display - JSON-LD schema: add in
layouts/partials/schema.htmlpartial - Sitemap auto-generated at
/sitemap.xml - RSS auto-generated at
/index.xml
Jekyll
Frontmatter Format (YAML Required)
---
layout: post
title: "How Does AI Search Impact Organic Traffic in 2026?"
description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize."
date: 2026-02-18
last_modified_at: 2026-02-18
author: "Author Name"
categories: [seo-strategy]
tags: [ai-search, seo, traffic]
image: /assets/images/ai-search-cover.jpg
---
Naming Convention (Required)
Posts must follow: _posts/YYYY-MM-DD-title-slug.md
Example: _posts/2026-02-18-ai-search-organic-traffic.md
Jekyll will not process files that do not follow this naming pattern.
Image Embedding

Images live in assets/images/ or images/ depending on project convention.
Chart / SVG Embedding
Jekyll uses the kramdown renderer, which passes through raw HTML:
<figure>
<svg viewBox="0 0 560 380" role="img" aria-label="AIO CTR rebound chart">
<!-- SVG content with standard HTML attributes -->
</svg>
<figcaption>Source: Seer Interactive (Apr 2026)</figcaption>
</figure>
No special configuration needed: kramdown does not strip HTML by default.
Liquid Templates
Access page variables in layouts:
<h1>{{ page.title }}</h1>
<time datetime="{{ page.date | date_to_xmlschema }}">
{{ page.date | date: "%B %d, %Y" }}
</time>
{% if page.last_modified_at %}
<meta property="article:modified_time"
content="{{ page.last_modified_at | date_to_xmlschema }}">
{% endif %}
Loop through posts:
{% for post in site.posts limit:10 %}
<article>
<h2><a href="{{ post.url }}">{{ post.title }}</a></h2>
<p>{{ post.description }}</p>
</article>
{% endfor %}
Layout Hierarchy
_layouts/
default.html <-- Base layout (HTML shell, head, nav, footer)
post.html <-- Blog post layout (extends default)
page.html <-- Static page layout (extends default)
Math Support via MathJax
# _config.yml
markdown: kramdown
kramdown:
math_engine: mathjax
Usage in posts:
The formula is $$ E = mc^2 $$
Key Configuration Notes
_config.ymlis the central configuration file- Collections: define custom collections beyond posts in
_config.yml - Plugins:
jekyll-seo-tagfor automatic OG/Twitter meta tags jekyll-sitemapfor sitemap generationjekyll-last-modified-atfor automaticlast_modified_atfrom git- Build with
bundle exec jekyll build(produces_site/directory) - JSON-LD: use
jekyll-seo-tagor manually include in_includes/head.html
WordPress
Gutenberg Blocks (Modern)
Gutenberg uses block-based editing. Key blocks for blog content:
| Block | Purpose | Notes |
|---|---|---|
| Paragraph | Body text | Each paragraph auto-wraps in <p> |
| Heading | H2-H6 | Set level in block toolbar |
| Image | Photos | Set alt text, caption, link in sidebar |
| Custom HTML | SVG charts | Paste raw SVG in HTML block |
| List | Bullets/numbers | For FAQ answers, step lists |
| Quote | Blockquotes | For expert quotes with attribution |
| Table | Comparison tables | For feature/pricing comparisons |
| Group | Wrappers | Group blocks for styling |
Classic Editor (HTML)
<h2>How Does AI Search Impact Organic Traffic?</h2>
<p>AIO organic CTR rebounded from 1.3% in December 2025 to about 2.4%
in February 2026 (<a href="https://seerinteractive.com">Seer Interactive</a>,
April 2026). This means brands should optimize for citation, since cited pages
earn 120% more clicks per impression.</p>
<figure>
<img src="https://cdn.pixabay.com/photo/.../image.jpg"
alt="Marketing dashboard showing AI search traffic metrics"
width="1200" height="630" loading="lazy">
<figcaption>Photo via Pixabay</figcaption>
</figure>
Image Embedding
Upload via Media Library, then insert. Set these fields:
- Alt text: Descriptive sentence with topic keywords
- Title: Short descriptive title
- Caption: Optional, shows below image
- Featured Image: Set in post sidebar (used as OG image and blog listing)
Chart / SVG Embedding
Use the Custom HTML block:
<figure class="wp-block-html chart-container">
<svg viewBox="0 0 560 380" role="img" aria-label="Chart description">
<!-- Standard SVG with HTML attributes -->
</svg>
</figure>
Yoast SEO / RankMath Integration
| Field | Where | Purpose |
|---|---|---|
| Focus keyword | SEO panel below editor | Primary target keyword |
| SEO title | SEO panel | Title tag (if different from H1) |
| Meta description | SEO panel | 150-160 chars, fact-dense |
| Canonical URL | SEO panel → Advanced | Prevents duplicate content |
| OG image | Social tab in SEO panel | Social sharing preview |
| OG title | Social tab | Title for social shares |
| OG description | Social tab | Description for social shares |
Custom Fields for Structured Data
Use ACF (Advanced Custom Fields) or native custom fields:
last_updated: for dateModified in schemaauthor_bio: for E-E-A-T author sectionfaq_items: for FAQPage entity markup when visible Q&A exists
Featured Image
Set via the "Featured Image" panel in the post editor sidebar. This image serves as both the blog listing thumbnail and the OG image for social sharing. Recommended size: 1200x630px.
Excerpt Field
The Excerpt field (in post sidebar) generates the meta description if Yoast/ RankMath meta description is empty. Keep it to 150-160 characters, fact-dense, with at least one statistic.
Key Configuration Notes
- Permalink structure: Settings > Permalinks > Post name (
/%postname%/) - REST API:
wp-json/wp/v2/postsfor programmatic publishing - Schema: Yoast/RankMath auto-generates BlogPosting schema
- Caching: use WP Super Cache or W3 Total Cache for TTFB < 200ms
- Security: keep WordPress, themes, and plugins updated
- robots.txt: accessible at
/robots.txt, configure via Yoast
Ghost
Content Formats
Modern Ghost stores editor content in Lexical JSON and accepts HTML input for HTML cards and Admin API publishing.
Ghost Admin API (Programmatic Publishing)
const GhostAdminAPI = require('@tryghost/admin-api')
const api = new GhostAdminAPI({
url: 'https://your-blog.ghost.io',
key: 'ADMIN_API_KEY',
version: 'v5.0'
})
api.posts.add({
title: 'How Does AI Search Impact Organic Traffic in 2026?',
html: '<p>AIO organic CTR rebounded from 1.3% to about 2.4%...</p>',
status: 'draft',
tags: [{ name: 'AI Search' }, { name: 'SEO' }],
meta_title: 'AI Search Impact on Organic Traffic (2026 Data)',
meta_description: 'AI Overview CTR gap narrowed to about 38%...',
og_image: 'https://cdn.pixabay.com/photo/.../cover.jpg',
og_title: 'AI Search Impact on Organic Traffic',
og_description: 'New data reveals how AI search reshapes organic visibility.',
canonical_url: 'https://your-blog.com/ai-search-organic-traffic',
feature_image: 'https://cdn.pixabay.com/photo/.../cover.jpg',
feature_image_alt: 'Marketing dashboard showing AI search metrics',
})
Image Embedding
In the Ghost editor, use the Image card. For HTML content:
<figure class="kg-card kg-image-card">
<img class="kg-image"
src="https://cdn.pixabay.com/photo/.../image.jpg"
alt="Marketing team analyzing AI search data"
loading="lazy">
<figcaption>Photo via Pixabay</figcaption>
</figure>
Chart / SVG Embedding
Use the HTML card in the Ghost editor to paste raw SVG:
<figure class="kg-card kg-html-card">
<svg viewBox="0 0 560 380" role="img" aria-label="Chart description">
<!-- Standard SVG -->
</svg>
</figure>
Built-in SEO Fields
| Field | Location | Purpose |
|---|---|---|
| Meta title | Post settings > Meta data | Title tag override |
| Meta description | Post settings > Meta data | 150-160 chars |
| Canonical URL | Post settings > Meta data | Duplicate prevention |
| OG image | Post settings > Twitter/Facebook | Social preview image |
| OG title | Post settings > Twitter/Facebook | Social preview title |
| Feature image | Post header | Hero + OG fallback |
| Feature image alt | Post header | Accessibility |
| Excerpt | Post settings > Excerpt | Newsletter + listing text |
Custom Theme Considerations
Ghost themes use Handlebars templates:
{{! post.hbs }}
<article class="post">
<h1>{{title}}</h1>
<time datetime="{{date format='YYYY-MM-DD'}}">{{date format="MMMM DD, YYYY"}}</time>
{{#if updated_at}}
<time datetime="{{updated_at format='YYYY-MM-DD'}}">
Updated: {{updated_at format="MMMM DD, YYYY"}}
</time>
{{/if}}
<div class="post-content">{{content}}</div>
</article>
Dynamic Routing
Configure content organization in routes.yaml:
routes:
/about/: about
collections:
/blog/:
permalink: /blog/{slug}/
filter: tag:-hash-podcast
template: blog
taxonomies:
tag: /tag/{slug}/
author: /author/{slug}/
Key Configuration Notes
- Ghost themes often output structured data automatically, but custom and headless themes must validate rendered JSON-LD in the final HTML
- Default output is server-rendered HTML: AI crawlers can access content
- Newsletters: Ghost has built-in email sending for subscriber lists
- Membership: tiers and paid content built-in
- Themes: install via Ghost Admin > Settings > Design
- Content API: for headless CMS setups (read-only, public content)
11ty (Eleventy)
Frontmatter Format
---
title: "How Does AI Search Impact Organic Traffic in 2026?"
description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize."
date: 2026-02-18
lastUpdated: 2026-02-18
author: "Author Name"
tags:
- ai-search
- seo
- posts
layout: post.njk
coverImage: "/images/ai-search-cover.jpg"
coverImageAlt: "Marketing dashboard showing AI search metrics"
---
Template Languages
11ty supports Nunjucks (.njk), Liquid (.liquid), Handlebars (.hbs),
JavaScript (.11ty.js), and more. Nunjucks is the most common choice.
Data Cascade
11ty merges data from multiple sources (highest to lowest priority):
- File data: frontmatter in the content file
- Directory data:
blog.jsonin the content directory - Global data: files in
_data/directory
// blog/blog.json (applies to all files in blog/)
{
"layout": "post.njk",
"tags": ["posts"],
"permalink": "/blog/{{ page.fileSlug }}/"
}
Image Embedding

For optimized images, use eleventy-img plugin:
{% image "src/images/search-dashboard.jpg", "Marketing team analyzing search data" %}
Chart / SVG Embedding
Raw HTML/SVG works directly in markdown files. 11ty passes through HTML without stripping.
<figure>
<svg viewBox="0 0 560 380" role="img" aria-label="AIO CTR rebound chart">
<!-- SVG content -->
</svg>
<figcaption>Source: Seer Interactive (Apr 2026)</figcaption>
</figure>
Computed Data for Dates and URLs
// blog/blog.11tydata.js
module.exports = {
eleventyComputed: {
permalink: (data) => `/blog/${data.page.fileSlug}/`,
lastUpdatedDisplay: (data) => {
const date = data.lastUpdated || data.page.date
return new Date(date).toLocaleDateString('en-US', {
year: 'numeric', month: 'long', day: 'numeric'
})
}
}
}
Passthrough File Copy
// .eleventy.js
module.exports = function(eleventyConfig) {
eleventyConfig.addPassthroughCopy("src/images")
eleventyConfig.addPassthroughCopy("src/svg")
eleventyConfig.addPassthroughCopy({ "src/favicon.ico": "/" })
}
Key Configuration Notes
- Static output by default: ideal for AI crawlers
- No build-step JS unless explicitly added (fast pages)
- Collections: use
tagsin frontmatter to group content - Filters: add custom Nunjucks filters in
.eleventy.jsfor date formatting - Pagination: built-in for tag pages and archive pages
- JSON-LD: inject via layout template using frontmatter data
- Sitemap: use
eleventy-plugin-sitemapor generate manually
Gatsby
Frontmatter Format
---
title: "How Does AI Search Impact Organic Traffic in 2026?"
description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize."
date: "2026-02-18"
lastUpdated: "2026-02-18"
author: "Author Name"
tags: ["ai-search", "seo", "traffic"]
slug: "ai-search-organic-traffic"
featuredImage: "../images/ai-search-cover.jpg"
featuredImageAlt: "Marketing dashboard showing AI search metrics"
---
MDX Support
// gatsby-config.js
module.exports = {
plugins: [
{
resolve: 'gatsby-plugin-mdx',
options: {
extensions: ['.mdx', '.md'],
gatsbyRemarkPlugins: [
'gatsby-remark-images',
'gatsby-remark-prismjs',
],
},
},
],
}
Image Embedding

Using gatsby-plugin-image:
import { GatsbyImage, getImage } from 'gatsby-plugin-image'
const BlogPost = ({ data }) => {
const image = getImage(data.mdx.frontmatter.featuredImage)
return (
<GatsbyImage
image={image}
alt={data.mdx.frontmatter.featuredImageAlt}
/>
)
}
Chart / SVG Embedding
In MDX files, use JSX-compatible SVG (same camelCase rules as Next.js):
<figure style={{margin: '2.5rem 0', textAlign: 'center'}}>
<svg viewBox="0 0 560 380" role="img" aria-label="CTR chart">
<text x="280" y="30" textAnchor="middle" fontSize="16" fill="currentColor">
Chart Title
</text>
</svg>
</figure>
GraphQL Data Layer
query BlogPostBySlug($slug: String!) {
mdx(frontmatter: { slug: { eq: $slug } }) {
body
frontmatter {
title
description
date(formatString: "MMMM DD, YYYY")
lastUpdated(formatString: "MMMM DD, YYYY")
tags
featuredImage {
childImageSharp {
gatsbyImageData(width: 1200, placeholder: BLURRED)
}
}
}
}
}
createPages API for Dynamic Routes
// gatsby-node.js
const path = require('path')
const blogPostTemplate = path.resolve('./src/templates/blog-post.tsx')
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions
const result = await graphql(`
query {
allMdx {
nodes {
id
frontmatter { slug }
internal { contentFilePath }
}
}
}
`)
result.data.allMdx.nodes.forEach((node) => {
createPage({
path: `/blog/${node.frontmatter.slug}`,
component: `${blogPostTemplate}?__contentFilePath=${node.internal.contentFilePath}`,
context: { id: node.id },
})
})
}
Key Configuration Notes
- Static output at build time: AI crawlers get full HTML
- Use
gatsby-plugin-sitemapfor sitemap generation - Use
gatsby-plugin-robots-txtfor robots.txt configuration gatsby-plugin-react-helmetor Gatsby Head API for meta tags- JSON-LD: use
gatsby-plugin-schema-snapshotor inline in Head component - Build can be slow for large sites: consider incremental builds
HTML / Static
Semantic HTML5 Structure
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>How Does AI Search Impact Organic Traffic in 2026?</title>
<meta name="description" content="AI Overview CTR gap narrowed to about 38%. Here's how to optimize for Google rankings and AI citations in 2026.">
<!-- Open Graph -->
<meta property="og:type" content="article">
<meta property="og:title" content="How Does AI Search Impact Organic Traffic in 2026?">
<meta property="og:description" content="AI Overview CTR gap narrowed to about 38%.">
<meta property="og:image" content="https://cdn.pixabay.com/photo/.../cover.jpg">
<meta property="og:url" content="https://yourblog.com/ai-search-organic-traffic">
<meta property="article:published_time" content="2026-02-18T00:00:00Z">
<meta property="article:modified_time" content="2026-02-18T00:00:00Z">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="How Does AI Search Impact Organic Traffic in 2026?">
<meta name="twitter:description" content="AI Overview CTR gap narrowed to about 38%.">
<meta name="twitter:image" content="https://cdn.pixabay.com/photo/.../cover.jpg">
<!-- JSON-LD Structured Data -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": "How Does AI Search Impact Organic Traffic in 2026?",
"description": "AI Overview CTR gap narrowed to about 38%.",
"image": "https://cdn.pixabay.com/photo/.../cover.jpg",
"datePublished": "2026-02-18",
"dateModified": "2026-02-18",
"author": {
"@type": "Person",
"name": "Author Name",
"url": "https://yourblog.com/about"
},
"publisher": {
"@type": "Organization",
"name": "Blog Name",
"logo": {
"@type": "ImageObject",
"url": "https://yourblog.com/logo.png"
}
},
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://yourblog.com/ai-search-organic-traffic"
}
}
</script>
</head>
<body>
<nav aria-label="Main navigation">
<!-- Navigation -->
</nav>
<article>
<header>
<h1>How Does AI Search Impact Organic Traffic in 2026?</h1>
<time datetime="2026-02-18">February 18, 2026</time>
</header>
<section>
<h2>What Is the Impact of AI Overviews on Click-Through Rates?</h2>
<p>AIO organic CTR rebounded from 1.3% in December 2025 to about 2.4%
in February 2026 (<a href="https://seerinteractive.com">Seer Interactive</a>,
April 2026). Cited pages now earn 120% more clicks per impression than
uncited pages.</p>
<figure>
<img src="https://cdn.pixabay.com/photo/.../image.jpg"
alt="Marketing dashboard showing AI search CTR metrics"
width="1200" height="630" loading="lazy">
<figcaption>Photo via Pixabay</figcaption>
</figure>
</section>
<aside aria-label="Frequently Asked Questions">
<h2>Frequently Asked Questions</h2>
<!-- FAQ content -->
</aside>
</article>
<footer>
<!-- Footer -->
</footer>
</body>
</html>
Image Embedding
<figure>
<img src="https://cdn.pixabay.com/photo/.../image.jpg"
alt="Descriptive sentence including topic keywords naturally"
width="1200" height="630"
loading="lazy"
decoding="async">
<figcaption>Photo via Pixabay</figcaption>
</figure>
Chart / SVG Embedding
<figure>
<svg viewBox="0 0 560 380"
style="max-width: 100%; height: auto; font-family: 'Inter', system-ui, sans-serif"
role="img"
aria-label="Chart showing AIO organic CTR rebound from 1.3% to about 2.4%">
<title>AIO Organic CTR Rebound</title>
<desc>Bar chart comparing the December 2025 AIO CTR floor to the February 2026 rebound</desc>
<!-- SVG content with standard HTML attributes -->
</svg>
<figcaption>Source: Seer Interactive (Apr 2026)</figcaption>
</figure>
Inline JSON-LD Schema
Place in <head> for BlogPosting:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": "Title",
"datePublished": "2026-02-18",
"dateModified": "2026-02-18",
"author": { "@type": "Person", "name": "Author" }
}
</script>
Place in <head> for FAQPage only when visible Q&A exists. It is entity
support for AI citation, not a Google rich result:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "What is the question?",
"acceptedAnswer": {
"@type": "Answer",
"text": "The visible answer text with a specific statistic and source."
}
}
]
}
</script>
Key Configuration Notes
- No framework dependency: works with any hosting
- AI crawlers can read static HTML without JS execution
- Manually manage OG/Twitter meta tags in
<head> - Use
loading="lazy"anddecoding="async"on images for performance - Schema must be in HTML source, not injected via JavaScript
- Generate sitemap.xml manually or with a build script
- Use
<link rel="canonical" href="...">to prevent duplicate content - Place CSS in
<head>(inline critical CSS for fast TTFB)
Platform Selection Quick Reference
| Priority | Criterion | Recommendation |
|---|---|---|
| AI crawlers | JS execution required? | Use SSG/SSR (Next.js, Astro, Hugo, 11ty, Gatsby) |
| Speed | TTFB < 200ms | Hugo (fastest builds), 11ty, Astro, static HTML |
| MDX/React | Component-driven content | Next.js, Gatsby |
| Simplicity | Minimal tooling | Hugo, Jekyll, 11ty, static HTML |
| Non-technical users | Visual editor | WordPress, Ghost |
| Headless CMS | API-first | Ghost (Content API), WordPress (REST API) |
Universal Requirements (All Platforms)
- Static or server-rendered HTML: AI crawlers cannot execute JavaScript
- TTFB under 200ms: AI crawlers timeout at 3-5 seconds
- Schema in HTML source: not injected via client-side JS
- robots.txt allowing AI crawlers: GPTBot, ClaudeBot, PerplexityBot
- Sitemap at /sitemap.xml: helps all crawlers discover content
- OG meta tags: required for social sharing previews
- dateModified in schema: critical for freshness signals
| 1 | # Platform-Specific Output Formatting |
| 2 | |
| 3 | Adapt blog output to each platform's requirements. Detect the platform |
| 4 | from project structure (see `SKILL.md` Platform Detection table) and apply |
| 5 | the corresponding format rules below. |
| 6 | |
| 7 | ## Contents |
| 8 | |
| 9 | [Next.js / MDX] |
| 10 | [Astro] |
| 11 | [Hugo] |
| 12 | [Jekyll] |
| 13 | [WordPress] |
| 14 | [Ghost] |
| 15 | [11ty (Eleventy)] |
| 16 | [Gatsby] |
| 17 | [HTML / Static] |
| 18 | [Platform Selection Quick Reference] |
| 19 | |
| 20 | |
| 21 | |
| 22 | ## Next.js / MDX |
| 23 | |
| 24 | ### Frontmatter Format |
| 25 | |
| 26 | |
| 27 | title: "How Does AI Search Impact Organic Traffic in 2026?" |
| 28 | description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize for Google rankings and AI citations in 2026." |
| 29 | date: "2026-02-18" |
| 30 | lastUpdated: "2026-02-18" |
| 31 | author: "Author Name" |
| 32 | tags: ["ai-search", "seo", "traffic"] |
| 33 | coverImage: "https://cdn.pixabay.com/photo/2024/01/15/12/00/ai-search.jpg" |
| 34 | coverImageAlt: "Marketing dashboard showing AI search traffic metrics and citation rates" |
| 35 | ogImage: "https://cdn.pixabay.com/photo/2024/01/15/12/00/ai-search.jpg" |
| 36 | |
| 37 | |
| 38 | |
| 39 | **Supported frontmatter fields**: title, description, date, lastUpdated, author, |
| 40 | tags, coverImage, coverImageAlt, ogImage. Adapt field names to match the |
| 41 | project's existing convention (some use `image` instead of `coverImage`). |
| 42 | |
| 43 | ### Image Embedding |
| 44 | |
| 45 |  |
| 46 | |
| 47 | |
| 48 | For projects using `next/image` component: |
| 49 | |
| 50 | import Image from 'next/image' |
| 51 | |
| 52 | <Image |
| 53 | src="https://cdn.pixabay.com/photo/.../image.jpg" |
| 54 | alt="Marketing team analyzing search traffic on a dashboard" |
| 55 | width={1200} |
| 56 | height={630} |
| 57 | priority={false} |
| 58 | /> |
| 59 | |
| 60 | |
| 61 | ### next.config.ts Image Domains (Required) |
| 62 | |
| 63 | // next.config.ts |
| 64 | const nextConfig = { |
| 65 | images: { |
| 66 | remotePatterns: [ |
| 67 | { protocol: 'https', hostname: 'cdn.pixabay.com' }, |
| 68 | { protocol: 'https', hostname: 'images.unsplash.com' }, |
| 69 | { protocol: 'https', hostname: 'images.pexels.com' }, |
| 70 | ], |
| 71 | }, |
| 72 | } |
| 73 | |
| 74 | |
| 75 | Without these entries, `next/image` will reject external image URLs at build time. |
| 76 | |
| 77 | ### Chart / SVG Embedding (JSX-Compatible) |
| 78 | |
| 79 | All SVG attributes must use camelCase in MDX files. HTML-style attributes |
| 80 | cause compilation errors. |
| 81 | |
| 82 | |
| 83 | <figure className="chart-container" style={{margin: '2.5rem 0', textAlign: 'center', padding: '1.5rem', borderRadius: '12px'}}> |
| 84 | <svg |
| 85 | viewBox="0 0 560 380" |
| 86 | style={{maxWidth: '100%', height: 'auto', fontFamily: "'Inter', system-ui, sans-serif"}} |
| 87 | role="img" |
| 88 | aria-label="Chart showing AIO organic CTR rebound from 1.3% to about 2.4%" |
| 89 | > |
| 90 | <title>AIO Organic CTR Rebound</title> |
| 91 | <desc>Bar chart comparing the December 2025 AIO CTR floor to the February 2026 rebound</desc> |
| 92 | <text x="280" y="30" textAnchor="middle" fontSize="16" fontWeight="700" fill="currentColor"> |
| 93 | AIO Organic CTR Rebound |
| 94 | </text> |
| 95 | <rect x="100" y="152" width="160" height="108" rx="6" fill="#f97316" /> |
| 96 | <text x="180" y="212" textAnchor="middle" fontSize="14" fontWeight="800" fill="white"> |
| 97 | 1.3% |
| 98 | </text> |
| 99 | <rect x="300" y="60" width="160" height="200" rx="6" fill="#38bdf8" /> |
| 100 | <text x="380" y="165" textAnchor="middle" fontSize="14" fontWeight="800" fill="white"> |
| 101 | ~2.4% |
| 102 | </text> |
| 103 | <text x="280" y="372" textAnchor="middle" fontSize="10" fill="currentColor" opacity="0.35"> |
| 104 | Source: Seer Interactive (Apr 2026) |
| 105 | </text> |
| 106 | </svg> |
| 107 | </figure> |
| 108 | |
| 109 | |
| 110 | **JSX attribute conversion reference:** |
| 111 | |
| 112 | | HTML Attribute | JSX Attribute | |
| 113 | |----------------|---------------| |
| 114 | | `stroke-width` | `strokeWidth` | |
| 115 | | `stroke-dasharray` | `strokeDasharray` | |
| 116 | | `stroke-linecap` | `strokeLinecap` | |
| 117 | | `text-anchor` | `textAnchor` | |
| 118 | | `font-size` | `fontSize` | |
| 119 | | `font-weight` | `fontWeight` | |
| 120 | | `font-family` | `fontFamily` | |
| 121 | | `class` | `className` | |
| 122 | | `style="..."` | `style={{...}}` | |
| 123 | | `fill-opacity` | `fillOpacity` | |
| 124 | | `stop-color` | `stopColor` | |
| 125 | | `clip-path` | `clipPath` | |
| 126 | |
| 127 | ### MDX Component Imports for Custom Charts |
| 128 | |
| 129 | import { BarChart } from '@/components/charts/BarChart' |
| 130 | import { FAQSchema } from '@/components/FAQSchema' |
| 131 | |
| 132 | <BarChart data={chartData} title="AIO Organic CTR Rebound" /> |
| 133 | <FAQSchema faqs={[{ question: "...", answer: "..." }]} /> |
| 134 | |
| 135 | |
| 136 | Check the project's `components/` directory for available chart components |
| 137 | before inlining SVG. Use project components when they exist. |
| 138 | |
| 139 | ### generateStaticParams for SSG (Critical for AI Crawlers) |
| 140 | |
| 141 | AI crawlers (GPTBot, ClaudeBot, PerplexityBot) cannot execute JavaScript. |
| 142 | Pages must be statically generated or server-rendered. Never use client-only |
| 143 | rendering for blog content. |
| 144 | |
| 145 | |
| 146 | // app/blog/[slug]/page.tsx |
| 147 | export async function generateStaticParams() { |
| 148 | const posts = getAllPosts() |
| 149 | return posts.map((post) => ({ |
| 150 | slug: post.slug, |
| 151 | })) |
| 152 | } |
| 153 | |
| 154 | export async function generateMetadata({ params }: Props): Promise<Metadata> { |
| 155 | const { slug } = await params |
| 156 | const post = getPostBySlug(slug) |
| 157 | return { |
| 158 | title: post.title, |
| 159 | description: post.description, |
| 160 | openGraph: { |
| 161 | title: post.title, |
| 162 | description: post.description, |
| 163 | images: [post.ogImage], |
| 164 | type: 'article', |
| 165 | publishedTime: post.date, |
| 166 | modifiedTime: post.lastUpdated, |
| 167 | }, |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | |
| 172 | ### Key Configuration Notes |
| 173 | MDX files require `@next/mdx` or `next-mdx-remote` package |
| 174 | Verify `mdx-components.tsx` exists at project root for custom element mapping |
| 175 | Use `export const metadata` or `generateMetadata` for per-page SEO |
| 176 | JSON-LD schema should be rendered in the page component, not injected client-side |
| 177 | Sitemap: use `app/sitemap.ts` with `MetadataRoute.Sitemap` type |
| 178 | |
| 179 | |
| 180 | |
| 181 | ## Astro |
| 182 | |
| 183 | ### Frontmatter Format |
| 184 | |
| 185 | |
| 186 | title: "How Does AI Search Impact Organic Traffic in 2026?" |
| 187 | description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize." |
| 188 | pubDate: 2026-02-18 |
| 189 | updatedDate: 2026-02-18 |
| 190 | author: "Author Name" |
| 191 | tags: ["ai-search", "seo", "traffic"] |
| 192 | heroImage: "/images/ai-search-cover.jpg" |
| 193 | heroImageAlt: "Marketing dashboard showing AI search metrics" |
| 194 | |
| 195 | |
| 196 | |
| 197 | Astro uses `pubDate` and `updatedDate` (Date objects) instead of `date` |
| 198 | and `lastUpdated` (strings). Adapt to match the project's content schema. |
| 199 | |
| 200 | ### Content Collections (src/content/blog/) |
| 201 | |
| 202 | Astro 4+ uses type-safe content collections with Zod schema validation: |
| 203 | |
| 204 | |
| 205 | // src/content/config.ts |
| 206 | import { defineCollection, z } from 'astro:content' |
| 207 | |
| 208 | const blog = defineCollection({ |
| 209 | type: 'content', |
| 210 | schema: z.object({ |
| 211 | title: z.string(), |
| 212 | description: z.string(), |
| 213 | pubDate: z.coerce.date(), |
| 214 | updatedDate: z.coerce.date().optional(), |
| 215 | author: z.string().optional(), |
| 216 | tags: z.array(z.string()).optional(), |
| 217 | heroImage: z.string().optional(), |
| 218 | heroImageAlt: z.string().optional(), |
| 219 | }), |
| 220 | }) |
| 221 | |
| 222 | export const collections = { blog } |
| 223 | |
| 224 | |
| 225 | Place blog posts in `src/content/blog/` as `.md` or `.mdx` files. |
| 226 | |
| 227 | ### Image Embedding |
| 228 | |
| 229 |  |
| 230 | |
| 231 | |
| 232 | Using `astro:assets` for optimization: |
| 233 | |
| 234 | |
| 235 | import { Image } from 'astro:assets' |
| 236 | import searchDashboard from '../assets/search-dashboard.jpg' |
| 237 | |
| 238 | <Image src={searchDashboard} alt="Marketing team analyzing search data" /> |
| 239 | |
| 240 | |
| 241 | For remote images, configure `astro.config.mjs`: |
| 242 | |
| 243 | export default defineConfig({ |
| 244 | image: { |
| 245 | domains: ['cdn.pixabay.com', 'images.unsplash.com', 'images.pexels.com'], |
| 246 | }, |
| 247 | }) |
| 248 | |
| 249 | |
| 250 | ### Chart / SVG Embedding |
| 251 | |
| 252 | Standard SVG works directly in `.md` files. For `.astro` component wrappers: |
| 253 | |
| 254 | |
| 255 | |
| 256 | // src/components/Chart.astro |
| 257 | const { title, ariaLabel } = Astro.props |
| 258 | |
| 259 | <figure class="chart-container"> |
| 260 | <slot /> |
| 261 | <figcaption>{title}</figcaption> |
| 262 | </figure> |
| 263 | |
| 264 | |
| 265 | Use standard HTML attributes (not camelCase) in `.astro` and `.md` files: |
| 266 | |
| 267 | <svg viewBox="0 0 560 380" role="img" aria-label="AIO CTR rebound chart"> |
| 268 | <text x="280" y="30" text-anchor="middle" font-size="16" fill="currentColor"> |
| 269 | Chart Title |
| 270 | </text> |
| 271 | </svg> |
| 272 | |
| 273 | |
| 274 | ### Key Configuration Notes |
| 275 | Static output by default (SSG): ideal for AI crawlers without JS execution |
| 276 | Markdown files support raw HTML/SVG natively (no unsafe config needed) |
| 277 | For MDX support: add `@astrojs/mdx` integration |
| 278 | Sitemap: add `@astrojs/sitemap` integration with `site` config |
| 279 | RSS: add `@astrojs/rss` for feed generation |
| 280 | View Transitions: built-in via `<ViewTransitions />` component |
| 281 | |
| 282 | |
| 283 | |
| 284 | ## Hugo |
| 285 | |
| 286 | ### Frontmatter Format (YAML) |
| 287 | |
| 288 | |
| 289 | title: "How Does AI Search Impact Organic Traffic in 2026?" |
| 290 | description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize." |
| 291 | date: 2026-02-18 |
| 292 | lastmod: 2026-02-18 |
| 293 | author: "Author Name" |
| 294 | tags: ["ai-search", "seo", "traffic"] |
| 295 | categories: ["SEO Strategy"] |
| 296 | series: ["AI Search Optimization"] |
| 297 | images: |
| 298 | - "/images/ai-search-cover.jpg" |
| 299 | draft: false |
| 300 | |
| 301 | |
| 302 | |
| 303 | ### Frontmatter Format (TOML) |
| 304 | |
| 305 | +++ |
| 306 | title = "How Does AI Search Impact Organic Traffic in 2026?" |
| 307 | description = "AI Overview CTR gap narrowed to about 38%." |
| 308 | date = 2026-02-18 |
| 309 | lastmod = 2026-02-18 |
| 310 | author = "Author Name" |
| 311 | tags = ["ai-search", "seo", "traffic"] |
| 312 | categories = ["SEO Strategy"] |
| 313 | series = ["AI Search Optimization"] |
| 314 | images = ["/images/ai-search-cover.jpg"] |
| 315 | draft = false |
| 316 | +++ |
| 317 | |
| 318 | |
| 319 | Hugo uses `lastmod` instead of `lastUpdated`. Supports both YAML (`---`) |
| 320 | and TOML (`+++`) frontmatter delimiters. |
| 321 | |
| 322 | ### Taxonomy Structure |
| 323 | Hugo supports three built-in taxonomies: |
| 324 | **categories**: Broad topic groupings (content pillars) |
| 325 | **tags**: Specific topic labels (keywords) |
| 326 | **series**: Multi-part content sequences |
| 327 | |
| 328 | Configure in `hugo.toml`: |
| 329 | |
| 330 | [taxonomies] |
| 331 | category = "categories" |
| 332 | tag = "tags" |
| 333 | series = "series" |
| 334 | |
| 335 | |
| 336 | ### Image Embedding |
| 337 | |
| 338 |  |
| 339 | |
| 340 | |
| 341 | Hugo processes images from `static/images/` or page bundles (`content/blog/post-name/images/`). |
| 342 | |
| 343 | ### Chart / SVG Embedding via Shortcodes |
| 344 | |
| 345 | Create a custom shortcode for trusted, sanitized inline SVG only. Do not pass |
| 346 | user-derived or generated text through `safeHTML` unless it has been sanitized |
| 347 | with a strict SVG allowlist. |
| 348 | |
| 349 | |
| 350 | <!-- layouts/shortcodes/chart.html --> |
| 351 | <figure class="chart-container" style="margin: 2.5rem 0; text-align: center;"> |
| 352 | {{ .Inner | safeHTML }} |
| 353 | {{ with .Get "caption" }}<figcaption>{{ . }}</figcaption>{{ end }} |
| 354 | </figure> |
| 355 | |
| 356 | |
| 357 | Usage in markdown: |
| 358 | |
| 359 | {{< chart caption="Source: Seer Interactive (Apr 2026)" >}} |
| 360 | <svg viewBox="0 0 560 380" role="img" aria-label="AIO CTR rebound chart"> |
| 361 | <!-- SVG content --> |
| 362 | </svg> |
| 363 | {{< /chart >}} |
| 364 | |
| 365 | |
| 366 | ### Goldmark Renderer Config (Required for SVG) |
| 367 | |
| 368 | Hugo's default Goldmark renderer escapes raw HTML. Enable unsafe rendering only |
| 369 | for trusted authored SVG/HTML after sanitization: |
| 370 | |
| 371 | |
| 372 | # hugo.toml |
| 373 | [markup.goldmark.renderer] |
| 374 | unsafe = true |
| 375 | |
| 376 | |
| 377 | Without this setting, all `<svg>`, `<figure>`, and other HTML tags in markdown |
| 378 | files will be stripped from the output. If authors or external systems can |
| 379 | provide markup, prefer a shortcode that sanitizes SVG and rejects scripts, |
| 380 | event-handler attributes, foreignObject, external resources, and unsafe URLs. |
| 381 | |
| 382 | ### Custom Archetypes |
| 383 | |
| 384 | <!-- archetypes/blog.md --> |
| 385 | |
| 386 | title: "{{ replace .Name "-" " " | title }}" |
| 387 | description: "" |
| 388 | date: {{ .Date }} |
| 389 | lastmod: {{ .Date }} |
| 390 | author: "" |
| 391 | tags: [] |
| 392 | categories: [] |
| 393 | images: [] |
| 394 | draft: true |
| 395 | |
| 396 | |
| 397 | ## Introduction |
| 398 | |
| 399 | [Hook with statistic] |
| 400 | |
| 401 | |
| 402 | Create new posts with: `hugo new blog/my-post-title.md` |
| 403 | |
| 404 | ### Key Configuration Notes |
| 405 | Posts go in `content/blog/` or `content/posts/` (check project convention) |
| 406 | Page bundles (`content/blog/post-name/index.md`) co-locate images with content |
| 407 | Use `{{ .Params.lastmod }}` in templates for freshness display |
| 408 | JSON-LD schema: add in `layouts/partials/schema.html` partial |
| 409 | Sitemap auto-generated at `/sitemap.xml` |
| 410 | RSS auto-generated at `/index.xml` |
| 411 | |
| 412 | |
| 413 | |
| 414 | ## Jekyll |
| 415 | |
| 416 | ### Frontmatter Format (YAML Required) |
| 417 | |
| 418 | |
| 419 | layout: post |
| 420 | title: "How Does AI Search Impact Organic Traffic in 2026?" |
| 421 | description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize." |
| 422 | date: 2026-02-18 |
| 423 | last_modified_at: 2026-02-18 |
| 424 | author: "Author Name" |
| 425 | categories: [seo-strategy] |
| 426 | tags: [ai-search, seo, traffic] |
| 427 | image: /assets/images/ai-search-cover.jpg |
| 428 | |
| 429 | |
| 430 | |
| 431 | ### Naming Convention (Required) |
| 432 | Posts must follow: `_posts/YYYY-MM-DD-title-slug.md` |
| 433 | Example: `_posts/2026-02-18-ai-search-organic-traffic.md` |
| 434 | |
| 435 | Jekyll will not process files that do not follow this naming pattern. |
| 436 | |
| 437 | ### Image Embedding |
| 438 | |
| 439 |  |
| 440 | |
| 441 | |
| 442 | Images live in `assets/images/` or `images/` depending on project convention. |
| 443 | |
| 444 | ### Chart / SVG Embedding |
| 445 | |
| 446 | Jekyll uses the kramdown renderer, which passes through raw HTML: |
| 447 | |
| 448 | |
| 449 | <figure> |
| 450 | <svg viewBox="0 0 560 380" role="img" aria-label="AIO CTR rebound chart"> |
| 451 | <!-- SVG content with standard HTML attributes --> |
| 452 | </svg> |
| 453 | <figcaption>Source: Seer Interactive (Apr 2026)</figcaption> |
| 454 | </figure> |
| 455 | |
| 456 | |
| 457 | No special configuration needed: kramdown does not strip HTML by default. |
| 458 | |
| 459 | ### Liquid Templates |
| 460 | |
| 461 | Access page variables in layouts: |
| 462 | |
| 463 | <h1>{{ page.title }}</h1> |
| 464 | <time datetime="{{ page.date | date_to_xmlschema }}"> |
| 465 | {{ page.date | date: "%B %d, %Y" }} |
| 466 | </time> |
| 467 | |
| 468 | {% if page.last_modified_at %} |
| 469 | <meta property="article:modified_time" |
| 470 | content="{{ page.last_modified_at | date_to_xmlschema }}"> |
| 471 | {% endif %} |
| 472 | |
| 473 | |
| 474 | Loop through posts: |
| 475 | |
| 476 | {% for post in site.posts limit:10 %} |
| 477 | <article> |
| 478 | <h2><a href="{{ post.url }}">{{ post.title }}</a></h2> |
| 479 | <p>{{ post.description }}</p> |
| 480 | </article> |
| 481 | {% endfor %} |
| 482 | |
| 483 | |
| 484 | ### Layout Hierarchy |
| 485 | |
| 486 | _layouts/ |
| 487 | default.html <-- Base layout (HTML shell, head, nav, footer) |
| 488 | post.html <-- Blog post layout (extends default) |
| 489 | page.html <-- Static page layout (extends default) |
| 490 | |
| 491 | |
| 492 | ### Math Support via MathJax |
| 493 | |
| 494 | # _config.yml |
| 495 | markdown: kramdown |
| 496 | kramdown: |
| 497 | math_engine: mathjax |
| 498 | |
| 499 | |
| 500 | Usage in posts: |
| 501 | |
| 502 | The formula is $$ E = mc^2 $$ |
| 503 | |
| 504 | |
| 505 | ### Key Configuration Notes |
| 506 | `_config.yml` is the central configuration file |
| 507 | Collections: define custom collections beyond posts in `_config.yml` |
| 508 | Plugins: `jekyll-seo-tag` for automatic OG/Twitter meta tags |
| 509 | `jekyll-sitemap` for sitemap generation |
| 510 | `jekyll-last-modified-at` for automatic `last_modified_at` from git |
| 511 | Build with `bundle exec jekyll build` (produces `_site/` directory) |
| 512 | JSON-LD: use `jekyll-seo-tag` or manually include in `_includes/head.html` |
| 513 | |
| 514 | |
| 515 | |
| 516 | ## WordPress |
| 517 | |
| 518 | ### Gutenberg Blocks (Modern) |
| 519 | |
| 520 | Gutenberg uses block-based editing. Key blocks for blog content: |
| 521 | |
| 522 | | Block | Purpose | Notes | |
| 523 | |-------|---------|-------| |
| 524 | | Paragraph | Body text | Each paragraph auto-wraps in `<p>` | |
| 525 | | Heading | H2-H6 | Set level in block toolbar | |
| 526 | | Image | Photos | Set alt text, caption, link in sidebar | |
| 527 | | Custom HTML | SVG charts | Paste raw SVG in HTML block | |
| 528 | | List | Bullets/numbers | For FAQ answers, step lists | |
| 529 | | Quote | Blockquotes | For expert quotes with attribution | |
| 530 | | Table | Comparison tables | For feature/pricing comparisons | |
| 531 | | Group | Wrappers | Group blocks for styling | |
| 532 | |
| 533 | ### Classic Editor (HTML) |
| 534 | |
| 535 | <h2>How Does AI Search Impact Organic Traffic?</h2> |
| 536 | |
| 537 | <p>AIO organic CTR rebounded from 1.3% in December 2025 to about 2.4% |
| 538 | in February 2026 (<a href="https://seerinteractive.com">Seer Interactive</a>, |
| 539 | April 2026). This means brands should optimize for citation, since cited pages |
| 540 | earn 120% more clicks per impression.</p> |
| 541 | |
| 542 | <figure> |
| 543 | <img src="https://cdn.pixabay.com/photo/.../image.jpg" |
| 544 | alt="Marketing dashboard showing AI search traffic metrics" |
| 545 | width="1200" height="630" loading="lazy"> |
| 546 | <figcaption>Photo via Pixabay</figcaption> |
| 547 | </figure> |
| 548 | |
| 549 | |
| 550 | ### Image Embedding |
| 551 | Upload via Media Library, then insert. Set these fields: |
| 552 | **Alt text**: Descriptive sentence with topic keywords |
| 553 | **Title**: Short descriptive title |
| 554 | **Caption**: Optional, shows below image |
| 555 | **Featured Image**: Set in post sidebar (used as OG image and blog listing) |
| 556 | |
| 557 | ### Chart / SVG Embedding |
| 558 | Use the Custom HTML block: |
| 559 | |
| 560 | <figure class="wp-block-html chart-container"> |
| 561 | <svg viewBox="0 0 560 380" role="img" aria-label="Chart description"> |
| 562 | <!-- Standard SVG with HTML attributes --> |
| 563 | </svg> |
| 564 | </figure> |
| 565 | |
| 566 | |
| 567 | ### Yoast SEO / RankMath Integration |
| 568 | |
| 569 | | Field | Where | Purpose | |
| 570 | |-------|-------|---------| |
| 571 | | Focus keyword | SEO panel below editor | Primary target keyword | |
| 572 | | SEO title | SEO panel | Title tag (if different from H1) | |
| 573 | | Meta description | SEO panel | 150-160 chars, fact-dense | |
| 574 | | Canonical URL | SEO panel → Advanced | Prevents duplicate content | |
| 575 | | OG image | Social tab in SEO panel | Social sharing preview | |
| 576 | | OG title | Social tab | Title for social shares | |
| 577 | | OG description | Social tab | Description for social shares | |
| 578 | |
| 579 | ### Custom Fields for Structured Data |
| 580 | Use ACF (Advanced Custom Fields) or native custom fields: |
| 581 | `last_updated`: for dateModified in schema |
| 582 | `author_bio`: for E-E-A-T author section |
| 583 | `faq_items`: for FAQPage entity markup when visible Q&A exists |
| 584 | |
| 585 | ### Featured Image |
| 586 | Set via the "Featured Image" panel in the post editor sidebar. This image |
| 587 | serves as both the blog listing thumbnail and the OG image for social sharing. |
| 588 | Recommended size: 1200x630px. |
| 589 | |
| 590 | ### Excerpt Field |
| 591 | The Excerpt field (in post sidebar) generates the meta description if Yoast/ |
| 592 | RankMath meta description is empty. Keep it to 150-160 characters, fact-dense, |
| 593 | with at least one statistic. |
| 594 | |
| 595 | ### Key Configuration Notes |
| 596 | Permalink structure: Settings > Permalinks > Post name (`/%postname%/`) |
| 597 | REST API: `wp-json/wp/v2/posts` for programmatic publishing |
| 598 | Schema: Yoast/RankMath auto-generates BlogPosting schema |
| 599 | Caching: use WP Super Cache or W3 Total Cache for TTFB < 200ms |
| 600 | Security: keep WordPress, themes, and plugins updated |
| 601 | robots.txt: accessible at `/robots.txt`, configure via Yoast |
| 602 | |
| 603 | |
| 604 | |
| 605 | ## Ghost |
| 606 | |
| 607 | ### Content Formats |
| 608 | Modern Ghost stores editor content in Lexical JSON and accepts HTML input for |
| 609 | HTML cards and Admin API publishing. |
| 610 | |
| 611 | ### Ghost Admin API (Programmatic Publishing) |
| 612 | |
| 613 | const GhostAdminAPI = require('@tryghost/admin-api') |
| 614 | |
| 615 | const api = new GhostAdminAPI({ |
| 616 | url: 'https://your-blog.ghost.io', |
| 617 | key: 'ADMIN_API_KEY', |
| 618 | version: 'v5.0' |
| 619 | }) |
| 620 | |
| 621 | api.posts.add({ |
| 622 | title: 'How Does AI Search Impact Organic Traffic in 2026?', |
| 623 | html: '<p>AIO organic CTR rebounded from 1.3% to about 2.4%...</p>', |
| 624 | status: 'draft', |
| 625 | tags: [{ name: 'AI Search' }, { name: 'SEO' }], |
| 626 | meta_title: 'AI Search Impact on Organic Traffic (2026 Data)', |
| 627 | meta_description: 'AI Overview CTR gap narrowed to about 38%...', |
| 628 | og_image: 'https://cdn.pixabay.com/photo/.../cover.jpg', |
| 629 | og_title: 'AI Search Impact on Organic Traffic', |
| 630 | og_description: 'New data reveals how AI search reshapes organic visibility.', |
| 631 | canonical_url: 'https://your-blog.com/ai-search-organic-traffic', |
| 632 | feature_image: 'https://cdn.pixabay.com/photo/.../cover.jpg', |
| 633 | feature_image_alt: 'Marketing dashboard showing AI search metrics', |
| 634 | }) |
| 635 | |
| 636 | |
| 637 | ### Image Embedding |
| 638 | In the Ghost editor, use the Image card. For HTML content: |
| 639 | |
| 640 | <figure class="kg-card kg-image-card"> |
| 641 | <img class="kg-image" |
| 642 | src="https://cdn.pixabay.com/photo/.../image.jpg" |
| 643 | alt="Marketing team analyzing AI search data" |
| 644 | loading="lazy"> |
| 645 | <figcaption>Photo via Pixabay</figcaption> |
| 646 | </figure> |
| 647 | |
| 648 | |
| 649 | ### Chart / SVG Embedding |
| 650 | Use the HTML card in the Ghost editor to paste raw SVG: |
| 651 | |
| 652 | <figure class="kg-card kg-html-card"> |
| 653 | <svg viewBox="0 0 560 380" role="img" aria-label="Chart description"> |
| 654 | <!-- Standard SVG --> |
| 655 | </svg> |
| 656 | </figure> |
| 657 | |
| 658 | |
| 659 | ### Built-in SEO Fields |
| 660 | |
| 661 | | Field | Location | Purpose | |
| 662 | |-------|----------|---------| |
| 663 | | Meta title | Post settings > Meta data | Title tag override | |
| 664 | | Meta description | Post settings > Meta data | 150-160 chars | |
| 665 | | Canonical URL | Post settings > Meta data | Duplicate prevention | |
| 666 | | OG image | Post settings > Twitter/Facebook | Social preview image | |
| 667 | | OG title | Post settings > Twitter/Facebook | Social preview title | |
| 668 | | Feature image | Post header | Hero + OG fallback | |
| 669 | | Feature image alt | Post header | Accessibility | |
| 670 | | Excerpt | Post settings > Excerpt | Newsletter + listing text | |
| 671 | |
| 672 | ### Custom Theme Considerations |
| 673 | Ghost themes use Handlebars templates: |
| 674 | |
| 675 | {{! post.hbs }} |
| 676 | <article class="post"> |
| 677 | <h1>{{title}}</h1> |
| 678 | <time datetime="{{date format='YYYY-MM-DD'}}">{{date format="MMMM DD, YYYY"}}</time> |
| 679 | {{#if updated_at}} |
| 680 | <time datetime="{{updated_at format='YYYY-MM-DD'}}"> |
| 681 | Updated: {{updated_at format="MMMM DD, YYYY"}} |
| 682 | </time> |
| 683 | {{/if}} |
| 684 | <div class="post-content">{{content}}</div> |
| 685 | </article> |
| 686 | |
| 687 | |
| 688 | ### Dynamic Routing |
| 689 | Configure content organization in `routes.yaml`: |
| 690 | |
| 691 | routes: |
| 692 | /about/: about |
| 693 | |
| 694 | collections: |
| 695 | /blog/: |
| 696 | permalink: /blog/{slug}/ |
| 697 | filter: tag:-hash-podcast |
| 698 | template: blog |
| 699 | |
| 700 | taxonomies: |
| 701 | tag: /tag/{slug}/ |
| 702 | author: /author/{slug}/ |
| 703 | |
| 704 | |
| 705 | ### Key Configuration Notes |
| 706 | Ghost themes often output structured data automatically, but custom and |
| 707 | headless themes must validate rendered JSON-LD in the final HTML |
| 708 | Default output is server-rendered HTML: AI crawlers can access content |
| 709 | Newsletters: Ghost has built-in email sending for subscriber lists |
| 710 | Membership: tiers and paid content built-in |
| 711 | Themes: install via Ghost Admin > Settings > Design |
| 712 | Content API: for headless CMS setups (read-only, public content) |
| 713 | |
| 714 | |
| 715 | |
| 716 | ## 11ty (Eleventy) |
| 717 | |
| 718 | ### Frontmatter Format |
| 719 | |
| 720 | |
| 721 | title: "How Does AI Search Impact Organic Traffic in 2026?" |
| 722 | description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize." |
| 723 | date: 2026-02-18 |
| 724 | lastUpdated: 2026-02-18 |
| 725 | author: "Author Name" |
| 726 | tags: |
| 727 | - ai-search |
| 728 | - seo |
| 729 | - posts |
| 730 | layout: post.njk |
| 731 | coverImage: "/images/ai-search-cover.jpg" |
| 732 | coverImageAlt: "Marketing dashboard showing AI search metrics" |
| 733 | |
| 734 | |
| 735 | |
| 736 | ### Template Languages |
| 737 | 11ty supports Nunjucks (`.njk`), Liquid (`.liquid`), Handlebars (`.hbs`), |
| 738 | JavaScript (`.11ty.js`), and more. Nunjucks is the most common choice. |
| 739 | |
| 740 | ### Data Cascade |
| 741 | 11ty merges data from multiple sources (highest to lowest priority): |
| 742 | **File data**: frontmatter in the content file |
| 743 | **Directory data**: `blog.json` in the content directory |
| 744 | **Global data**: files in `_data/` directory |
| 745 | |
| 746 | |
| 747 | // blog/blog.json (applies to all files in blog/) |
| 748 | { |
| 749 | "layout": "post.njk", |
| 750 | "tags": ["posts"], |
| 751 | "permalink": "/blog/{{ page.fileSlug }}/" |
| 752 | } |
| 753 | |
| 754 | |
| 755 | ### Image Embedding |
| 756 | |
| 757 |  |
| 758 | |
| 759 | |
| 760 | For optimized images, use `eleventy-img` plugin: |
| 761 | |
| 762 | {% image "src/images/search-dashboard.jpg", "Marketing team analyzing search data" %} |
| 763 | |
| 764 | |
| 765 | ### Chart / SVG Embedding |
| 766 | Raw HTML/SVG works directly in markdown files. 11ty passes through HTML |
| 767 | without stripping. |
| 768 | |
| 769 | |
| 770 | <figure> |
| 771 | <svg viewBox="0 0 560 380" role="img" aria-label="AIO CTR rebound chart"> |
| 772 | <!-- SVG content --> |
| 773 | </svg> |
| 774 | <figcaption>Source: Seer Interactive (Apr 2026)</figcaption> |
| 775 | </figure> |
| 776 | |
| 777 | |
| 778 | ### Computed Data for Dates and URLs |
| 779 | |
| 780 | // blog/blog.11tydata.js |
| 781 | module.exports = { |
| 782 | eleventyComputed: { |
| 783 | permalink: (data) => `/blog/${data.page.fileSlug}/`, |
| 784 | lastUpdatedDisplay: (data) => { |
| 785 | const date = data.lastUpdated || data.page.date |
| 786 | return new Date(date).toLocaleDateString('en-US', { |
| 787 | year: 'numeric', month: 'long', day: 'numeric' |
| 788 | }) |
| 789 | } |
| 790 | } |
| 791 | } |
| 792 | |
| 793 | |
| 794 | ### Passthrough File Copy |
| 795 | |
| 796 | // .eleventy.js |
| 797 | module.exports = function(eleventyConfig) { |
| 798 | eleventyConfig.addPassthroughCopy("src/images") |
| 799 | eleventyConfig.addPassthroughCopy("src/svg") |
| 800 | eleventyConfig.addPassthroughCopy({ "src/favicon.ico": "/" }) |
| 801 | } |
| 802 | |
| 803 | |
| 804 | ### Key Configuration Notes |
| 805 | Static output by default: ideal for AI crawlers |
| 806 | No build-step JS unless explicitly added (fast pages) |
| 807 | Collections: use `tags` in frontmatter to group content |
| 808 | Filters: add custom Nunjucks filters in `.eleventy.js` for date formatting |
| 809 | Pagination: built-in for tag pages and archive pages |
| 810 | JSON-LD: inject via layout template using frontmatter data |
| 811 | Sitemap: use `eleventy-plugin-sitemap` or generate manually |
| 812 | |
| 813 | |
| 814 | |
| 815 | ## Gatsby |
| 816 | |
| 817 | ### Frontmatter Format |
| 818 | |
| 819 | |
| 820 | title: "How Does AI Search Impact Organic Traffic in 2026?" |
| 821 | description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize." |
| 822 | date: "2026-02-18" |
| 823 | lastUpdated: "2026-02-18" |
| 824 | author: "Author Name" |
| 825 | tags: ["ai-search", "seo", "traffic"] |
| 826 | slug: "ai-search-organic-traffic" |
| 827 | featuredImage: "../images/ai-search-cover.jpg" |
| 828 | featuredImageAlt: "Marketing dashboard showing AI search metrics" |
| 829 | |
| 830 | |
| 831 | |
| 832 | ### MDX Support |
| 833 | |
| 834 | // gatsby-config.js |
| 835 | module.exports = { |
| 836 | plugins: [ |
| 837 | { |
| 838 | resolve: 'gatsby-plugin-mdx', |
| 839 | options: { |
| 840 | extensions: ['.mdx', '.md'], |
| 841 | gatsbyRemarkPlugins: [ |
| 842 | 'gatsby-remark-images', |
| 843 | 'gatsby-remark-prismjs', |
| 844 | ], |
| 845 | }, |
| 846 | }, |
| 847 | ], |
| 848 | } |
| 849 | |
| 850 | |
| 851 | ### Image Embedding |
| 852 | |
| 853 |  |
| 854 | |
| 855 | |
| 856 | Using `gatsby-plugin-image`: |
| 857 | |
| 858 | import { GatsbyImage, getImage } from 'gatsby-plugin-image' |
| 859 | |
| 860 | const BlogPost = ({ data }) => { |
| 861 | const image = getImage(data.mdx.frontmatter.featuredImage) |
| 862 | return ( |
| 863 | <GatsbyImage |
| 864 | image={image} |
| 865 | alt={data.mdx.frontmatter.featuredImageAlt} |
| 866 | /> |
| 867 | ) |
| 868 | } |
| 869 | |
| 870 | |
| 871 | ### Chart / SVG Embedding |
| 872 | In MDX files, use JSX-compatible SVG (same camelCase rules as Next.js): |
| 873 | |
| 874 | <figure style={{margin: '2.5rem 0', textAlign: 'center'}}> |
| 875 | <svg viewBox="0 0 560 380" role="img" aria-label="CTR chart"> |
| 876 | <text x="280" y="30" textAnchor="middle" fontSize="16" fill="currentColor"> |
| 877 | Chart Title |
| 878 | </text> |
| 879 | </svg> |
| 880 | </figure> |
| 881 | |
| 882 | |
| 883 | ### GraphQL Data Layer |
| 884 | |
| 885 | query BlogPostBySlug($slug: String!) { |
| 886 | mdx(frontmatter: { slug: { eq: $slug } }) { |
| 887 | body |
| 888 | frontmatter { |
| 889 | title |
| 890 | description |
| 891 | date(formatString: "MMMM DD, YYYY") |
| 892 | lastUpdated(formatString: "MMMM DD, YYYY") |
| 893 | tags |
| 894 | featuredImage { |
| 895 | childImageSharp { |
| 896 | gatsbyImageData(width: 1200, placeholder: BLURRED) |
| 897 | } |
| 898 | } |
| 899 | } |
| 900 | } |
| 901 | } |
| 902 | |
| 903 | |
| 904 | ### createPages API for Dynamic Routes |
| 905 | |
| 906 | // gatsby-node.js |
| 907 | const path = require('path') |
| 908 | const blogPostTemplate = path.resolve('./src/templates/blog-post.tsx') |
| 909 | |
| 910 | exports.createPages = async ({ graphql, actions }) => { |
| 911 | const { createPage } = actions |
| 912 | const result = await graphql(` |
| 913 | query { |
| 914 | allMdx { |
| 915 | nodes { |
| 916 | id |
| 917 | frontmatter { slug } |
| 918 | internal { contentFilePath } |
| 919 | } |
| 920 | } |
| 921 | } |
| 922 | `) |
| 923 | |
| 924 | result.data.allMdx.nodes.forEach((node) => { |
| 925 | createPage({ |
| 926 | path: `/blog/${node.frontmatter.slug}`, |
| 927 | component: `${blogPostTemplate}?__contentFilePath=${node.internal.contentFilePath}`, |
| 928 | context: { id: node.id }, |
| 929 | }) |
| 930 | }) |
| 931 | } |
| 932 | |
| 933 | |
| 934 | ### Key Configuration Notes |
| 935 | Static output at build time: AI crawlers get full HTML |
| 936 | Use `gatsby-plugin-sitemap` for sitemap generation |
| 937 | Use `gatsby-plugin-robots-txt` for robots.txt configuration |
| 938 | `gatsby-plugin-react-helmet` or Gatsby Head API for meta tags |
| 939 | JSON-LD: use `gatsby-plugin-schema-snapshot` or inline in Head component |
| 940 | Build can be slow for large sites: consider incremental builds |
| 941 | |
| 942 | |
| 943 | |
| 944 | ## HTML / Static |
| 945 | |
| 946 | ### Semantic HTML5 Structure |
| 947 | |
| 948 | <!DOCTYPE html> |
| 949 | <html lang="en"> |
| 950 | <head> |
| 951 | <meta charset="utf-8"> |
| 952 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 953 | <title>How Does AI Search Impact Organic Traffic in 2026?</title> |
| 954 | <meta name="description" content="AI Overview CTR gap narrowed to about 38%. Here's how to optimize for Google rankings and AI citations in 2026."> |
| 955 | |
| 956 | <!-- Open Graph --> |
| 957 | <meta property="og:type" content="article"> |
| 958 | <meta property="og:title" content="How Does AI Search Impact Organic Traffic in 2026?"> |
| 959 | <meta property="og:description" content="AI Overview CTR gap narrowed to about 38%."> |
| 960 | <meta property="og:image" content="https://cdn.pixabay.com/photo/.../cover.jpg"> |
| 961 | <meta property="og:url" content="https://yourblog.com/ai-search-organic-traffic"> |
| 962 | <meta property="article:published_time" content="2026-02-18T00:00:00Z"> |
| 963 | <meta property="article:modified_time" content="2026-02-18T00:00:00Z"> |
| 964 | |
| 965 | <!-- Twitter Card --> |
| 966 | <meta name="twitter:card" content="summary_large_image"> |
| 967 | <meta name="twitter:title" content="How Does AI Search Impact Organic Traffic in 2026?"> |
| 968 | <meta name="twitter:description" content="AI Overview CTR gap narrowed to about 38%."> |
| 969 | <meta name="twitter:image" content="https://cdn.pixabay.com/photo/.../cover.jpg"> |
| 970 | |
| 971 | <!-- JSON-LD Structured Data --> |
| 972 | <script type="application/ld+json"> |
| 973 | { |
| 974 | "@context": "https://schema.org", |
| 975 | "@type": "BlogPosting", |
| 976 | "headline": "How Does AI Search Impact Organic Traffic in 2026?", |
| 977 | "description": "AI Overview CTR gap narrowed to about 38%.", |
| 978 | "image": "https://cdn.pixabay.com/photo/.../cover.jpg", |
| 979 | "datePublished": "2026-02-18", |
| 980 | "dateModified": "2026-02-18", |
| 981 | "author": { |
| 982 | "@type": "Person", |
| 983 | "name": "Author Name", |
| 984 | "url": "https://yourblog.com/about" |
| 985 | }, |
| 986 | "publisher": { |
| 987 | "@type": "Organization", |
| 988 | "name": "Blog Name", |
| 989 | "logo": { |
| 990 | "@type": "ImageObject", |
| 991 | "url": "https://yourblog.com/logo.png" |
| 992 | } |
| 993 | }, |
| 994 | "mainEntityOfPage": { |
| 995 | "@type": "WebPage", |
| 996 | "@id": "https://yourblog.com/ai-search-organic-traffic" |
| 997 | } |
| 998 | } |
| 999 | </script> |
| 1000 | </head> |
| 1001 | <body> |
| 1002 | <nav aria-label="Main navigation"> |
| 1003 | <!-- Navigation --> |
| 1004 | </nav> |
| 1005 | |
| 1006 | <article> |
| 1007 | <header> |
| 1008 | <h1>How Does AI Search Impact Organic Traffic in 2026?</h1> |
| 1009 | <time datetime="2026-02-18">February 18, 2026</time> |
| 1010 | </header> |
| 1011 | |
| 1012 | <section> |
| 1013 | <h2>What Is the Impact of AI Overviews on Click-Through Rates?</h2> |
| 1014 | <p>AIO organic CTR rebounded from 1.3% in December 2025 to about 2.4% |
| 1015 | in February 2026 (<a href="https://seerinteractive.com">Seer Interactive</a>, |
| 1016 | April 2026). Cited pages now earn 120% more clicks per impression than |
| 1017 | uncited pages.</p> |
| 1018 | |
| 1019 | <figure> |
| 1020 | <img src="https://cdn.pixabay.com/photo/.../image.jpg" |
| 1021 | alt="Marketing dashboard showing AI search CTR metrics" |
| 1022 | width="1200" height="630" loading="lazy"> |
| 1023 | <figcaption>Photo via Pixabay</figcaption> |
| 1024 | </figure> |
| 1025 | </section> |
| 1026 | |
| 1027 | <aside aria-label="Frequently Asked Questions"> |
| 1028 | <h2>Frequently Asked Questions</h2> |
| 1029 | <!-- FAQ content --> |
| 1030 | </aside> |
| 1031 | </article> |
| 1032 | |
| 1033 | <footer> |
| 1034 | <!-- Footer --> |
| 1035 | </footer> |
| 1036 | </body> |
| 1037 | </html> |
| 1038 | |
| 1039 | |
| 1040 | ### Image Embedding |
| 1041 | |
| 1042 | <figure> |
| 1043 | <img src="https://cdn.pixabay.com/photo/.../image.jpg" |
| 1044 | alt="Descriptive sentence including topic keywords naturally" |
| 1045 | width="1200" height="630" |
| 1046 | loading="lazy" |
| 1047 | decoding="async"> |
| 1048 | <figcaption>Photo via Pixabay</figcaption> |
| 1049 | </figure> |
| 1050 | |
| 1051 | |
| 1052 | ### Chart / SVG Embedding |
| 1053 | |
| 1054 | <figure> |
| 1055 | <svg viewBox="0 0 560 380" |
| 1056 | style="max-width: 100%; height: auto; font-family: 'Inter', system-ui, sans-serif" |
| 1057 | role="img" |
| 1058 | aria-label="Chart showing AIO organic CTR rebound from 1.3% to about 2.4%"> |
| 1059 | <title>AIO Organic CTR Rebound</title> |
| 1060 | <desc>Bar chart comparing the December 2025 AIO CTR floor to the February 2026 rebound</desc> |
| 1061 | <!-- SVG content with standard HTML attributes --> |
| 1062 | </svg> |
| 1063 | <figcaption>Source: Seer Interactive (Apr 2026)</figcaption> |
| 1064 | </figure> |
| 1065 | |
| 1066 | |
| 1067 | ### Inline JSON-LD Schema |
| 1068 | |
| 1069 | Place in `<head>` for BlogPosting: |
| 1070 | |
| 1071 | <script type="application/ld+json"> |
| 1072 | { |
| 1073 | "@context": "https://schema.org", |
| 1074 | "@type": "BlogPosting", |
| 1075 | "headline": "Title", |
| 1076 | "datePublished": "2026-02-18", |
| 1077 | "dateModified": "2026-02-18", |
| 1078 | "author": { "@type": "Person", "name": "Author" } |
| 1079 | } |
| 1080 | </script> |
| 1081 | |
| 1082 | |
| 1083 | Place in `<head>` for FAQPage only when visible Q&A exists. It is entity |
| 1084 | support for AI citation, not a Google rich result: |
| 1085 | |
| 1086 | <script type="application/ld+json"> |
| 1087 | { |
| 1088 | "@context": "https://schema.org", |
| 1089 | "@type": "FAQPage", |
| 1090 | "mainEntity": [ |
| 1091 | { |
| 1092 | "@type": "Question", |
| 1093 | "name": "What is the question?", |
| 1094 | "acceptedAnswer": { |
| 1095 | "@type": "Answer", |
| 1096 | "text": "The visible answer text with a specific statistic and source." |
| 1097 | } |
| 1098 | } |
| 1099 | ] |
| 1100 | } |
| 1101 | </script> |
| 1102 | |
| 1103 | |
| 1104 | ### Key Configuration Notes |
| 1105 | No framework dependency: works with any hosting |
| 1106 | AI crawlers can read static HTML without JS execution |
| 1107 | Manually manage OG/Twitter meta tags in `<head>` |
| 1108 | Use `loading="lazy"` and `decoding="async"` on images for performance |
| 1109 | Schema must be in HTML source, not injected via JavaScript |
| 1110 | Generate sitemap.xml manually or with a build script |
| 1111 | Use `<link rel="canonical" href="...">` to prevent duplicate content |
| 1112 | Place CSS in `<head>` (inline critical CSS for fast TTFB) |
| 1113 | |
| 1114 | |
| 1115 | |
| 1116 | ## Platform Selection Quick Reference |
| 1117 | |
| 1118 | | Priority | Criterion | Recommendation | |
| 1119 | |----------|-----------|---------------| |
| 1120 | | AI crawlers | JS execution required? | Use SSG/SSR (Next.js, Astro, Hugo, 11ty, Gatsby) | |
| 1121 | | Speed | TTFB < 200ms | Hugo (fastest builds), 11ty, Astro, static HTML | |
| 1122 | | MDX/React | Component-driven content | Next.js, Gatsby | |
| 1123 | | Simplicity | Minimal tooling | Hugo, Jekyll, 11ty, static HTML | |
| 1124 | | Non-technical users | Visual editor | WordPress, Ghost | |
| 1125 | | Headless CMS | API-first | Ghost (Content API), WordPress (REST API) | |
| 1126 | |
| 1127 | ### Universal Requirements (All Platforms) |
| 1128 | |
| 1129 | **Static or server-rendered HTML**: AI crawlers cannot execute JavaScript |
| 1130 | **TTFB under 200ms**: AI crawlers timeout at 3-5 seconds |
| 1131 | **Schema in HTML source**: not injected via client-side JS |
| 1132 | **robots.txt allowing AI crawlers**: GPTBot, ClaudeBot, PerplexityBot |
| 1133 | **Sitemap at /sitemap.xml**: helps all crawlers discover content |
| 1134 | **OG meta tags**: required for social sharing previews |
| 1135 | **dateModified in schema**: critical for freshness signals |
| 1136 |
Discussion
Alternatives
Browse more free Claude skills or everything in Development.