6 min read

How to Set Up Billing Portal in Stripe

Your customers need to manage subscriptions, update payment methods, and download invoices—but you don't want to build that UI. Stripe's Billing Portal handles all of this out of the box. Here's how to set it up.

Enable and Configure the Portal

Before you can use the Billing Portal, you need to enable it in your Stripe account and decide which features customers can access.

Navigate to Billing Portal Settings

In the Stripe Dashboard, go to Settings > Billing Portal. You'll see options to enable the portal and customize features.

Enable Portal Features

Turn on the features you want customers to access: Update payment method, Cancel subscription, View invoices, and Download invoices. You can also set branding to match your product with a logo and accent color.

Configure Subscription Management Options

Under Subscription updates, choose whether customers can pause, resume, or cancel subscriptions. Set allowed intervals for plan changes if you want to restrict how often they can upgrade or downgrade. Save your configuration.

javascript
// Portal configuration is managed via Dashboard, but you can also
// use the API to create a custom configuration programmatically:
const configuration = await stripe.billingPortal.configurations.create({
  features: {
    subscription_cancel: { enabled: true },
    subscription_pause: { enabled: true },
    subscription_update: { enabled: true, proration_behavior: 'create_prorations' },
    invoice_history: { enabled: true },
    payment_method_update: { enabled: true },
  },
  business_profile: {
    privacy_policy_url: 'https://example.com/privacy',
    terms_of_service_url: 'https://example.com/terms',
  },
});
Create a portal configuration via API (optional)
Tip: Enable Update payment method at minimum — it reduces failed charges when cards expire.

Generate and Serve Portal Sessions

Once configured, you create a Billing Portal session server-side and send the link to your customer.

Install Stripe SDK

Add the Stripe Node SDK to your backend: npm install stripe or yarn add stripe. Initialize it with your secret key.

javascript
const stripe = require('stripe')('sk_live_...');

// Or using ES modules:
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
Initialize the Stripe SDK

Create a Billing Portal Session

Call stripe.billingPortal.sessions.create() with the customer ID and a return URL (where they go after exiting the portal). The method returns a session with a URL.

javascript
const session = await stripe.billingPortal.sessions.create({
  customer: 'cus_1A2B3C4D5E6F7G8H', // The customer's Stripe ID
  return_url: 'https://example.com/account', // Where they return after
});

console.log(session.url); // https://billing.stripe.com/p/session/...
Create a portal session and get the URL

Redirect the Customer to the Portal

Send the session.url to your frontend and redirect the customer (or open in a new tab). They'll be authenticated automatically via the session token—no login required.

javascript
// Backend route (Node.js + Express example)
app.post('/create-portal-session', async (req, res) => {
  const { customerId } = req.body;

  const session = await stripe.billingPortal.sessions.create({
    customer: customerId,
    return_url: 'https://example.com/account',
  });

  res.json({ url: session.url });
});

// Frontend: redirect on button click
fetch('/create-portal-session', { method: 'POST', body: JSON.stringify({ customerId }) })
  .then(res => res.json())
  .then(({ url }) => window.location.href = url);
Full flow: create session server-side, redirect client-side
Watch out: The return_url must be a full URL. Stripe won't redirect to relative paths like /account.

Test and Monitor Changes

Verify the portal works before going live and set up webhooks to catch subscription changes.

Test with Stripe Test Mode

Toggle to Test mode in the Stripe Dashboard (top-left corner). Create a test customer with a test subscription using card 4242 4242 4242 4242. Generate a portal session and walk through the entire flow—update payment method, view invoices, try pausing or canceling.

Monitor Subscription Changes via Webhooks

Set up a webhook listener for events like customer.subscription.updated, customer.subscription.deleted, and invoice.payment_failed. This syncs changes back to your database (e.g., revoke feature access when a customer cancels).

javascript
app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
  const sig = req.headers['stripe-signature'];
  let event;

  try {
    event = stripe.webhooks.constructEvent(
      req.body,
      sig,
      process.env.STRIPE_WEBHOOK_SECRET
    );
  } catch (err) {
    return res.status(400).send(`Webhook Error: ${err.message}`);
  }

  if (event.type === 'customer.subscription.updated') {
    const subscription = event.data.object;
    // Sync to your database: check if paused, canceled, or plan changed
  }

  if (event.type === 'customer.subscription.deleted') {
    const subscription = event.data.object;
    // Revoke access for this customer
  }

  res.json({received: true});
});
Listen for subscription changes via webhooks
Tip: Use customer.subscription.deleted events to revoke access immediately, rather than polling Stripe's API.

Common Pitfalls

  • Forgetting to enable features in Billing Portal settings — customers see an empty portal if no features are turned on.
  • Using a relative URL for return_url — it must be a full URL starting with https://.
  • Not syncing subscription changes via webhooks — your backend gets out of sync if customers cancel, pause, or change plans in the portal.
  • Testing in live mode instead of test mode — accidentally charging real customers or modifying real subscriptions during development.

Wrapping Up

You now have a fully functional Billing Portal that lets customers manage their own subscriptions without you building custom pages. Track how often they use it—pause vs. cancel rates, plan changes—to understand churn drivers. If you want to track this automatically across tools, Product Analyst can help.

Track these metrics automatically

Product Analyst connects to your stack and surfaces the insights that matter.

Try Product Analyst — Free