SEO July 21, 2026 6 min read Updated July 29, 2026

Structured data in Webflow: Article, FAQ, Product and Breadcrumb JSON-LD

Webflow won't generate schema markup for you. Copy-ready JSON-LD for the four types worth having, bound to CMS fields — and the markup that gets sites penalised.

On this page

What structured data does and doesn't do

Structured data is machine-readable description of what a page contains. It doesn't rank you higher — Google has been consistent on this — but it makes you eligible for rich results: star ratings, FAQ accordions, breadcrumb trails, article dates and images in the search listing.

The value is click-through, not position. A result occupying more vertical space with a rating and a thumbnail earns more clicks than a plain blue link at the same position. That's the whole benefit, and it's a real one.

Webflow generates none of this. You add it as custom code, and the useful part is binding it to CMS fields so it stays correct as content changes.

Where to put it

Three options, in order of preference:

Collection page custom code (Page Settings → Custom Code → Inside <head>) for anything CMS-driven. This is where you can insert field values with the + Add Field picker, which is what makes the whole thing maintainable.

Static page custom code for one-off pages — homepage Organization markup, a pricing page's Product markup.

Site-wide custom code for Organization and WebSite only. Never put page-specific schema here; you'll describe every page as the same thing.

JSON-LD in a <script> tag is Google's recommended format and by far the easiest to maintain. Ignore guides recommending microdata attributes scattered through your markup — you'll be unpicking them for years.

Article

For blog posts. Bind the fields with Webflow's field picker rather than typing values.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "POST TITLE FIELD",
  "description": "POST EXCERPT FIELD",
  "image": "POST FEATURED IMAGE FIELD",
  "datePublished": "PUBLISHED DATE FIELD",
  "dateModified": "UPDATED DATE FIELD",
  "author": {
    "@type": "Person",
    "name": "AUTHOR NAME FIELD"
  },
  "publisher": {
    "@type": "Organization",
    "name": "Your Company",
    "logo": {
      "@type": "ImageObject",
      "url": "https://yoursite.com/logo.png"
    }
  },
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://yoursite.com/blog/POST SLUG FIELD"
  }
}
</script>

Two things that break this in practice:

Date format. Schema wants ISO 8601 (2026-07-21). Webflow's date fields output according to the format you pick in the field picker — choose one that produces YYYY-MM-DD, not "July 21, 2026". A malformed date invalidates the whole block.

Quotes in the title. A post titled The "right" way to do X will break the JSON when inserted raw, because the quote closes the string early. Either avoid straight quotes in titles, or use curly quotes, which are safe.

FAQPage

The one with the biggest visible payoff and the biggest downside risk.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "How long does setup take?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Most teams are live in under an hour."
      }
    },
    {
      "@type": "Question",
      "name": "Do I need a paid plan?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "No. The free tier covers a single site."
      }
    }
  ]
}
</script>

The rule that matters: the questions and answers must be visible on the page. Marking up FAQs that don't appear in the content, or that are hidden behind a toggle nobody can open, is a structured data violation and a manual action risk. Google has also narrowed FAQ rich result eligibility over time, so treat visible rich results as a bonus rather than the plan.

If your FAQs live in a CMS Collection, generate the array by putting the <script> opening tag before a Collection list, the object inside it, and the closing tag after — the classic trick being to render each item with a trailing comma and accept the trailing-comma-on-last-item problem, which some parsers tolerate and validators flag. Cleaner: keep FAQ schema on static pages where you control the list, and skip it for CMS-driven FAQs unless you're willing to generate it properly.

Product

For pricing and product pages. Only mark up what's genuinely on the page.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "PRODUCT NAME FIELD",
  "description": "PRODUCT DESCRIPTION FIELD",
  "image": "PRODUCT IMAGE FIELD",
  "brand": { "@type": "Brand", "name": "Your Company" },
  "offers": {
    "@type": "Offer",
    "price": "29.00",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock",
    "url": "https://yoursite.com/products/PRODUCT SLUG"
  }
}
</script>

Do not invent aggregateRating. Review stars are the most tempting rich result and the most policed. The rating must correspond to reviews actually displayed on that page. Fabricated ratings are exactly what manual actions exist for, and the recovery process is far more expensive than the clicks you'd gain.

Prices must match what's on the page. If the page says $29/month and the schema says 29.00 USD with no period, you're describing a one-off purchase — use priceSpecification for recurring pricing.

The quiet winner: low effort, low risk, and it changes the URL line in search results into a readable path.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://yoursite.com/" },
    { "@type": "ListItem", "position": 2, "name": "Blog", "item": "https://yoursite.com/blog" },
    { "@type": "ListItem", "position": 3, "name": "POST TITLE", "item": "https://yoursite.com/blog/POST SLUG" }
  ]
}
</script>

Two rules: the trail must match visible on-page breadcrumbs, and position must start at 1 and increment without gaps.

Organization, once, site-wide

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "Your Company",
  "url": "https://yoursite.com",
  "logo": "https://yoursite.com/logo.png",
  "sameAs": [
    "https://twitter.com/yourhandle",
    "https://www.linkedin.com/company/yourcompany"
  ]
}
</script>

sameAs is how you connect the site to your verified profiles. It's cheap and it helps entity resolution.

Validate, then check again in a month

Two tools, and they answer different questions:

Schema Markup Validator — is the syntax valid?

Google Rich Results Test — is it eligible for a rich result?

A block can pass the first and fail the second, usually because a required property is missing for the specific rich result type.

Then watch Search Console → Enhancements. That's where you find out that a CMS field went empty on forty items and every one of those pages now has invalid markup — the failure mode nobody catches by testing one page after launch.

What I'd skip

Not everything with a schema type is worth marking up.

HowTo — Google has substantially reduced its rich result presence. Speakable — narrow support, minimal payoff. Deeply nested everything — describing your author's author's employer's address adds bytes and complexity for no observable benefit.

Article, BreadcrumbList, Product where you sell, Organization once, and FAQ only where the content genuinely exists on the page. That covers what actually shows up in results, and it's maintainable by whoever inherits the site.

Share

Our Products

We don’t just build apps; we create solutions that transform how you use Webflow. Whether you’re looking to streamline workflows, add advanced functionality, or scale your business, we’ve got you covered.

All apps