Paywalled & Subscription Content
If your site has a paywall or subscription system, you must properly mark up gated content to avoid Google’s cloaking policies. schemaorg-kit provides helpers that make this easy.
Table of contents
- Google’s Policy
- For Articles
- For Web Pages
- Multiple Gated Sections
- Free Preview Pattern
- HTML Implementation
- Common Mistakes
Google’s Policy
Google’s subscription and paywalled content guidelines require:
- Structured data must match the visible content. If you show Google content that users can’t see without paying, it’s cloaking.
- Use
isAccessibleForFree: false+hasPartto tell Google which part of the page is behind the paywall. - Don’t block Googlebot with
robots.txtornoindex. Let Google crawl and index the page.
For Articles
import { createPaywalledArticle } from 'schemaorg-kit';
const article = createPaywalledArticle(
{
headline: 'The Hidden Cost of Low Interest Rates',
author: { '@type': 'Person', name: 'Finance Desk' },
datePublished: '2025-05-15',
image: 'https://financepost.example/interest-rates.jpg',
publisher: {
'@type': 'Organization',
name: 'Finance Post',
logo: { '@type': 'ImageObject', url: 'https://financepost.example/logo.png' },
},
},
{ cssSelector: '.article-body' } // CSS selector for the gated content
);
Output:
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "The Hidden Cost of Low Interest Rates",
"isAccessibleForFree": false,
"hasPart": [
{
"@type": "WebPageElement",
"isAccessibleForFree": false,
"cssSelector": ".article-body"
}
],
...
}
For Web Pages
import { createPaywalledWebPage } from 'schemaorg-kit';
const page = createPaywalledWebPage(
{
name: 'Member Dashboard',
url: 'https://app.example.com/dashboard',
description: 'Your personalized account dashboard.',
},
{ cssSelector: '#dashboard-content' }
);
Multiple Gated Sections
If multiple sections are behind the paywall, use createArticle directly and customize hasPart:
import { createArticle } from 'schemaorg-kit';
const article = createArticle({
headline: 'Premium Market Analysis',
author: { '@type': 'Person', name: 'Analyst' },
datePublished: '2025-06-01',
image: 'https://example.com/analysis.jpg',
isAccessibleForFree: false,
hasPart: [
{
'@type': 'WebPageElement',
isAccessibleForFree: false,
cssSelector: '.data-tables',
},
{
'@type': 'WebPageElement',
isAccessibleForFree: false,
cssSelector: '.chart-section',
},
{
'@type': 'WebPageElement',
isAccessibleForFree: false,
cssSelector: '.conclusions',
},
],
});
Free Preview Pattern
If some content is free (lead paragraph, abstract) but the rest is gated:
import { createArticle } from 'schemaorg-kit';
const article = createArticle({
headline: 'Exclusive: Inside the Fed's Next Move',
author: { '@type': 'Person', name: 'Reporter' },
datePublished: '2025-07-01',
image: 'https://example.com/fed.jpg',
// The article IS accessible for free (the preview part)
// Only the specific element is behind the paywall
isAccessibleForFree: false,
hasPart: [
{
'@type': 'WebPageElement',
isAccessibleForFree: false,
cssSelector: '.premium-content', // Only this section is gated
},
],
});
HTML Implementation
Your page must visually separate free vs. gated content with CSS classes that match your cssSelector:
<article>
<h1>The Hidden Cost of Low Interest Rates</h1>
<!-- Free preview — visible to all -->
<p class="article-intro">
Interest rates have stayed near historic lows for over a decade...
</p>
<!-- Gated content — matches cssSelector: ".article-body" -->
<div class="article-body">
<p>The full analysis reveals that...</p>
<!-- Paywall overlay should appear here for non-subscribers -->
</div>
</article>
Common Mistakes
Don’t use
isAccessibleForFree: falsewithouthasPart. WithouthasPart, Google doesn’t know which element is gated and may treat it as cloaking.
Don’t use
noindexon paywalled pages. This defeats the purpose — the page needs to be indexed for Google to apply the subscription content treatment.
Test with Google’s Rich Results Test after implementing. The tool shows whether your paywalled markup is recognized correctly.