Introduction to Production-Ready Paywall Strategies

Getting a paywall to show up is one thing. Getting it to perform reliably, securely, and efficiently in a live production environment is an entirely different challenge.

This tutorial — Part 3 of the series — builds on the foundational concepts introduced in earlier installments by shifting focus to the practices that separate a polished, production-grade paywall from a basic prototype. The topics covered here are not just nice-to-haves; they are the difference between a paywall that converts users predictably and one that introduces revenue-impacting bugs at the worst possible moment.

RevenueCat provides a rich set of guides and best practices organized under its Playbooks documentation. As the official overview states, Playbooks are "step-by-step guides that walk you through implementing specific solutions using RevenueCat" and each one includes "detailed implementation instructions, subscription configurations in our Dashboard, [and] best practices and recommendations." Source

In this tutorial, you will learn how to:

  • Configure and display a Hard Paywall for maximum conversion without harming user experience.
  • Secure your server-side integration using webhook authorization.
  • Run end-to-end sandbox testing before going live.
  • Leverage the RevenueCat MCP tool for advanced paywall management in production.
  • Monitor and iterate on paywall performance without disrupting live users.

Before proceeding, ensure you have already completed the RevenueCat onboarding checklist: created your account, created a project, connected a store, installed the SDK, configured the SDK, and configured your products. Source


Hard Paywall Configuration and Display Optimization

Understanding the Hard Paywall Strategy

A Hard Paywall is one of the most direct monetization strategies available: users must complete a purchase before they can access specific content or features. There is no free tier and no trial to exhaust — the paywall is the gateway.

According to RevenueCat's Hard Paywalls playbook, this model is well-suited for apps that:

  • Provide high-value content or functionality
  • Operate with high unit economics (such as AI-driven features with significant per-user costs)
  • Have a clear value proposition
  • Target an audience with a high willingness to pay

Source

The directness of the hard paywall is its strength, but it also means that misconfiguration has an outsized impact. An incorrectly configured entitlement or a paywall that fails to appear on first launch can result in users leaving before they ever see your value proposition.

Step 1: Configure a Single-Tier Entitlement

RevenueCat Entitlements represent a level of access, features, or content that a user is "entitled" to. They are scoped to a project and are typically unlocked after a user purchases a product. Source

For hard paywalls, the recommended approach is deliberate and simple. Because a hard paywall blocks the main feature access of the app, RevenueCat recommends "creating a single-tier access level or entitlement that grants access to all features of the application." Source

Why this matters in production: Having a single, well-named entitlement (e.g., pro_access or full_access) reduces the chance of logic errors in your app code when checking whether a user should see the paywall or be passed through to the main experience. Multi-tier entitlement setups introduce branching logic that can be difficult to reason about at scale.

Action: In the RevenueCat dashboard, navigate to your project, open Entitlements, and create a single entitlement that maps to all of your subscription and one-time purchase products.

Step 2: Configure Your Products

Products are the individual SKUs that users actually purchase from the stores (Apple, Google, Stripe, etc.). Source

Ensure each product SKU is:

  1. Created and approved in the respective store (App Store Connect, Google Play Console, etc.).
  2. Added to your RevenueCat project under Products.
  3. Attached to the entitlement you created in Step 1.

Step 3: Adapt Your Implementation to the Paywall Template

RevenueCat's hard paywall guide notes that implementation details can vary based on the type of paywall template being used. Source

Regardless of template, the core production concern is display timing and reliability. A hard paywall must appear:

  • On first launch, before any restricted content is accessible.
  • After session restore — if a user was previously a subscriber and their subscription has lapsed, the paywall must re-appear correctly.
  • Without flicker — avoid momentarily displaying restricted content before the entitlement check completes. Always await the result of getCustomerInfo() before rendering your main content.
// Swift example: Gate content behind an entitlement check
Purchases.shared.getCustomerInfo { (customerInfo, error) in
    if customerInfo?.entitlements["full_access"]?.isActive == true {
        // Show main app content
        showMainContent()
    } else {
        // Show hard paywall
        showPaywall()
    }
}

Production tip: If your SDK fetch is slow or returns an error, default to showing the paywall rather than the main content. Defaulting to access-denied on error is the safer behavior for a hard paywall strategy.

Refer to the Hard Paywalls playbook for template-specific display instructions.


Webhook Security and Authorization Best Practices

Why Webhooks Matter in Production

RevenueCat webhooks allow your backend to react to subscription lifecycle events in real time. With webhooks integrated, you can:

  • Maintain an up-to-date record of subscriptions and purchases in your own backend
  • Trigger automations and workflows based on the subscription lifecycle
  • Remind subscribers of the benefits of your app when they decide to unsubscribe, or notify them when there are billing issues

Source

Note: Webhooks are available on RevenueCat's Pro plan. If you are on a legacy plan without webhook access, refer to RevenueCat's pricing page to migrate. Source

Registering Your Webhook URL

To set up a webhook in the RevenueCat dashboard: Source

  1. Navigate to your project and find the Integrations card in the left menu. Choose Webhooks.
  2. Choose Add new configuration.
  3. Name the new Webhook integration. You can set up multiple webhook URLs — the name helps differentiate them.
  4. Enter the HTTPS URL of the endpoint that you want to receive your webhooks.
  5. (Optional) Set an authorization header that will be sent with each POST request.
  6. Select whether to send events for production purchases, sandbox purchases, or both.
  7. Select if the webhook events should be sent only for one app or for all apps of the project.
  8. (Optional) Filter the kinds of events that should be sent to the webhook URL.

Implementing Webhook Authorization

One of the most overlooked production requirements is securing your webhook endpoint. Without authorization, any actor who discovers your webhook URL can send forged events to your server.

RevenueCat supports setting an authorization header that will be sent with every POST request to your webhook endpoint. Source On your server, validate this header on every incoming request before processing the event payload.

Here is a minimal example in Node.js:

// Express.js webhook handler with authorization check
app.post('/webhooks/revenuecat', (req, res) => {
  const authHeader = req.headers['authorization'];
  const expectedToken = process.env.REVENUECAT_WEBHOOK_SECRET;

  if (!authHeader || authHeader !== `Bearer ${expectedToken}`) {
    console.warn('Unauthorized webhook request received');
    return res.status(401).send('Unauthorized');
  }

  const event = req.body;
  console.log(`Received event: ${event.event.type} for app user ID: ${event.event.app_user_id}`);

  // Process the event...
  res.status(200).send('OK');
});

Store your webhook secret in an environment variable — never hardcode it.

Understanding RevenueCat's Single Environment Model

A critical detail that trips up many developers during production configuration: RevenueCat does not have separate sandbox and production environments at the infrastructure level. The transaction type embedded in the event payload determines whether it is a sandbox or production event. Source

When configuring your webhook, you explicitly choose whether to receive production events, sandbox events, or both. This means you can — and should — use a single webhook endpoint that branches internally based on the environment field in the event payload, or configure two separate webhook URLs for cleaner separation.

// Branching based on environment in the event payload
const environment = event.event.environment; // "SANDBOX" or "PRODUCTION"

if (environment === 'SANDBOX') {
  // Log or process differently for test events
  console.log('Sandbox event — skipping fulfillment');
  return res.status(200).send('OK');
}

// Process production event
await fulfillSubscription(event.event.app_user_id, event.event.product_id);

Sandbox Testing and Pre-Launch Validation

Why Sandbox Testing Is Non-Negotiable

Deploying paywall changes to live users without prior validation is a significant risk. A misconfigured entitlement, a broken webhook handler, or a missing product mapping can silently prevent users from completing purchases — or worse, allow users through without a valid purchase.

RevenueCat's sandbox environment lets you simulate real purchase flows using test accounts, giving you confidence that your implementation is correct before any real money changes hands. Source

Triggering Test Webhook Events from the Dashboard

One of the most useful tools for validating your webhook server is RevenueCat's ability to issue test webhook events directly from the dashboard. Source This lets you:

  • Confirm your endpoint is reachable and responding with a 200 status.
  • Validate that your authorization check is working correctly.
  • Test your event-handling logic for specific event types (e.g., INITIAL_PURCHASE, RENEWAL, CANCELLATION) without needing to go through an actual purchase flow.

How to trigger a test event:

  1. In the RevenueCat dashboard, navigate to Integrations → Webhooks.
  2. Open the webhook configuration you want to test.
  3. Use the Send Test option to dispatch a test event to your endpoint.
  4. Inspect your server logs to confirm receipt and correct processing.

Validating End-to-End Paywall Behavior

Beyond webhook testing, you should validate the complete purchase flow using sandbox accounts:

Test Scenario What to Validate
First-time purchase Entitlement is unlocked, paywall dismisses, main content appears
Subscription renewal Renewal webhook fires, entitlement remains active
Subscription cancellation Cancellation webhook fires, entitlement revokes at period end
Lapsed subscription on re-launch Paywall re-appears correctly, previous entitlement not granted
Restore purchases Restored entitlement is correctly detected via getCustomerInfo()

Common Pitfalls When Moving to Production

  • Forgetting to switch webhook scope: If your webhook was configured to receive only sandbox events during testing, update it to include production events before launch. Source
  • Not handling duplicate events: Webhooks can be delivered more than once. Make your event handlers idempotent by checking whether you have already processed an event ID before fulfilling it.
  • Assuming synchronous entitlement updates: The SDK's getCustomerInfo() fetches the latest state from RevenueCat's servers. After a purchase, always call getCustomerInfo() to get the freshest entitlement state rather than relying on locally cached data.

Refer to the RevenueCat Playbooks overview for additional production readiness guidance.


MCP Tool Best Practices for Paywall Management

What is the RevenueCat MCP Server?

The RevenueCat MCP (Model Context Protocol) Server enables AI assistants to manage subscription apps, products, entitlements, and everything in-between without requiring direct dashboard access. This powerful tool provides 26 different capabilities for complete subscription management through natural language interactions. Source

The MCP server acts as a bridge between AI assistants (such as Claude, GPT-4, and others) and the RevenueCat API, enabling natural language interactions with your subscription infrastructure. Source

The cloud-hosted MCP server is available at https://mcp.revenuecat.ai/mcp and is best suited for: Source

  • Team collaboration and shared access
  • Production environments
  • Individual developer use
  • Integration with multiple AI assistants or applications
  • Centralized, always-available service

Security Considerations in Production

When using the MCP tool in a live production environment, API key hygiene is paramount. RevenueCat's best practices documentation recommends the following: Source

  • Use dedicated keys: Create separate API keys for different environments (development, staging, production).
  • Principle of least privilege: Use read-only keys when write access is not needed.
  • Regular rotation: Periodically rotate your API keys for security.

In practice, this means your MCP integration used for read-only paywall monitoring (e.g., inspecting offering configurations or entitlement mappings) should use a different, read-only API key than your integration that writes changes to offerings or packages.

Naming Conventions for Packages

When managing packages through the MCP tool, follow RevenueCat's established naming conventions to ensure compatibility with the SDK's default offering logic: Source

Package Type Identifier
Monthly subscription $rc_monthly
Annual subscription $rc_annual
Three-month subscription $rc_three_month
Six-month subscription $rc_six_month
Lifetime purchase $rc_lifetime
Custom packages $rc_custom_*

Deviating from these conventions for standard durations can cause packages to not be recognized correctly by the RevenueCat SDK's default offering display logic.

Troubleshooting OAuth Issues

If you are using OAuth to authenticate with the RevenueCat MCP, you may encounter specific errors: Source

Unknown MCP Client

  • Symptoms: OAuth flow fails with an error indicating the client is not recognized.
  • Cause: RevenueCat uses a simplified