Paywall SEO: Getting Subscriber-Only Content Indexed Safely

Paywall SEO: Getting Subscriber-Only Content Indexed Safely

If a page shows Googlebot the full text of an article and shows a visitor a locked paragraph and a subscribe button, that sounds exactly like the definition of cloaking. It is not, provided you tell Google about the split with structured data instead of leaving it to guess. Google has a specific schema.org mechanism for this, built around two properties, isAccessibleForFree and hasPart with cssSelector, and it exists precisely so publishers can be indexed for the full value of an article without giving that article away for free to every reader.

This post covers why a naive paywall looks like a policy violation, how the markup actually works, the difference between a metered and a hard paywall in how you annotate them, what a search result actually shows for gated content, and the implementation mistakes that quietly break the whole setup after a redesign.

Why a Paywall Looks Like Cloaking

Cloaking, in Google's definition, is showing search engines different content than you show human visitors, usually keyed off user-agent or IP address, to rank for content the visitor never actually gets. The intent is deception, and the mechanism is differential serving based on who is asking.

A subscription site that shows the full article to a logged-in subscriber and a truncated preview to an anonymous visitor is not doing that, as long as it does not also serve a third, different version to Googlebot. The crawl should see the same underlying HTML a logged-out human sees: the full text present in the response, with a client-side or presentation-level mechanism, a blur, a fade, a hard cut after a few paragraphs, controlling what actually renders as readable for someone without a session. What makes this legitimate rather than deceptive is that you are not hiding the gating from anyone, including Google. You declare it explicitly in the page's own structured data, so a ranking system can tell the difference between a page that is short because the writer had nothing more to say and one that is short in search because a business model, not the content, ends there.

The failure mode publishers actually fall into is not looking like they cloak. It is the opposite: a CMS that strips the paywalled text out of the server response entirely for any session it treats as unauthenticated, including Googlebot's, because Googlebot carries no login cookie. If that happens, no markup saves you, because the crawler never receives the paragraphs in the first place. Get the delivery model right before worrying about the annotation.

The isAccessibleForFree and cssSelector Properties

The paywalled content markup lives on the Article or NewsArticle structured data you likely already have for headline and author eligibility. Two additions turn it into a paywall declaration.

At the top level, isAccessibleForFree is set to false whenever any part of the piece requires a subscription, and true when the whole thing is free. This flag alone tells Google not to treat the shorter, gated version a logged-out crawl might otherwise assemble as the whole story.

When only part of the article is gated, you add a hasPart array. Each entry describes one gated region: its type is typically WebPageElement, its own isAccessibleForFree is false, and its cssSelector is the exact CSS selector matching the DOM element that contains the subscriber-only text on the rendered page. If your article body sits in a container classed "article-body" and the paywalled portion is a nested element classed "subscriber-content", the selector needs to point at that specific nested element, not the whole body, or you are misdeclaring how much of the piece is actually gated.

Two things matter and are easy to get wrong. The selector has to match the live page's actual markup, character for character, not the markup from the day a developer wrote the template. And the full text of the gated section still has to be present in the HTML a crawl receives; cssSelector tells Google which part is subscriber-only, it does not let Google discover text that was never delivered to it.

Metered, Lead-In, and Hard Paywalls

The three common shapes annotate the same way in principle but differ in what you mark as gated, and in how closely the reader-facing experience needs to track the declaration over time.

A metered paywall lets a visitor read a set number of full articles, tracked by cookie or account, before gating kicks in. Because whether a given visitor is gated depends on a counter they carry with them rather than on the article itself, isAccessibleForFree should generally reflect the article's status for a fresh, cookie-less visitor: if a brand-new anonymous session can read it in full, mark it accessible and let the meter live as a client-side layer on top, rather than a property of the document.

A lead-in or freemium paywall gives every visitor the same fixed preview, typically the first paragraph or two, and gates everything after that permanently, regardless of how many articles that visitor has read elsewhere on the site. This is the cleanest case for hasPart and cssSelector: the free lead-in is one DOM region, the gated remainder a separate, clearly bounded one, and the selector for the gated portion does not change per visitor, only per template.

A hard paywall shows nothing of the body to anyone without an active subscription. Here isAccessibleForFree on the article itself is simply false, with no hasPart breakdown needed, because the entire body is the gated region.

The history explains why "flexible" is the operative word in how Google treats this now. Google used to run a program called First Click Free, requiring participating news publishers to let anyone reach a full article from a search result a handful of times per day, in exchange for full indexing. Google retired that requirement in 2017 and replaced it with what it called flexible sampling: publishers could set their own metering strategy, including giving away zero free articles, as long as the structured data correctly described what was gated. The tradeoff moved from "give away some reads to be indexed" to "describe your paywall accurately to be indexed," a materially better deal for subscription businesses.

What a Search Result Actually Shows

Marking content isAccessibleForFree false does not mean Google refuses to index it, and it does not mean Google misrepresents the page to searchers as free when it is not. Two separate things happen, and conflating them is the source of most confusion about this feature.

The first is ranking and relevance: Google's systems read the full text, including the gated portion, when deciding what the page is about and how well it answers a query. That is the entire point, it lets a publisher be found and ranked on the strength of content most visitors cannot read for free, rather than only on the thin preview.

The second is what the visitor experiences after clicking. Nothing about the structured data changes that. A non-subscriber who clicks through from a search result hits exactly the same paywall they would hit by typing the URL directly, because the markup does not unlock anything, it only informs Google's understanding of the page. On surfaces where subscription status is a relevant signal, such as Google News and Discover for eligible publishers, a lock icon or subscription indicator can appear on the result, which reduces low-value clicks from users who were never going to convert.

The snippet text itself typically still gets pulled from the meta description or early visible content, since a snippet promising content a reader cannot see is a poor experience regardless of what the ranking system knows. None of this requires anything beyond describing the paywall honestly; Google's systems handle the separation between what they understood the page to be about and what they show a given searcher on their own.

Implementation Walkthrough

Start by identifying the actual DOM boundary of the gated content in the rendered page, not in a design mockup. Open the page's source as an anonymous visitor would receive it and find the exact container, div, section, or set of paragraphs, that holds the subscriber-only text.

Add or extend the Article structured data with isAccessibleForFree and, if only part of the piece is gated, a hasPart entry whose cssSelector matches that container precisely. Keep the selector as specific and stable as reasonably possible; a generic class name reused elsewhere on the page for unrelated content makes the declaration ambiguous.

Confirm, separately from the markup, that the server sends the full article text in the initial HTML response regardless of session state. If the front end injects gated paragraphs only after a client-side authentication check resolves, an unauthenticated crawl may receive nothing to index at all, no matter how correct the schema is. Gating belongs in the presentation layer, CSS that visually truncates or blurs the container, or an overlay sitting on top of it, not in whether the text exists in the response body.

Keep the visible gating behavior and the declared markup honest relative to each other on an ongoing basis. If a redesign changes the class name on the gated container and nobody updates the cssSelector, the declaration silently stops matching anything, and Google is left to infer the paywall boundary itself again.

  • Identify the exact gated DOM element in the anonymous, server-rendered HTML
  • Add isAccessibleForFree (and hasPart + cssSelector for partial gating)
  • Verify the server still sends the full text regardless of session state
  • Recheck the selector after every template or redesign change

Testing That the Markup Actually Works

Run the page through a structured data testing tool to confirm the JSON-LD parses without errors and that the cssSelector values are present as strings; a typo in the property name can fail silently rather than throwing an obvious error.

Use URL Inspection in Search Console, or an equivalent fetch-and-render check, to see the HTML Google actually retrieved, and confirm the gated paragraphs are present in that fetched source, not just in what your own browser shows while logged in as a test subscriber. These are frequently different, and the gap between them is exactly where indexing breaks.

Re-run both checks after any front-end redesign that touches the article template, not only after the paywall implementation first ships. Selector drift from unrelated CSS refactors is the leading cause of paywall markup quietly going stale months after launch.

Edge Cases Worth Planning For

Content that starts free and moves behind an archive paywall after some window, common in trade publications and some news sites, needs a defined workflow for updating the markup at the moment the access model changes, not a one-time setup treated as permanent.

Sites running different models in different sections, some articles free forever and others gated, should treat the markup per article rather than assuming a site-wide default, since a shared template applied blindly will misdeclare whichever category is the exception.

Watch for CMS templates where a "subscribe to continue" prompt and the real article body occupy the same DOM position depending on session state, rather than the prompt sitting as an overlay on top of body text still present underneath. If the template swaps the entire node rather than layering a visual treatment over existing text, an anonymous crawl session receives the prompt instead of the article, and no amount of correct cssSelector syntax recovers content that was never delivered.

Syndicated or partner content distributed under someone else's paywall raises canonicalization and licensing questions beyond this markup, and those are typically resolved per agreement rather than through a generic technical fix.

Frequently asked questions

Is paywalled content structured data a form of cloaking?

No, as long as the underlying HTML Googlebot receives matches what an anonymous human visitor's browser also receives. Cloaking means serving a different version of the page to the crawler; paywall markup is a declaration added to one shared version, telling Google which part is gated instead of hiding that fact.

Do I need a hasPart entry for every paragraph that is gated?

No. A single hasPart entry with a cssSelector targeting the container that wraps all the gated paragraphs is enough in most templates. You only need multiple entries if the gated content lives in genuinely separate, non-contiguous DOM regions on the same page.

Will marking an article isAccessibleForFree false hurt its rankings?

There is no inherent penalty for accurately declaring a paywall; the markup exists so the full text can still inform ranking. What can hurt visibility is applying the flag to content that is not actually gated, or letting the declared selector drift out of sync with what the page really shows.

What happened to First Click Free?

Google retired the First Click Free program, which required a set number of free full-article reads per day, in 2017. It was replaced by flexible sampling, which lets publishers choose their own metering strategy, including no free reads at all, as long as the paywall is described accurately in structured data.

Does this markup work outside of Google News?

The isAccessibleForFree and hasPart properties are general schema.org Article properties and are not limited to News-eligible publishers. Some visual treatments, like a lock badge on a Google News or Discover surface, are limited to publishers eligible for those specific surfaces, but the underlying indexing behavior applies more broadly.

Updated: October 17, 2026

All articles