Question markup: making a question machine-readable as a question
Two schema types can carry a question and they are not alternatives. One says your site asked and your site answered. The other says a stranger asked and your readers answered. Choosing the wrong one is not a validation error, it is a false statement about who wrote your page.
The short answer
FAQPage and QAPage are not interchangeable, and who asked decides which one applies. FAQPage is for questions the publisher wrote and answered; QAPage is for a single user-submitted question with community answers, and it permits exactly one question per page. Using the wrong type is worse than using none.
Who asked decides the type
The whole decision comes down to authorship, and it takes one question to resolve. Did your organisation write both the question and the answer? That is FAQPage. Did a visitor ask the question, with answers arriving from other visitors and possibly one marked as accepted? That is QAPage.
The types are not near-synonyms with different names. A QAPage declares a public thread: one question, community answers, votes, an accepted answer that may or may not exist yet. Google treats it as user-generated content, which is a different category of trust from an answer your company publishes under its own name. Applying it to a support page you wrote yourself does not buy you a second eligibility, it misfiles the page.
Marketing FAQ, product FAQ, help centre article: FAQPage. Forum thread, product question widget, community board: QAPage.
What a QAPage looks like, since almost nobody writes one
FAQPage is everywhere and QAPage is rare, which is why the wrong one usually gets copied from the wrong example. Here is a complete thread, with the properties that carry the community semantics.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "QAPage",
"mainEntity": {
"@type": "Question",
"name": "Why does my sitemap list 200 URLs when a crawl finds 340?",
"text": "The sitemap is generated nightly from published
posts. A crawl of the same site keeps returning
about 140 more URLs than the sitemap contains.
Which number is wrong?",
"answerCount": 2,
"upvoteCount": 4,
"dateCreated": "2026-03-04T09:12:00+00:00",
"author": { "@type": "Person", "name": "priya-lt" },
"acceptedAnswer": {
"@type": "Answer",
"text": "Neither is wrong. A sitemap lists what you want
indexed; a crawler lists what it can reach.
The extra URLs are almost always tag and
pagination pages, which are reachable and
deliberately left out of the sitemap.",
"url": "https://example.com/forum/sitemap-count#a-8812",
"upvoteCount": 11,
"dateCreated": "2026-03-04T11:40:00+00:00",
"author": { "@type": "Person", "name": "marcus-r" }
},
"suggestedAnswer": [
{
"@type": "Answer",
"text": "Check for a trailing-slash duplicate first.
Serving both forms doubles the crawlable set
without changing the sitemap at all.",
"url": "https://example.com/forum/sitemap-count#a-8817",
"upvoteCount": 2,
"dateCreated": "2026-03-04T14:02:00+00:00",
"author": { "@type": "Person", "name": "dana92" }
}
]
}
}
</script>acceptedAnswer is the one the asker or a moderator marked as resolved. suggestedAnswer holds the rest, as an array. A live thread with no resolution is perfectly valid with only suggestedAnswer populated, which is worth knowing because it is the opposite of how FAQPage behaves: a FAQPage question with no accepted answer is broken, since your own site declining to answer its own question is not a state that means anything.
Three differences that break a copied implementation
People start from an FAQPage block and rename the type. These are the three places that approach falls apart.
mainEntityis one object, not an array. FAQPage takes a list of questions because a page can answer many. QAPage takes exactly one question, because the type describes a thread. A forum index listing forty threads is not a QAPage with forty questions, it is a list of pages that each are one.answerCountis required and has to be true. It states how many answers the page carries. Hardcoding it, or letting it drift as replies arrive, is a factual error in your markup rather than a missing optional field. Generate it from the same query that renders the answers.- Answers have authors. An answer written by a named person is the substance of the type. Votes and timestamps are recommended rather than required, but an answer with no author on a page you are declaring as community content is the tell that the type is wrong.
One more, and it comes up on every help centre that has both a written article and a comment thread: do not declare both types on the same page. Two competing statements about what the page is leaves a parser to pick, and it may not pick the one you wanted. The FAQPage side of this covers the markup for the common case in full.
Pairing the headings against the declaration
The interesting failure is not a malformed block, it is a mismatch: three question headings on the page, one of them in the markup, or markup describing a question the page no longer asks. Seeing that requires the outline and the structured data read together across every page.
This one needs the full crawl
This pairs your headings against your structured data, so it needs the full heading outline of a page and its schema read together rather than a single field.
The instant search on this site audits a single page, so rather than show you a verdict it cannot support, this guide sends you to the place the check actually runs.
What a declaration commits you to
A heading phrased as a question is a hint, and a hint that turns out to be unhelpful costs you nothing. Markup is an assertion, and assertions can be wrong. Four commitments come with it.
- The text exists on the page. Every question and every answer in the block has to be readable by a person visiting the URL. Not summarised, not richer in the JSON than in the HTML.
- The counts stay accurate. QAPage in particular asserts numbers that move: answers arrive, votes accumulate, a moderator accepts one. Markup that was true at deploy is a maintenance obligation, not a one-off task.
- The authorship claim is true. Declaring community answers means declaring that visitors wrote them. If your support team wrote them under a first-name handle, you have described your own editorial content as user-generated, which understates its authority rather than adding to it.
- The question actually gets answered. This one catches people out. Declaring a question commits the passage beneath it to being an answer, and a heading followed by three paragraphs of context that never lands is now a documented promise the page breaks. Writing a passage that stands alone is the other half of doing this properly.
Most question headings should carry no markup at all
There is a third option, and it is the right one more often than either type.
A blog post with two H2s phrased as questions is not an FAQ. A product page with one "Does it work offline?" heading is not a Q&A thread. Wrapping either in markup to collect a declaration produces a page claiming to be something it is not, and the page was working fine.
The test worth applying: is answering a set of questions the structure of this page, or does this page happen to contain a question? Only the first is a candidate. A parser reading a question heading followed by an answer already has a strong signal, so declining to declare costs you very little, and phrasing the heading well is where the unmarked version gets its value.
Why the wrong type is worse than no type
The rating carries a failure mode most markup checks do not have. A missing declaration is an omission: a parser infers the question and answer from your headings, and usually gets it right. A wrong declaration is a contradiction, and it competes with the page rather than describing it.
That asymmetry is what puts this above Refinement. The cost of the mistake is not a forgone nicety, it is having told a machine that your published support answer came from a stranger on the internet, or that a marketing page is a discussion thread. Structured data that disagrees with its page is the category Google reserves manual actions for, which makes it a different class of problem from an absent field.
It stays under Critical because a page with no question markup at all loses nothing that matters, and because the fix is one script tag rather than a rebuild. That is the same reasoning applied to every additive markup check on the audit page, with the wrong-type case explaining why it does not slide any lower.
Does this affect AI search? The declaration is a tiebreaker
Yes, but not as the mechanism people assume. A model does not need markup to notice that a heading ends in a question mark and a paragraph follows. It reads the page. The declaration does not create the question-and-answer pair, it removes the ambiguity about where the answer stops, which matters when the page is long and the answer is short.
Where it does something markup alone can do is attribution, and this is the part worth getting right. QAPage says an answer has an author and a vote count. FAQPage says the site is speaking in its own voice. A pipeline weighing how much to trust a passage can use that distinction, and if you have mislabelled your own expert content as community chatter you have handed it a reason to discount you. This is the rare case where wrong markup plausibly costs you more with an assistant than with a search engine.
What cannot be said honestly is how much any of it is weighted. No vendor documents its treatment of either type, and nobody publishes reliable figures on citation rates for structured data. The defensible position is that a correct declaration is cheap and a wrong one carries real downside, which is enough to decide what to do without inventing a number. Where it fits among the rest is set out in the AI search group.
Confirming the type matches the page
Parse first, since both types are still tied to features Google supports and the Rich Results Test therefore still reports them. It will tell you about a missing answerCount or an answer without text. It will not tell you the type is wrong, because a well-formed QAPage on a marketing page is syntactically perfect.
The check that catches the real error is one sentence long and has to be done by a person: read the block aloud as a claim. "A visitor asked this and other visitors answered it." If that is false, the type is wrong no matter what any validator says. Then confirm answerCount against the answers actually rendered, and re-run the crawl to see the pages where a question heading and a declaration still disagree, since that mismatch is what the check reports rather than absence.
Questions this check raises
- What is the difference between FAQPage and QAPage?
- FAQPage marks up questions you wrote and answered yourself, and a page can hold many. QAPage marks up one question asked by a user with answers from other people, and it is restricted to a single question per page with properties for accepted and suggested answers. Forums use the second; almost everyone else uses the first.
- Should every question heading be marked up?
- No, and most should not. A heading phrased as a question inside an article is part of the article, not an FAQ entry. Marking up every one of them turns a coherent page into a list of disconnected pairs and makes a claim about the document that is not true.
- What happens if I use the wrong type?
- The markup is either ignored or read as a claim your page does not support. QAPage on a publisher-written FAQ declares that a user asked the question and the community answered, which is false, and false structured data is the category most likely to attract a manual action.