How to Add Subscriptions to a Chrome Extension
Chrome extensions have unique billing challenges. Learn how to implement subscriptions, handle authentication in a browser context, and gate features by plan.
In This Guide
Comparisons
Why Chrome Extension Billing is Different
Chrome extensions operate in a unique environment:
These constraints make traditional SaaS billing patterns harder. You can't just drop in a checkout page.
Monetization Options for Chrome Extensions
Chrome Web Store Payments (Deprecated)
Google deprecated the Chrome Web Store payment API in 2020. You can no longer use Google's built-in monetization.
One-Time Purchase via Gumroad/LemonSqueezy
Sell a license key, validate it in the extension.
Pros: Simple, no ongoing infrastructure
Cons: No recurring revenue, license key sharing
Subscription via Your Own Backend
Use a subscription platform (like StackBE) to handle billing.
Pros: Recurring revenue, feature gating, customer management
Cons: Requires a backend, more complex
For sustainable Chrome extension businesses, subscriptions are the path to recurring revenue.
Architecture Overview
A subscription-enabled Chrome extension has three parts:
Chrome Extension (client)
↕ API calls
Your Backend or StackBE (subscription management)
↕ Payment processing
Stripe (payment gateway)
The Flow
1. User installs extension from Chrome Web Store
2. Extension prompts to create account (or sign in)
3. User authenticates via magic link (email-based, works great for extensions)
4. Extension stores session token in `chrome.storage.sync`
5. Extension checks subscription status on load
6. Free users see basic features; paid users unlock premium
7. Upgrade flow opens checkout in a new tab
8. After payment, extension detects subscription change
Step-by-Step Implementation
1. Set Up StackBE
Create your StackBE app and define plans:
Free Plan:
Pro Plan ($9/month):
2. Authentication in the Extension
Magic links work particularly well for extensions because:
Popup or Options Page Auth Flow:
// popup.js or options.jsasync function sendMagicLink(email) {const response = await fetch('https://api.stackbe.io/v1/auth/magic-link', {method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Api-Key': YOUR_API_KEY,
'X-App-Id': YOUR_APP_ID
},body: JSON.stringify({
email,
callbackUrl: chrome.runtime.getURL('auth-callback.html')
})});// Show "check your email" message}Auth Callback Page:
Create an `auth-callback.html` in your extension that captures the token from the magic link URL.
// auth-callback.jsconst params = new URLSearchParams(window.location.search);const token = params.get('token');if (token) {// Store session in chrome.storagechrome.storage.sync.set({ sessionToken: token });
// Redirect to success viewwindow.close();
}3. Checking Subscription Status
On extension load (or popup open), check the current subscription:
async function checkSubscription() {const { sessionToken } = await chrome.storage.sync.get('sessionToken');if (!sessionToken) {return { plan: 'none', authenticated: false };}const response = await fetch('https://api.stackbe.io/v1/subscriptions/current', {headers: {
'Authorization': `Bearer ${sessionToken}`,
'X-Api-Key': YOUR_API_KEY,
'X-App-Id': YOUR_APP_ID
}});if (response.ok) {const subscription = await response.json();return {plan: subscription.plan.slug,
status: subscription.status,
authenticated: true
};}return { plan: 'free', authenticated: true };}4. Gating Features
Use subscription status to enable/disable features:
async function initExtension() {const { plan, status } = await checkSubscription();// Cache the plan locally for performancechrome.storage.local.set({ currentPlan: plan });
if (plan === 'pro' && status === 'active') {enableProFeatures();
} else {enableFreeFeatures();
showUpgradePrompt();
}}5. Entitlement Checks
For granular feature gating, use StackBE's entitlements API:
async function hasFeature(featureKey) {const { sessionToken } = await chrome.storage.sync.get('sessionToken');const response = await fetch(`https://api.stackbe.io/v1/entitlements/check/${featureKey}`,
{headers: {
'Authorization': `Bearer ${sessionToken}`,
'X-Api-Key': YOUR_API_KEY
}});
const { hasAccess } = await response.json();return hasAccess;}// Usageif (await hasFeature('bulk_export')) {showBulkExportButton();
}6. Upgrade Flow
Open Stripe checkout in a new tab:
async function openUpgradeFlow(planId) {const { sessionToken } = await chrome.storage.sync.get('sessionToken');const response = await fetch('https://api.stackbe.io/v1/checkout/session', {method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${sessionToken}`,
'X-Api-Key': YOUR_API_KEY,
'X-App-Id': YOUR_APP_ID
},body: JSON.stringify({
planId,
successUrl: chrome.runtime.getURL('upgrade-success.html'),
cancelUrl: chrome.runtime.getURL('popup.html')
})});const { url } = await response.json();chrome.tabs.create({ url });
}7. Detecting Subscription Changes
After checkout, detect that the subscription has changed:
// upgrade-success.html script// Re-check subscription status and update extensionasync function onUpgradeSuccess() {const sub = await checkSubscription();chrome.storage.sync.set({ currentPlan: sub.plan });
// Notify the extension popup/backgroundchrome.runtime.sendMessage({ type: 'SUBSCRIPTION_UPDATED', plan: sub.plan });
}Manifest V3 Considerations
Service Workers
MV3 uses service workers instead of persistent background pages. They're ephemeral—they can shut down between events.
Implication: Don't rely on in-memory subscription state. Always read from `chrome.storage`.
Content Security Policy
MV3 has stricter CSP. You can't inline scripts or load external scripts in extension pages.
Implication: All API calls must be from your extension's JavaScript files, not injected scripts.
Host Permissions
Declare API permissions in manifest.json:
{"permissions": ["storage"],
"host_permissions": [
"https://api.stackbe.io/*"
]
}Chrome Web Store Considerations
Pricing Display
The Chrome Web Store allows you to describe pricing in your listing. Mention your free tier and link to pricing for paid plans.
Review Guidelines
Google reviews extensions with payment flows. Ensure:
Free vs Paid Split
Common Chrome extension pricing strategy:
Best Practices
Cache Subscription Status
Don't check the API on every popup open:
async function getCachedSubscription() {const { cachedPlan, cacheTimestamp } = await chrome.storage.local.get(['cachedPlan', 'cacheTimestamp'
]);
// Refresh if cache is older than 5 minutesif (!cachedPlan || Date.now() - cacheTimestamp > 300000) {const sub = await checkSubscription();chrome.storage.local.set({
cachedPlan: sub.plan,
cacheTimestamp: Date.now()
});return sub.plan;}return cachedPlan;}Handle Offline Gracefully
Extensions work offline. If subscription check fails:
Sync Across Devices
Using `chrome.storage.sync` ensures session data follows the Chrome profile:
Show Clear Upgrade Paths
When free users hit limits, show what they're missing:
Revenue Expectations
Chrome extension economics:
Example: 10,000 installs × 3% conversion × $9/month = $2,700 MRR
The key is distribution. Chrome Web Store is free distribution. Pair it with StackBE for the billing backend.
Next Steps
1. Set up StackBE and create your plans
2. Implement auth using magic links
3. Add subscription checks to your extension
4. Build the upgrade flow with Stripe checkout
5. Test thoroughly across Chrome profiles and devices
For a detailed walkthrough with code examples, see our blog post on adding subscriptions to Chrome extensions.
Related Resources
Chrome Extension Subscriptions Tutorial
Step-by-step code tutorial
SaaS Billing Guide
Complete billing fundamentals
Entitlements Guide
Feature gating for extensions
StackBE vs Gumroad
Subscriptions vs one-time sales
StackBE vs LemonSqueezy
Alternative billing for extensions
Auth API Docs
Magic link authentication
Ready to simplify your SaaS backend?
StackBE combines auth, billing, and entitlements in one API. Get started in minutes, not weeks.
Get Started FreeFrequently Asked Questions
Other Guides
The Complete Guide to SaaS Billing
Master SaaS billing from subscription models to payment recovery. Learn how to implement billing that scales with your business.
The Complete Guide to SaaS Authentication
Master SaaS authentication from passwordless to enterprise SSO. Learn how to implement secure, user-friendly auth for your application.
The Complete Guide to SaaS Entitlements
Master SaaS entitlements—the system that controls what features users can access based on their subscription. Learn why it's different from feature flags.
How to Add Subscriptions to a Next.js App
Next.js is the most popular framework for SaaS. Learn how to add authentication, subscription billing, and feature gating with StackBE.
How to Monetize Your API Product
Turning your API into a business requires more than just code. Learn pricing strategies, usage-based billing, and access control for API products.
How to Add Subscriptions to a Desktop Application
Desktop apps have unique subscription challenges: offline access, license validation, and cross-platform auth. Learn how to handle them with StackBE.