Start free

FAQPage schema for web extraction

A FAQPage schema captures a support or help page as structured data: the page title, its URL, a count of how many entries it holds, and a questions array where each item pairs the question text with its answer. Teams extract this to harvest scattered help-center content into a uniform Q&A dataset, feed verified answers into a support assistant or RAG index, audit answers across product versions, or compare how competitors phrase the same policy. Naming each field gives you typed records you can search, render, and validate, instead of a wall of accordion HTML you still have to pull apart by hand. FAQ pages are a strong fit for describing fields rather than writing CSS selectors, because no two help centers mark up their questions the same way. One site wraps each entry in a details and summary pair, another uses headings followed by paragraphs, a third renders the whole accordion with JavaScript only after the page loads. You describe what a question and an answer are once, and because every request runs through a real headless browser, the model reads the rendered Q&A pairs regardless of the underlying markup. When a page lists no answer for a stub question, that answer comes back as null instead of an invented sentence, so an empty value means the page genuinely had none rather than the extraction quietly guessing. The count field is derived from the questions actually found, which gives you a cheap integrity check: if count and the array length ever disagree in your pipeline, you know to look before you trust the record.


Fields in a FAQPage schema

The fields teams most often extract for a faqpage, what type each one is, and whether it is usually present.

Field Type Required Notes
questions { question: string, answer: string }[] yes The list of FAQ entries, each an object pairing the question text with its answer. Returning this typed as an array of objects preserves the question-to-answer mapping so you can index, render, or embed each pair directly, instead of getting one run-together block of text you must re-split and re-align yourself.
question string yes Inside each questions item, the question exactly as worded on the page, such as How do I reset my password. Captured verbatim so search and deduplication match real user phrasing, and so the field stays a reliable key when you join the same FAQ across product versions.
answer string optional Inside each questions item, the full answer text for that question. Returned as null when a question is listed with no answer yet, so a null tells you the page truly left it blank rather than the model inventing a plausible-sounding reply to fill the gap.
pageTitle string optional The title of the FAQ or help page itself, such as Billing FAQ or Frequently Asked Questions. Useful as a human-readable label when you store many FAQ pages together, and it returns null on pages that carry no distinct title rather than borrowing one from the first question.
url string optional The canonical URL of the FAQ page, returned as a typed string. Keeping the source URL on the record lets you trace each Q&A pair back to its origin, refresh it later, and cite it in a support assistant so answers stay verifiable instead of anonymous.
count number optional The number of question-and-answer entries found on the page, returned as a number so you can sort, threshold, or sum across many pages without parsing text. It acts as an integrity check against the questions array length, and returns null only when no FAQ section is present at all.
category string optional An optional grouping label the page assigns to its questions, such as Billing, Shipping, or Account. Returned as a string when the page organizes its FAQ into sections, and null when it presents a single flat list, letting you bucket answers without guessing a category that was never stated.

The schema

Copy this and send it with any URL.

{
  "questions": "{ question: string, answer: string }[]",
  "pageTitle": "string",
  "url": "string",
  "count": "number",
  "category": "string"
}

Example output

Validated JSON back, matching the schema.

{
  "questions": [
    {
      "question": "How do I reset my password?",
      "answer": "Open the sign-in page, choose Forgot password, and enter the email on your account. We send a reset link that stays valid for 30 minutes."
    },
    {
      "question": "Can I change my plan at any time?",
      "answer": "Yes. Upgrades take effect immediately and we prorate the difference; downgrades apply at the start of your next billing cycle."
    },
    {
      "question": "Do you offer refunds?",
      "answer": "We refund unused time on annual plans within 14 days of purchase. Monthly plans are not prorated on cancellation."
    },
    {
      "question": "Where can I download my invoices?",
      "answer": null
    }
  ],
  "pageTitle": "Billing and Account FAQ",
  "url": "https://en.wikipedia.org/wiki/FAQ",
  "count": 4,
  "category": "Billing"
}

Try this faqpage schema against a real page in the live demo, or read the docs to use it via the API.

FAQPage schema: FAQ

How does Extracto keep each answer attached to the right question?
You describe questions as a list of objects, each with a question and an answer, and Extracto renders the page in headless Chrome before passing the text to the model with your schema as a strict contract. The model reads the FAQ in document order and returns each question next to its own answer, so the pairing never drifts. Because the output is a typed array of objects rather than one block of text, you can index, embed, or render each pair directly, and the mapping holds even on pages that build their accordion entirely with JavaScript after load.
Why is count a number instead of text, and what is it good for?
Typing count as a number means you get 4 back rather than the string four, so you can sort pages by size, threshold out near-empty stubs, or sum entries across a whole help center without parsing words. It also doubles as an integrity check: if count and the length of the questions array ever disagree in your pipeline, that is a signal to inspect the record before trusting it. When a page has no FAQ section at all, count returns null rather than a guessed zero you could not tell apart from a real empty page.
What happens when a question on the page has no answer yet?
The answer field for that entry returns null instead of a sentence the model made up to look complete. That keeps your dataset honest: a null tells you the page genuinely listed the question without an answer, perhaps a placeholder the team has not filled in, so you can flag or backfill those entries deliberately. This behavior is enforced because the JSON is validated against your schema before it is returned, so missing values surface as null rather than as a confident but invented reply.
Can Extracto extract FAQ pages from any site, including protected ones?
It works on any public FAQ or help page, including JavaScript-rendered and anti-bot-protected ones, because every request runs through a real headless browser with a managed anti-bot bypass layer and proxies handled for you. Help centers sitting behind Cloudflare, DataDome, or PerimeterX are covered by that managed layer with no setup on your side. The exception is login-gated content that needs session cookies, such as a customer-only knowledge base, which is available on Enterprise. Respect each site's robots.txt and terms of service, and keep request volume modest.
Do I need CSS selectors to target the questions and answers?
No. You describe what a question and an answer are in your schema, and Extracto reads them from the rendered page no matter how that page is marked up. One FAQ might use details and summary elements, another headings with paragraphs, a third a JavaScript accordion, and the same schema handles all of them without selector tweaks. That is the difference from a selector-based scraper that breaks the moment a site changes its markup: you maintain a description of the data you want, not a brittle map of one site's HTML structure.