How to implement a paywall for blog posts in Sanity CMS?

12 replies
Last updated: Apr 7, 2022
This might be the completely wrong way to go about this (looking for the right way to do it, please help) but let's say I've got a blog post schema/editor set up on Sanity and I want the output to be behind a paywall for the website visitor. Would the best way to go about this be to set up a boolean schema type on the blog schema for paid or not paid? And then in the website code, have the article behind authentication and all that jazz that checks if the user is paid user or just a normal user? Any and all advice (Preferably not too advanced in language) or any links to set me on the right path would be well loved and appreciated.
AI Update

You're on the right track! Your approach is actually a solid and common pattern for implementing paywalled content. Let me break down the recommended way to do this:

The Basic Approach (What You Described)

Yes, adding a boolean field to your blog post schema is exactly the right starting point:

{
  name: 'isPremium',
  title: 'Premium Content',
  type: 'boolean',
  description: 'Check this to put content behind paywall'
}

Then in your website code (like Next.js), you'd:

  1. Check if the user is authenticated and has an active subscription (using something like NextAuth.js + Stripe)
  2. Query the post and check the isPremium field
  3. Show full content to paid users, or just a preview/excerpt to free users

Making It Better: Content Preview Strategy

Instead of just hiding everything, consider these improvements:

Add an excerpt field to your schema so free users can see a teaser:

{
  name: 'excerpt',
  title: 'Preview Excerpt',
  type: 'text',
  description: 'Short preview shown to non-subscribers'
}

Use GROQ to conditionally fetch content in your Next.js getServerSideProps or Server Components:

// In your Next.js page
const query = `*[_type == "post" && slug.current == $slug][0]{
  title,
  excerpt,
  isPremium,
  ${userIsPaid ? 'content' : ''}
}`

This way, you're not even sending the full content to the client if the user isn't paid.

The Authentication Side

For the authentication/subscription checking part, you'd typically:

  1. Use an auth provider like NextAuth.js or Clerk to handle user authentication
  2. Use Stripe (or similar) for subscription management
  3. Check subscription status in your Next.js middleware or getServerSideProps/Server Components before rendering the page

Important Security Note

Make sure the authentication check happens server-side (in Next.js Server Components, getServerSideProps, or API routes), not just in client-side JavaScript. Otherwise, someone could inspect the page source or network requests and access the premium content anyway.

Starter Resources

While Sanity doesn't have a specific paywall starter, you can combine:

Your approach is fundamentally correct - Sanity handles the content modeling (with the boolean flag), and your frontend application handles the authentication and conditional rendering. Keep it simple to start, and you can always add more sophisticated features later!

Show original thread
12 replies
that’s not to say sanity content is inherently insecure in any way - there are a variety of access controls in place to make sure your query sources and API interactions are controlled. But it is at its core a platform meant for publishing data and I would advise something external to the studio for any sensitive information (like password strings, tokens, or financial transactions).
Thank you User - I'm not so much concerned about people bypassing stuff by various means (at this point in time), I'm more wondering how I should set up my data in Sanity so that I can say some articles are behind a paywall and other articles are not (In the code)?
for example I visit: website/blog/article-is-pay-only -- In sanity, in the content studio that I've created this post in, should I make a schema type that I can use as a data point in my coding to tell a person visiting they need to have a specific type of account or need to sign up to view the data? If the article's boolean type for the data point is true, run this code - if the information is false, run that code? Does that make sense?
Oh! That should be super easy (once you grasp queries and some basic node/js functions). Insert a boolean input in your article documents.
You could make a single groq query to grab all article documents and then render them according to the user’s auth state in your front end.
OR
You could make two groq queries and (say if you’re using nextjs) in your page where those article results are mapped - then (again react/nextjs) add a state function to check if the user is logged in or not. If they’re logged in, run the ‘view all articles’ query or by default run the ‘view free articles’ query then map (ie query the desired articles and then return article titles/slugs html as links) the results.

Then in each (nextjs) [slug] page for each article, I would add a second check to see if the user is authorized and/or the document free/premium boolean is set. And if the article should be behind that auth wall, the user is redirected to some prompt asking them to log in or sign up for a premium account and then redirect back home.
((and if you’d prefer graphql to groq this is supported as well, I’m just a groq fan within sanity))
groq has been amazing thus far and this answers my questions!! I will probably end up using versions of all that (you've given me ideas) Thank you! (And I'm using remix 🙂 )
Oh man, I’ve been meaning to play with that more for weeks, I just keep getting distracted. A couple dev friends have been telling me to spend some time with it. Do you feel it’s worth learning? (I’m a big fan of both next and sveltekit too and love tinkering with all the things)
user U
As far as Next, Gatsby and Remix goes - I'm having the most fun with Remix and I'm not nearly as confused as I am trying to figure out some things with Next and Gatsby. It's been really rewarding using it, especially as someone who did most his coding back in the mid 00s and then focused on CSS for a decade! It's been really straightforward and awesome!
I’ve been suggesting sveltekit for some of my CSS dev friends lately, as an alternative to 11ty for the ones that aren’t fond of jsx. I’ll take some time to get going with Remix then, thank you!
Hi, we're also looking at implementing a similar scenario like this, where documents must be accessible to certain users based on different criteria. Our backend is .NET based, and I think we can make all that work.
I was just wondering about the end user editing experience... Studio has very rich features for working with drafts and publishing, but we have to implement editing in our own front end, which will be a simplified version of Studio. The way that Studio works with keeping history, making drafts, etc., is that specific to Studio or is it more of a platform feature in the Content Lake?
user U
I would just suggest for a non-studio solution that you do what you can to keep API interactions to a minimum, as outside of the studio these will count against your quota. But it’s totally doable.
I haven’t tinkered with this yet myself, but you might be able to mix the drafts feature with your own fe forms by
prepending your _id values with
drafts.
OK, thanks for the guidance, will definitely pursue this.

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?