Skip to main content
RapidDev - Software Development Agency
bubble-tutorial

How to build subscriptions in Bubble

Gate content by subscription tier in Bubble by checking the user's subscription status before showing premium content, handling expired subscriptions with upgrade prompts, and building upgrade and downgrade flows. This ensures only paying subscribers access your premium features.

What you'll learn

  • How to check subscription status before displaying gated content
  • How to build content visibility rules based on subscription tier
  • How to handle expired subscriptions with upgrade prompts
  • How to implement upgrade and downgrade flows
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner5 min read20-25 minAll Bubble plansMarch 2026RapidDev Engineering Team
TL;DR

Gate content by subscription tier in Bubble by checking the user's subscription status before showing premium content, handling expired subscriptions with upgrade prompts, and building upgrade and downgrade flows. This ensures only paying subscribers access your premium features.

Overview: Adding User Subscription Features in Bubble

This tutorial shows you how to gate app content by subscription tier. You will check the user's active subscription before showing premium content, display upgrade prompts for free users, handle expired subscriptions gracefully, and build the upgrade/downgrade flow.

Prerequisites

  • A Bubble account with an existing app
  • Stripe plugin configured for subscription payments
  • A Subscription or Plan data type already created
  • Basic understanding of Bubble conditionals and workflows

Step-by-step guide

1

Set up the subscription data structure

Go to the Data tab and ensure you have: a Plan Option Set with tiers (Free, Pro, Business) and attributes (monthly_price, features list). On the User data type, add fields: current_plan (Option Set: Plan), subscription_status (text: active, cancelled, expired), stripe_subscription_id (text), and subscription_end_date (date).

Expected result: User has subscription-related fields and a Plan Option Set defines available tiers.

2

Build content gating with conditionals

On pages with premium content, wrap gated sections in a Group. Add a conditional: When Current User's current_plan is Free or Current User's subscription_status is not active — hide this Group. Show a different Group with an upgrade prompt: This feature is available on Pro and above. Upgrade now. For individual elements, use conditionals to show/hide based on the plan tier. Always use Privacy Rules as the security layer — conditionals only control UI visibility.

Pro tip: Put the security check in Privacy Rules, not just element visibility. Hidden elements can still be accessed by tech-savvy users.

Expected result: Premium content is hidden from free users with upgrade prompts shown instead.

3

Handle expired subscriptions

Create a backend workflow called check_expired_subscriptions that runs daily. Search for Users where subscription_end_date < Current date/time and subscription_status = active. For each, change subscription_status to expired and current_plan to Free. On page load, check if the user's subscription has expired: When Current User's subscription_status is expired, show a banner: Your subscription has expired. Renew to continue accessing premium features.

Expected result: Expired subscriptions are automatically detected and users see renewal prompts.

4

Build the upgrade flow

Create an upgrade page showing the Plan Option Set in a Repeating Group with pricing, features, and a Select Plan button per tier. The workflow: trigger Stripe Checkout for the selected plan's price. On payment success, update the User: current_plan = selected plan, subscription_status = active, stripe_subscription_id = Stripe result, subscription_end_date = one month from now.

Expected result: Users can select a plan, pay via Stripe, and immediately access premium content.

5

Implement downgrade and cancellation

On the account settings page, show the current plan with a Change Plan button. For downgrades, use Stripe's API to update the subscription to the lower plan — the change takes effect at the end of the current billing period. For cancellation, call Stripe's cancel subscription endpoint. Update the User: subscription_status = cancelled. The user keeps access until subscription_end_date. For complex subscription management with usage-based billing, consider working with RapidDev.

Expected result: Users can downgrade or cancel their subscription, with access continuing until the end of the billing period.

Complete working example

Workflow summary
1SUBSCRIPTION FEATURES WORKFLOW SUMMARY
2==========================================
3
4OPTION SET: Plan
5 Free: $0, basic features
6 Pro: $29, premium features
7 Business: $99, all features + priority support
8
9USER FIELDS:
10 current_plan (Plan Option Set)
11 subscription_status (text: active/cancelled/expired)
12 stripe_subscription_id (text)
13 subscription_end_date (date)
14
15CONTENT GATING:
16 Group Premium Content:
17 Visible when: Current User's current_plan is not Free
18 AND subscription_status is active
19 Group Upgrade Prompt:
20 Visible when: Current User's current_plan is Free
21 OR subscription_status is not active
22
23WORKFLOW 1: Upgrade
24 Event: Button Select Plan is clicked
25 Action 1: Stripe Checkout (plan price * 100)
26 On success:
27 Action 2: Make changes to Current User
28 current_plan = selected Plan
29 subscription_status = active
30 subscription_end_date = Current date + 1 month
31
32WORKFLOW 2: Cancel
33 Event: Button Cancel is clicked
34 Action 1: Call Stripe API - Cancel Subscription
35 Action 2: Make changes to Current User
36 subscription_status = cancelled
37
38BACKEND: check_expired_subscriptions (daily)
39 Search: Users where end_date < now AND status = active
40 Action: Make changes to list
41 subscription_status = expired
42 current_plan = Free

Common mistakes when building subscriptions in Bubble

Why it's a problem: Relying only on element visibility for content gating

How to avoid: Use Privacy Rules to prevent premium content data from being sent to free users at all.

Why it's a problem: Not checking subscription expiry

How to avoid: Run a daily backend workflow that checks subscription_end_date and updates expired accounts.

Why it's a problem: Applying plan changes immediately instead of at period end

How to avoid: Schedule downgrades to take effect at the subscription_end_date using Stripe's built-in proration handling.

Best practices

  • Use Privacy Rules as the security layer for content gating, not just visibility conditionals
  • Check subscription expiry daily with a backend workflow
  • Show clear upgrade prompts instead of just hiding content
  • Handle downgrades at the end of the billing period
  • Display current plan and renewal date on the account settings page
  • Store the stripe_subscription_id for managing subscriptions via API
  • Offer a grace period before revoking access on expired subscriptions

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I am building a Bubble.io app with subscription tiers (Free, Pro, Business). I need to gate content based on the user's plan, handle expired subscriptions, and build upgrade/downgrade flows with Stripe. How do I set this up?

Bubble Prompt

Add subscription-based content gating. Check the user's plan before showing premium content. Show upgrade prompts for free users. Build upgrade and cancellation workflows with Stripe and handle expired subscriptions automatically.

Frequently asked questions

How do I handle Stripe webhooks for subscription changes?

Set up a Stripe webhook endpoint using Bubble's API workflows. Listen for events like invoice.paid, customer.subscription.updated, and customer.subscription.deleted to keep your User records in sync.

Can I offer annual billing discounts?

Yes. Create separate Stripe Prices for monthly and annual billing. Display both options on the pricing page with the annual discount highlighted.

What happens if a payment fails?

Stripe automatically retries failed payments. Listen for the invoice.payment_failed webhook event and update the user's subscription_status to past_due with a warning banner.

Can RapidDev help with subscription management?

Yes. RapidDev specializes in Bubble development and can build complete subscription systems with Stripe webhooks, usage-based billing, team subscriptions, and customer portal integration.

Should I use Stripe's Customer Portal?

Yes. Stripe's Customer Portal lets users manage their subscription, update payment methods, and view invoices without you building that UI. Link to it from your account settings page.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.