Connect Firebase to Stripe by using the official Stripe Payments Firebase Extension or building a custom Cloud Function webhook. The Extension automates customer creation, subscription syncing, and payment processing by storing data in Firestore. For custom setups, create an onRequest Cloud Function that receives Stripe webhook events, verifies the signature, and updates Firestore accordingly. Always store your Stripe secret key using defineSecret() and verify webhook signatures to prevent forged requests.
Integrating Stripe Payments with Firebase Using Extensions and Cloud Functions
Firebase and Stripe together power payment systems for thousands of apps. This tutorial covers two approaches: the official Stripe Payments Firebase Extension (fastest setup, best for subscriptions) and a custom Cloud Function webhook (most flexible, best for one-time payments and complex logic). Both approaches store payment data in Firestore and use Cloud Functions on the Blaze plan.
Prerequisites
- A Firebase project on the Blaze plan with Firestore and Cloud Functions enabled
- A Stripe account with API keys (Dashboard > Developers > API keys)
- Firebase CLI installed and authenticated
- Basic understanding of Cloud Functions and Firestore
Step-by-step guide
Install the Stripe Payments Firebase Extension
Install the Stripe Payments Firebase Extension
The fastest way to connect Firebase to Stripe is the official 'Run Payments with Stripe' extension. Go to the Firebase Console > Extensions > Explore Extensions and search for Stripe. Click Install and configure it with your Stripe secret key and webhook signing secret. The extension automatically creates Firestore collections for customers, products, and subscriptions.
1# Install via Firebase CLI2firebase ext:install stripe/firestore-stripe-payments --project=your-project-id34# The CLI prompts for:5# - Stripe API key (from Stripe Dashboard > Developers > API keys)6# - Stripe webhook signing secret7# - Firestore collection names (default: customers, products, subscriptions)8# - Cloud Functions locationExpected result: The Stripe extension is installed and creates Firestore collections for syncing payment data.
Configure Stripe webhook endpoint
Configure Stripe webhook endpoint
After installing the extension, copy the webhook URL from Firebase Console > Functions and add it to Stripe. In the Stripe Dashboard, go to Developers > Webhooks > Add endpoint. Paste the Cloud Function URL and select the events to listen for. At minimum, subscribe to checkout.session.completed, customer.subscription.created, customer.subscription.updated, and customer.subscription.deleted.
1// Stripe webhook URL format (from Firebase Console > Functions):2// https://us-central1-your-project.cloudfunctions.net/ext-firestore-stripe-payments-handleWebhookEvents34// Events to subscribe to in Stripe Dashboard:5// - checkout.session.completed6// - customer.subscription.created7// - customer.subscription.updated8// - customer.subscription.deleted9// - invoice.payment_succeeded10// - invoice.payment_failedExpected result: Stripe sends webhook events to your Firebase Cloud Function endpoint.
Create a checkout session from your app
Create a checkout session from your app
With the extension installed, create a checkout session by writing a document to the checkout_sessions subcollection under the customer document in Firestore. The extension picks up the new document, creates a Stripe Checkout session, and writes the session URL back to the document. Your app redirects the user to this URL.
1import { db } from "@/lib/firebase";2import { auth } from "@/lib/firebase";3import {4 collection, addDoc, onSnapshot5} from "firebase/firestore";67async function createCheckoutSession(priceId: string) {8 const user = auth.currentUser;9 if (!user) throw new Error("Must be logged in");1011 // Create a checkout session document12 const checkoutRef = await addDoc(13 collection(db, "customers", user.uid, "checkout_sessions"),14 {15 price: priceId, // Stripe Price ID from your products16 success_url: window.location.origin + "/success",17 cancel_url: window.location.origin + "/pricing",18 }19 );2021 // Listen for the Stripe session URL22 onSnapshot(checkoutRef, (snap) => {23 const data = snap.data();24 if (data?.url) {25 window.location.assign(data.url); // Redirect to Stripe Checkout26 }27 if (data?.error) {28 console.error("Checkout error:", data.error.message);29 }30 });31}Expected result: Clicking a purchase button creates a checkout session and redirects the user to Stripe Checkout.
Build a custom webhook handler (alternative to extension)
Build a custom webhook handler (alternative to extension)
If you need more control than the extension provides, build a custom Cloud Function that receives Stripe webhooks. Use onRequest to create an HTTP endpoint, verify the webhook signature with Stripe's library, and handle events by updating Firestore. Store the Stripe secret key and webhook signing secret using defineSecret().
1import { onRequest } from "firebase-functions/v2/https";2import { defineSecret } from "firebase-functions/params";3import { getFirestore } from "firebase-admin/firestore";4import * as admin from "firebase-admin";5import Stripe from "stripe";67admin.initializeApp();8const db = getFirestore();910const stripeSecretKey = defineSecret("STRIPE_SECRET_KEY");11const webhookSecret = defineSecret("STRIPE_WEBHOOK_SECRET");1213export const stripeWebhook = onRequest(14 {15 secrets: [stripeSecretKey, webhookSecret],16 cors: false, // Stripe does not use CORS17 },18 async (req, res) => {19 const stripe = new Stripe(stripeSecretKey.value());2021 // Verify webhook signature22 let event: Stripe.Event;23 try {24 event = stripe.webhooks.constructEvent(25 req.rawBody,26 req.headers["stripe-signature"] as string,27 webhookSecret.value()28 );29 } catch (err) {30 res.status(400).send(`Webhook signature verification failed`);31 return;32 }3334 // Handle events35 switch (event.type) {36 case "checkout.session.completed": {37 const session = event.data.object as Stripe.Checkout.Session;38 await db.doc(`orders/${session.id}`).set({39 customerId: session.customer,40 status: "paid",41 amount: session.amount_total,42 createdAt: admin.firestore.FieldValue.serverTimestamp(),43 });44 break;45 }46 case "customer.subscription.updated": {47 const sub = event.data.object as Stripe.Subscription;48 await db.doc(`subscriptions/${sub.id}`).update({49 status: sub.status,50 currentPeriodEnd: new Date(sub.current_period_end * 1000),51 });52 break;53 }54 }5556 res.json({ received: true });57 }58);Expected result: A custom Cloud Function handles Stripe webhooks and syncs payment data to Firestore.
Read subscription status in your app
Read subscription status in your app
Query Firestore to check if the current user has an active subscription. The extension stores subscription data under customers/{uid}/subscriptions. For custom webhooks, read from whatever collection you write to. Use this to gate premium features in your app.
1import { db, auth } from "@/lib/firebase";2import {3 collection, query, where, getDocs4} from "firebase/firestore";56async function checkSubscriptionStatus(): Promise<boolean> {7 const user = auth.currentUser;8 if (!user) return false;910 // With Stripe Extension:11 const subsRef = collection(12 db, "customers", user.uid, "subscriptions"13 );14 const q = query(15 subsRef,16 where("status", "in", ["active", "trialing"])17 );1819 const snapshot = await getDocs(q);20 return !snapshot.empty;21}2223// Usage:24const isPremium = await checkSubscriptionStatus();25if (isPremium) {26 // Show premium features27} else {28 // Show upgrade prompt29}Expected result: Your app can check if the current user has an active Stripe subscription via Firestore.
Complete working example
1import { onRequest } from "firebase-functions/v2/https";2import { defineSecret } from "firebase-functions/params";3import { getFirestore } from "firebase-admin/firestore";4import * as admin from "firebase-admin";5import { logger } from "firebase-functions";6import Stripe from "stripe";78admin.initializeApp();9const db = getFirestore();1011const stripeSecretKey = defineSecret("STRIPE_SECRET_KEY");12const webhookSecret = defineSecret("STRIPE_WEBHOOK_SECRET");1314export const stripeWebhook = onRequest(15 {16 secrets: [stripeSecretKey, webhookSecret],17 cors: false,18 maxInstances: 10,19 },20 async (req, res) => {21 const stripe = new Stripe(stripeSecretKey.value());2223 let event: Stripe.Event;24 try {25 event = stripe.webhooks.constructEvent(26 req.rawBody,27 req.headers["stripe-signature"] as string,28 webhookSecret.value()29 );30 } catch (err) {31 logger.error("Webhook signature failed:", err);32 res.status(400).send("Signature verification failed");33 return;34 }3536 logger.info(`Stripe event: ${event.type}`);3738 switch (event.type) {39 case "checkout.session.completed": {40 const session = event.data41 .object as Stripe.Checkout.Session;42 await db.doc(`orders/${session.id}`).set({43 stripeCustomerId: session.customer,44 status: "paid",45 amount: session.amount_total,46 currency: session.currency,47 createdAt:48 admin.firestore.FieldValue.serverTimestamp(),49 });50 break;51 }52 case "customer.subscription.created":53 case "customer.subscription.updated": {54 const sub = event.data55 .object as Stripe.Subscription;56 await db.doc(`subscriptions/${sub.id}`).set(57 {58 stripeCustomerId: sub.customer,59 status: sub.status,60 priceId: sub.items.data[0]?.price.id,61 currentPeriodEnd: new Date(62 sub.current_period_end * 100063 ),64 updatedAt:65 admin.firestore.FieldValue.serverTimestamp(),66 },67 { merge: true }68 );69 break;70 }71 case "customer.subscription.deleted": {72 const sub = event.data73 .object as Stripe.Subscription;74 await db.doc(`subscriptions/${sub.id}`).update({75 status: "canceled",76 canceledAt:77 admin.firestore.FieldValue.serverTimestamp(),78 });79 break;80 }81 }8283 res.json({ received: true });84 }85);Common mistakes when connecting Firebase to Stripe for Payments
Why it's a problem: Not verifying the Stripe webhook signature, allowing anyone to send fake payment events to your endpoint
How to avoid: Always call stripe.webhooks.constructEvent() with the raw request body, stripe-signature header, and your webhook signing secret. Return 400 if verification fails.
Why it's a problem: Storing the Stripe secret key in a .env file or hardcoding it in function code
How to avoid: Use defineSecret('STRIPE_SECRET_KEY') to store it in Cloud Secret Manager. Include it in the function's secrets array. Never put secret keys in .env files — they are deployed unencrypted.
Why it's a problem: Forgetting to add the Cloud Function URL as a webhook endpoint in the Stripe Dashboard
How to avoid: After deploying your function, copy its URL from Firebase Console > Functions and add it in Stripe Dashboard > Developers > Webhooks > Add endpoint. Select the specific events you want to receive.
Why it's a problem: Using req.body instead of req.rawBody for webhook signature verification, causing all signatures to fail
How to avoid: Firebase Cloud Functions automatically parse the JSON body. Stripe's signature verification needs the raw body. Use req.rawBody which contains the unparsed request body.
Best practices
- Always verify Stripe webhook signatures using stripe.webhooks.constructEvent() to prevent forged events
- Store Stripe API keys in Cloud Secret Manager using defineSecret() — never in .env files or code
- Use the Stripe Extension for standard subscription workflows to avoid writing boilerplate webhook code
- Set Firestore security rules so users can only read their own customer and subscription documents
- Handle both subscription creation and updates in the same case block to handle edge cases
- Log all Stripe events with structured logging for debugging payment issues
- Set maxInstances on your webhook function to prevent scaling issues during high-traffic events
- Test webhooks locally using Stripe CLI: stripe listen --forward-to localhost:5001/project/region/stripeWebhook
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
Show me how to build a Firebase Cloud Function that handles Stripe webhooks. I need to verify the webhook signature, handle checkout.session.completed and subscription events, and sync data to Firestore. Use v2 Cloud Functions with defineSecret for the Stripe keys.
Create a Firebase + Stripe integration using Cloud Functions v2. Build an onRequest webhook handler that verifies Stripe signatures using req.rawBody, stores Stripe keys with defineSecret, and syncs checkout.session.completed and subscription events to Firestore. Include security rules for the customer data.
Frequently asked questions
Should I use the Stripe Extension or build a custom webhook?
Use the extension for standard subscription and checkout workflows — it handles the common cases without code. Build a custom webhook if you need custom business logic, one-time payments with complex fulfillment, or integration with other services beyond Firestore.
Do I need the Blaze plan for Stripe integration?
Yes. Both the Stripe Extension and custom webhook Cloud Functions require the Blaze (pay-as-you-go) plan. Cloud Functions cannot be deployed on the free Spark plan.
How do I test Stripe webhooks locally?
Install the Stripe CLI and run: stripe listen --forward-to localhost:5001/your-project/us-central1/stripeWebhook. This forwards Stripe test events to your local Firebase Emulator. Use stripe trigger checkout.session.completed to simulate events.
Why are my webhook signatures always failing?
The most common cause is using req.body (parsed JSON) instead of req.rawBody (raw string) for signature verification. Stripe needs the exact bytes that were sent. Also verify you are using the correct webhook signing secret (not the API key).
How do I handle subscription renewals?
Listen for the invoice.payment_succeeded event for successful renewals and invoice.payment_failed for failed payments. The customer.subscription.updated event fires when the subscription status changes. If you need help architecting complex payment flows, RapidDev can build a production-ready Stripe integration for your Firebase app.
Can I use Stripe with Firebase Auth?
Yes. Create a Stripe customer when a Firebase user signs up, and store the Stripe customer ID in Firestore linked to the Firebase UID. The Stripe Extension does this automatically. For custom implementations, create the Stripe customer in an Auth onCreate trigger.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation