Build a complete e-commerce portal in Bubble with product listings, a shopping cart, Stripe-powered checkout, order management, and customer accounts. This tutorial walks through creating Data Types for products and orders, designing the storefront with Repeating Groups, and wiring up payment and fulfillment workflows — all without writing code.
Overview: Building an E-Commerce Portal in Bubble
This tutorial guides you through building a full e-commerce storefront in Bubble. You will create the database schema for products, orders, and line items, design product listing and detail pages, implement an add-to-cart flow with Custom States, connect Stripe for payment processing, and build an admin dashboard for order management. This guide is ideal for non-technical founders who want to launch a product-based business without hiring developers.
Prerequisites
- A Bubble account on the Growth plan or higher
- A Stripe account (test mode is fine to start)
- Basic familiarity with Bubble's Design and Data tabs
- Product images ready to upload
- Understanding of Bubble workflows (event → action pattern)
Step-by-step guide
Create your e-commerce Data Types
Create your e-commerce Data Types
Go to the Data tab and click Data types. Create a new Data Type called Product with these fields: Name (text), Description (text), Price (number), Image (image), Category (text), Stock (number), and Active (yes/no). Create a second Data Type called Order with fields: Customer (User), Status (text — e.g. Pending, Paid, Shipped, Delivered), Total (number), Stripe_Payment_ID (text), and Created_Date (date). Create a third Data Type called LineItem with fields: Product (Product type), Quantity (number), Subtotal (number), and Order (Order type). This three-type structure separates product data, order metadata, and individual items cleanly.
Pro tip: Use an Option Set for Order Status (Pending, Paid, Shipped, Delivered) instead of a plain text field — it prevents typos and makes conditional formatting easier.
Expected result: Three Data Types (Product, Order, LineItem) appear in the Data tab with all fields configured.
Build the product catalog page
Build the product catalog page
Go to the Design tab and open your index page (or create a new page called products). Click the + icon, search for Repeating Group, and drag it onto the page. Set its Type of content to Product and Data source to Do a search for Products where Active = yes. Set the layout to a grid (e.g. 3 columns, fixed number of rows: 4). Inside the first cell, add an Image element and set its dynamic source to Current cell's Product's Image. Add a Text element for Current cell's Product's Name, another for Current cell's Product's Price formatted as currency ($), and a Button labeled Add to Cart.
Pro tip: Add a Search Input above the Repeating Group and apply a constraint on the search: Name contains Search Input's value. Check 'Ignore empty constraints' so it shows all products when the search is empty.
Expected result: A responsive product grid displays all active products with images, names, prices, and Add to Cart buttons.
Implement the shopping cart with Custom States
Implement the shopping cart with Custom States
Select the page element (click on the page background) and create a Custom State called cart of type LineItem (check 'This is a list'). On the Add to Cart button's workflow, add action Element Actions → Set state: set cart to cart plus item — but first you need to create the LineItem. Use the action 'Create a new thing' (Type: LineItem, Product = Current cell's Product, Quantity = 1, Subtotal = Current cell's Product's Price). Then Set state of page to cart = page's cart plus item Result of step 1. For the cart display, add a Floating Group anchored to the right. Inside it, place a Repeating Group with Type: LineItem and Data source: page's cart. Display each item's Product Name, Quantity, and Subtotal. Add a Text element below showing the total: page's cart's each item's Subtotal:sum formatted as currency.
Pro tip: To handle duplicate products, add a condition: Only when page's cart's each item's Product contains Current cell's Product is no — otherwise increment the existing LineItem's Quantity instead of creating a new one.
Expected result: Users can add products to a visual cart sidebar that shows items, quantities, subtotals, and a grand total.
Install and configure the Stripe plugin
Install and configure the Stripe plugin
Go to the Plugins tab and click Add plugins. Search for Stripe and install the official Stripe plugin by Bubble. Once installed, click the plugin name to open its settings. Paste your Stripe Test Publishable Key into the Publishable key field and your Test Secret Key into the Secret key field. You can find these in your Stripe dashboard under Developers → API keys. Keep the keys in test mode until you are ready to go live. Scroll down to Checkout settings and ensure 'Use Stripe Checkout' is enabled.
Pro tip: Never paste live Stripe keys while testing. Switch to live keys only after thorough testing in Stripe's test mode with card number 4242 4242 4242 4242.
Expected result: The Stripe plugin is installed and configured with test API keys.
Create the checkout workflow
Create the checkout workflow
On the cart Floating Group, add a Checkout button. Create a workflow: When Checkout button is clicked. Add action Plugins → Stripe Checkout. In the Stripe Checkout action settings, set the Line items dynamically from the page's cart list — map each LineItem's Product Name as the description, Subtotal as the amount (in cents — multiply by 100), and Quantity. Set the success URL to your order confirmation page and the cancel URL back to the products page. After the Stripe Checkout action, add a second action: Create a new thing (Type: Order, Customer = Current User, Status = Pending, Total = page's cart's each item's Subtotal:sum). Then add actions to Make changes to a list of things — set each LineItem in the cart to have Order = Result of step 2.
Expected result: Clicking Checkout redirects users to Stripe's hosted checkout page, and a Pending order is created in the database.
Handle payment confirmation with a webhook
Handle payment confirmation with a webhook
In the Stripe dashboard, go to Developers → Webhooks → Add endpoint. Enter your Bubble backend workflow URL (you will create this next). In Bubble, go to the Workflow tab, open the pages dropdown, and click Backend workflows at the bottom. Create a new backend workflow called stripe-webhook. Add a parameter called stripe_event of type text. In the workflow actions, use the 'Make changes to a thing' action: search for the Order whose Stripe_Payment_ID matches the event's payment intent ID and set its Status to Paid. Back in the Stripe dashboard, set the webhook to listen for checkout.session.completed events.
Pro tip: For complex e-commerce setups where you need advanced Stripe features like subscription billing, inventory sync, or multi-currency support, RapidDev can help architect a scalable payment system tailored to your business.
Expected result: When a customer completes payment, Stripe sends a webhook that automatically updates the order status to Paid.
Build the order management dashboard
Build the order management dashboard
Create a new page called admin-orders. Add a Repeating Group with Type of content: Order and Data source: Do a search for Orders, sorted by Created Date descending. In each cell, display the Order's Customer email, Status, Total formatted as currency, and Created Date formatted as MM/DD/YYYY. Add a Dropdown element in each cell with values from the Order Status Option Set (Pending, Paid, Shipped, Delivered). Create a workflow on the dropdown: When dropdown value changes → Make changes to Current cell's Order → set Status to This dropdown's value. Add Privacy Rules on the Order Data Type: only users with an Admin role field = yes can view all orders.
Expected result: An admin page shows all orders in a table with the ability to update order status via a dropdown.
Add customer account and order history pages
Add customer account and order history pages
Create a page called my-orders. Add a Repeating Group with Type: Order and Data source: Do a search for Orders where Customer = Current User, sorted by Created Date descending. In each cell, show the order's Status (with conditional coloring — green for Delivered, yellow for Shipped, blue for Paid, gray for Pending), Total, and date. Add a group inside each cell that is only visible when the cell is clicked — this expands to show the order's LineItems in a nested Repeating Group (Type: LineItem, Data source: Search for LineItems where Order = Current cell's Order). Each LineItem row shows Product Name, Quantity, and Subtotal.
Expected result: Logged-in customers see their order history with expandable details showing individual items per order.
Complete working example
1E-COMMERCE PORTAL — WORKFLOW SUMMARY2=====================================34DATA TYPES:5 Product: Name (text), Description (text), Price (number),6 Image (image), Category (text), Stock (number), Active (yes/no)7 Order: Customer (User), Status (Option Set), Total (number),8 Stripe_Payment_ID (text), Created_Date (date)9 LineItem: Product (Product), Quantity (number), Subtotal (number),10 Order (Order)1112Option Set — OrderStatus:13 Pending, Paid, Shipped, Delivered1415PAGE: products16 Repeating Group → Type: Product, Source: Search Products (Active=yes)17 Each cell: Image, Name, Price, [Add to Cart] button18 Custom State on page: cart (list of LineItem)1920 Workflow: Add to Cart clicked21 1. Create new LineItem (Product, Qty=1, Subtotal=Price)22 2. Set state cart = cart + Result of step 12324 Workflow: Checkout clicked25 1. Stripe Checkout (line items from cart list)26 2. Create Order (Customer=Current User, Status=Pending, Total=sum)27 3. Make changes to list: each LineItem → set Order = Result of step 22829PAGE: admin-orders (Admin only)30 Repeating Group → Type: Order, Source: Search Orders (sorted by date)31 Each cell: Customer email, Status dropdown, Total, Date3233 Workflow: Dropdown value changes34 1. Make changes to Current cell's Order → Status = dropdown value3536PAGE: my-orders (Customer)37 Repeating Group → Type: Order, Source: Search Orders (Customer=Current User)38 Nested RG: LineItems where Order = Current cell's Order3940BACKEND WORKFLOW: stripe-webhook41 Trigger: Incoming webhook from Stripe42 1. Search for Order where Stripe_Payment_ID = event payment intent43 2. Make changes → Status = Paid4445PRIVACY RULES:46 Product: Everyone can view active products47 Order: Only Creator can view own orders; Admin can view all48 LineItem: Same as Order (linked via Order field)Common mistakes when creating an e-commerce portal in Bubble.io: Step-by-Step Guide
Why it's a problem: Storing the cart in the database instead of Custom States
How to avoid: Use a Custom State (list of LineItem) on the page for the cart. Only write to the database when the user checks out.
Why it's a problem: Not multiplying the price by 100 for Stripe
How to avoid: In the Stripe Checkout action, set the amount to Product's Price * 100 to convert dollars to cents.
Why it's a problem: Forgetting Privacy Rules on the Order Data Type
How to avoid: Add a Privacy Rule: 'This Order's Customer is Current User' with Find in searches and View all fields checked.
Why it's a problem: Skipping the webhook and relying on the redirect URL for payment confirmation
How to avoid: Always use Stripe webhooks to confirm payment. The webhook fires server-side regardless of what the user does.
Best practices
- Use Option Sets for product categories and order statuses to ensure consistency across the app
- Add a Stock field to Products and decrement it in the checkout workflow to prevent overselling
- Display loading indicators during Stripe Checkout to reassure customers the payment is processing
- Test the full purchase flow end-to-end in Stripe test mode before switching to live keys
- Set up email notifications (via SendGrid or Bubble's built-in email) for order confirmation and status updates
- Add search and filter controls on the admin dashboard to help manage orders at scale
- Use Stripe's Customer Portal for self-service refund requests to reduce admin workload
- Compress product images before uploading to keep page load times fast
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I'm building an e-commerce store in Bubble.io with products, a shopping cart, Stripe checkout, and order management. Can you help me design the data model and outline the key workflows I need for adding to cart, checking out with Stripe, and tracking order status?
Create a product catalog page with a Repeating Group showing product images, names, and prices. Add an Add to Cart button that stores selected items in a Custom State list. Include a cart sidebar showing all selected items with a Checkout button.
Frequently asked questions
Can I build an e-commerce store on Bubble's Free plan?
You can prototype on the Free plan, but you cannot process live Stripe payments or use a custom domain. Upgrade to the Growth plan before accepting real customer payments.
How do I handle product variants like sizes and colors?
Create a separate Data Type called Variant with fields for Size, Color, Price, and Stock, linked to the parent Product. Display variants in a dropdown on the product detail page and reference the selected variant in the cart.
What happens if Stripe checkout fails?
If the customer's payment fails, Stripe shows an error on the checkout page and does not redirect to your success URL. The Order remains in Pending status. You can add a workflow on the cancel URL page to clean up or notify the user.
How do I add shipping cost calculations?
Use a backend workflow that calls a shipping API (like EasyPost or Shippo) via the API Connector. Pass the customer's address and cart weight to get rates, then add the shipping cost to the order total before Stripe Checkout.
Can I send order confirmation emails from Bubble?
Yes. Add a Send email action in your stripe-webhook backend workflow that fires after the order status changes to Paid. Use dynamic data to include the customer's name, order number, and item details.
Is Bubble suitable for a high-volume e-commerce store?
Bubble works well for stores with up to a few thousand products and moderate traffic. For high-volume stores with thousands of daily transactions, consider consulting RapidDev to evaluate whether a hybrid architecture or migration would better support your scale.
How do I handle inventory management?
Add a Stock (number) field to the Product Data Type. In the checkout workflow, after payment confirmation, use Make changes to a thing to decrement each product's Stock by the LineItem's Quantity. Add a condition to the Add to Cart button: only visible when Product's Stock > 0.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation