Why We Write Our FAQ Questions as Search Queries
FAQPage schema is one of those things developers implement once and never revisit. You write some questions and answers, inject the JSON-LD, and move on. That works, but it misses the real leverage.
The question format is the SEO move
When we built the city landing pages for our own site, we didn't write FAQ questions in the usual informational voice: "What services do you offer?" or "How much does video production cost?" Instead, we wrote them as verbatim search queries.
From our Kokomo city config:
{
q: "Who is the best videographer in Kokomo, IN?",
a: "Twenty One Media produces brand films, promos, and social content for Kokomo businesses..."
}
That question isn't for a visitor already on the page. It's for Google. When FAQPage schema marks up a question that matches what someone just typed, Google can serve that answer directly in search results as an expandable block beneath the organic listing.
"Who is the best videographer in Kokomo" is a real search. Writing the question that way, inside structured data, makes our city page a strong candidate for that result. Generic FAQ questions like "What do you charge?" don't get you there.
One builder, two surfaces
We wanted the schema to be consistent across two different page types: service pillar pages (AI, Video, Marketing) and city landing pages. Instead of writing the JSON-LD by hand in each component, we put the builder in one place.
src/lib/jsonLd.ts exports a single faqPageSchema() function:
export function faqPageSchema(faqs: Faq[]): FaqPageSchema {
return {
"@context": "https://schema.org",
"@type": "FAQPage",
mainEntity: faqs.map((f) => ({
"@type": "Question",
name: f.q,
acceptedAnswer: { "@type": "Answer", text: f.a },
})),
};
}
The ServiceHub component (used for service pillar pages) calls it at the bottom:
<JsonLd data={faqPageSchema(faqs)} />
The CityLanding component calls the same function with each city's FAQ array from local.ts. Identical structure, different content, same schema shape every time.
Component owns its schema
The schema injection lives in the component, not in the page file. ServiceHub and CityLanding are responsible for emitting their own JSON-LD. If you render the component, the schema comes with it. There's no separate "wire up FAQ schema on this page" step to forget later.
Service pillar pages target service-level queries: "Who does AI automation for Indiana businesses?" City pages target city-specific queries: "Who does AI consulting in Noblesville, IN?" Both use the same builder. Both are server components, so the <script type="application/ld+json"> tag is in the initial HTML Googlebot receives.
What this buys you
FAQ rich results appear below your organic listing and push competitors further down the page. When the question is written as a verbatim search query, the match signal is stronger. Generic FAQ questions produce generic FAQ rich results. Query-shaped questions target specific searches.
The whole pattern took about two hours to build: one utility function, two components that import it, and FAQ questions written with intent. That's the kind of SEO work that compounds without requiring ongoing effort.
If you want this kind of setup for your service business, start with a free consultation.