How to Add FAQ Schema (FAQPage) — WordPress and Plain HTML
FAQPage schema format, Google's usage policy, two ways to apply it (WordPress and direct HTML), common mistakes, and how to validate.
TL;DR
FAQPage schema is markup that explicitly tells search engines and AI what your frequently asked questions are and how you officially answer them. AI search (ChatGPT, Gemini, Google AI Overview) cites this format more than almost any other, which makes the ROI high.
1. Where FAQ schema shows up
Traditional Google rich snippets (the expandable Q&A box in search results) have shrunk for general sites since the 2023 policy change. But the surfaces have actually expanded.
- Google AI Overview — prioritizes FAQ-marked pages when generating answers
- ChatGPT / Perplexity / Claude — use FAQPage as structured context in web search modes
- Voice search and smart speakers — Q&A format maps cleanly to spoken answers
- Site-level SEO signal — clearly communicates page topic and scope
Plenty of sites drop FAQ schema after seeing the rich-snippet drop. In the AI search era, it's actually become more important than before.
2. Google's policy: eligibility
To get FAQPage schema properly recognized:
! FAQPage policy essentials
- The answer has to be visible on the page — users must actually be able to read it. If it's only in the markup and not in the body, Google treats it as spam.
- It must be an official answer — user comments and forum posts don't qualify. Use
QAPagefor those. - No promotional content — "How does this product make my life better?" and similar self-promo Q&A violate policy.
- No hate, violent, or sexual content
- No duplicates — don't mark up the same Q&A on multiple pages.
3. JSON-LD format
Here's the simplest form.
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "What's your refund policy?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Within 7 days of purchase, we offer a full refund regardless of whether the item has been used."
}
},
{
"@type": "Question",
"name": "How long does shipping take?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Orders ship within 2–3 business days after purchase."
}
}
]
}
It's just @type: "FAQPage" with an array of Question objects in mainEntity. Add as many as you need (5–15 is the typical sweet spot).
4. Application A — plain HTML site
Drop the <script type="application/ld+json"> block into <head> or right before </body>.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Shipping and Refund Info</title>
</head>
<body>
<h1>Frequently Asked Questions</h1>
<h2>What's your refund policy?</h2>
<p>Within 7 days of purchase, we offer a full refund regardless of whether the item has been used.</p>
<h2>How long does shipping take?</h2>
<p>Orders ship within 2–3 business days after purchase.</p>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{ "@type": "Question", "name": "What's your refund policy?",
"acceptedAnswer": { "@type": "Answer", "text": "Within 7 days of purchase, we offer a full refund regardless of whether the item has been used." }},
{ "@type": "Question", "name": "How long does shipping take?",
"acceptedAnswer": { "@type": "Answer", "text": "Orders ship within 2–3 business days after purchase." }}
]
}
</script>
</body>
</html>
The key — the question/answer text in the HTML body and in the JSON-LD must match. It's fine if the body answer is longer and the markup is the shortened version, but never put an answer in markup that isn't on the page.
5. Application B — WordPress
Three approaches. Accuracy increases as you go down.
B-1. Yoast SEO / Rank Math plugin
Add an "FAQ" block in the Gutenberg editor and FAQPage JSON-LD gets injected automatically. Easiest, but with the least control over output. Behavior gets inconsistent when answers are long or contain HTML.
B-2. Schema-dedicated plugin
Tools like "Schema & Structured Data for WP & AMP" let you manage FAQPage alongside other types. Watch out for the plugin double-outputting Organization or WebSite alongside what you already have.
B-3. Add code directly (most accurate)
Hook into functions.php or write the <script type="application/ld+json"> block directly into your page template. 100% control over output.
add_action('wp_head', function() {
if (!is_page('faq')) return;
$faqs = [
['q' => "What's your refund policy?", 'a' => 'Within 7 days of purchase...'],
['q' => 'How long does shipping take?', 'a' => '2–3 business days...'],
];
$main = array_map(fn($f) => [
'@type' => 'Question', 'name' => $f['q'],
'acceptedAnswer' => ['@type' => 'Answer', 'text' => $f['a']]
], $faqs);
$jsonld = json_encode([
'@context' => 'https://schema.org', '@type' => 'FAQPage',
'mainEntity' => $main
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
echo '<script type="application/ld+json">' . $jsonld . '</script>';
});
6. Validation
Once you ship, validate with two tools.
- Rich Results Test — checks whether Google recognizes it and surfaces any errors
- Schema Markup Validator — strictly checks compliance with the schema.org spec
If Rich Results Test detects "FAQs," you're good.
7. Five common mistakes
- Marking up answers that aren't on the page — the most common reason for a penalty
- Reusing the same answer across multiple pages — Google may ignore them all
- Promotional or self-praising Q&A — "Why is our product the best?" and the like
- Advertising links inside answer.text — anchor tags meant to funnel traffic violate policy
- Fewer than 5 Q&A items — too few and it may not be worth a FAQPage rating
Build it yourself
The Schema:LAB form builder makes FAQPage accurate. Type in your questions and answers, and you get JSON-LD instantly — paste and ship.
Type your questions and answers, and we'll output schema.org-compliant FAQPage JSON-LD instantly. (Included in the Free plan.)
→ Build FAQPage with a formPaste a URL and we show which structured data you currently have, and if FAQPage is missing, it shows up as a recommended addition.
→ Diagnose whether your site is missing FAQ schema