Build a shopping cart in Bubble using a CartItem data type linked to the User and Product. Users add items via a workflow that creates or updates CartItem records, view their cart in a Repeating Group, adjust quantities, and see real-time price totals. For anonymous users, store cart data in Custom States until they sign up or log in, then migrate items to the database.
Build a Full Shopping Cart in Bubble
This tutorial walks you through building a complete shopping cart for an e-commerce Bubble app. You will create the data structure, implement add-to-cart workflows, display the cart with quantity controls, calculate totals, and handle both logged-in and guest users. This is a core feature for any online store built on Bubble.
Prerequisites
- A Bubble account with an existing app
- A Product data type with name, price, image, and stock fields
- User authentication set up (login/signup)
- Basic familiarity with Repeating Groups and workflows
Step-by-step guide
Create the CartItem Data Type
Create the CartItem Data Type
Go to Data tab → Data types → '+ New type' and create 'CartItem' with fields: user (User), product (Product), quantity (number, default 1), and line_total (number). The user field links each cart item to the logged-in user. The line_total will store quantity * product price so you do not recalculate it on every page load. Set Privacy Rules so users can only see their own CartItems (condition: Current User = This CartItem's user).
Expected result: A CartItem data type exists with user, product, quantity, and line_total fields, plus privacy rules.
Build the Add to Cart Workflow
Build the Add to Cart Workflow
On your product listing or detail page, add an 'Add to Cart' button. Create a workflow: When 'Add to Cart' is clicked → first, search for an existing CartItem where user = Current User AND product = Current cell's Product. If the search count > 0, use 'Make changes to a thing' on the first result to increment quantity by 1 and update line_total. If count = 0, use 'Create a new thing' (CartItem) with user = Current User, product = the product, quantity = 1, and line_total = product's price. Show a confirmation toast or animation.
Pro tip: Use 'Result of step X' references instead of re-searching for the CartItem. Also, add an 'Only when Current User is logged in' condition and redirect guests to login first, or use the anonymous cart approach covered in step 5.
Expected result: Clicking Add to Cart creates a new CartItem or increases quantity if the product is already in the cart.
Design the Cart Page with Quantity Controls
Design the Cart Page with Quantity Controls
Create a 'cart' page. Add a Repeating Group with Type of content 'CartItem' and data source 'Do a Search for CartItems (user = Current User)'. In each cell, display: the product image, product name, unit price, a quantity display with minus (-) and plus (+) buttons, the line total, and a Remove (X) button. For the plus button workflow: Make changes to Current cell's CartItem — set quantity to quantity + 1 and line_total to product's price * (quantity + 1). For minus: set quantity to quantity - 1, but add 'Only when quantity > 1'. For remove: Delete Current cell's CartItem.
Expected result: A cart page showing all items with working quantity adjustment buttons and a remove option.
Calculate and Display Cart Totals
Calculate and Display Cart Totals
Below the Repeating Group, add a summary section. Use dynamic text expressions: Subtotal = 'Do a Search for CartItems (user = Current User):each item's line_total:sum'. Tax = Subtotal * your tax rate (e.g., 0.08 for 8%). Total = Subtotal + Tax. Format all amounts as currency. Add an 'Items in cart' count using 'Do a Search for CartItems (user = Current User):count' — display this as a badge on a cart icon in your navigation bar for visibility across all pages.
Pro tip: For the nav cart badge, use a reusable element for your header and place the cart count as a dynamic text. It will auto-update across all pages since Bubble searches update in real time.
Expected result: Cart page shows subtotal, tax, and total that update automatically when items are added, changed, or removed.
Handle Guest User Carts with Custom States
Handle Guest User Carts with Custom States
For anonymous users who have not logged in, you cannot create database records linked to a User. Instead, use a Custom State on the page (or a reusable header element) of type 'list of CartItems'. When a guest clicks Add to Cart, create the CartItem without a user field and add it to the Custom State list. Display the Custom State list in the cart Repeating Group. When the guest signs up or logs in, create a workflow that iterates through the Custom State list and sets the user field to the newly logged-in user. Then clear the Custom State.
Expected result: Guest users can add items to a temporary cart that persists during their session and migrates to their account on login.
Add a Proceed to Checkout Button
Add a Proceed to Checkout Button
At the bottom of the cart page, add a 'Proceed to Checkout' button. The workflow should validate the cart: check that all products are still in stock (search for each CartItem's product and compare stock_quantity >= CartItem's quantity). If any item is out of stock, show an alert. If all items are available, navigate to the checkout page and pass the cart data. On the checkout page, collect shipping information and trigger the payment flow (Stripe Checkout or your payment provider).
Expected result: A checkout button that validates stock availability before proceeding to payment.
Complete working example
1DATA TYPES:2- Product3 - name (text)4 - price (number)5 - image (image)6 - stock_quantity (number)7 - description (text)89- CartItem10 - user (User)11 - product (Product)12 - quantity (number, default: 1)13 - line_total (number)1415PRIVACY RULES:16- CartItem: user = Current User (Find in searches, View all fields)1718PAGE: cart1920ELEMENTS:21- RepeatingGroup CartItems22 - Type: CartItem23 - Source: Search for CartItems (user = Current User)24 - Cell layout (Row):25 - Image: Current cell's CartItem's product's image26 - Text: product name27 - Text: unit price :formatted as $#,##0.0028 - Button "-" (decrease qty)29 - Text: quantity30 - Button "+" (increase qty)31 - Text: line_total :formatted as $#,##0.0032 - Button "X" (remove)3334- Group CartSummary35 - Text: "Subtotal: " & Search for CartItems:each item's line_total:sum :formatted36 - Text: "Tax (8%): " & (subtotal * 0.08) :formatted37 - Text: "Total: " & (subtotal * 1.08) :formatted (bold)38 - Text: Search for CartItems:count & " items"3940- Button "Proceed to Checkout"41- Group EmptyCart (visible when CartItems count = 0)42 - Text: "Your cart is empty"43 - Button: "Continue Shopping" → Go to products page4445WORKFLOWS:461. Add to Cart (on product page)47 → Search for CartItems (user=Current User, product=This Product)48 → If count > 0: Make changes to first result49 quantity = quantity + 1, line_total = product's price * (quantity + 1)50 → If count = 0: Create new CartItem51 user=Current User, product, quantity=1, line_total=product's price52532. Plus button clicked54 → Make changes to Current cell's CartItem55 quantity = quantity + 156 line_total = product's price * (quantity + 1)57583. Minus button clicked (Only when quantity > 1)59 → Make changes to Current cell's CartItem60 quantity = quantity - 161 line_total = product's price * (quantity - 1)62634. Remove button clicked64 → Delete Current cell's CartItem65665. Proceed to Checkout clicked67 → Validate stock for all items68 → If valid: Go to checkout page69 → If invalid: Show alert with out-of-stock itemsCommon mistakes when implementing a shopping cart in Bubble.io: Step-by-Step Guide
Why it's a problem: Recalculating line totals on the frontend instead of storing them
How to avoid: Store line_total as a field on CartItem and update it whenever quantity changes.
Why it's a problem: Not checking stock availability before checkout
How to avoid: Validate stock quantities in the checkout workflow and show clear error messages for out-of-stock items.
Why it's a problem: Allowing quantity to go below 1 with the minus button
How to avoid: Add 'Only when Current cell's CartItem's quantity > 1' to the minus button workflow. To remove entirely, use the separate Remove button.
Best practices
- Store line_total as a database field and update it with each quantity change to avoid repeated calculations.
- Show a cart item count badge in the navigation bar across all pages using a reusable header element.
- Add an empty cart state with a 'Continue Shopping' button for good UX.
- Validate product stock availability at checkout time, not just at add-to-cart time.
- Set Privacy Rules so users can only access their own CartItems.
- Handle edge cases: product price changes after being added to cart, product deletion while in cart.
- For high-traffic stores, clean up abandoned carts with a scheduled backend workflow that deletes CartItems older than 7 days.
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I'm building an e-commerce app in Bubble.io and need a shopping cart. I have a Product data type with name, price, image, and stock. I need add-to-cart, quantity adjustment, remove, and totals. How do I structure the CartItem data type and workflows?
Build a shopping cart system. Create a CartItem data type linked to User and Product. On product pages, add an Add to Cart button that creates or updates CartItems. Build a cart page with a Repeating Group showing items, quantity controls, line totals, and a cart summary with subtotal, tax, and total.
Frequently asked questions
Should I use a database or Custom States for the cart?
Use the database (CartItem data type) for logged-in users — it persists across sessions and devices. Use Custom States for guest users as a temporary solution, then migrate to database records on login.
How do I show the cart count in the navigation across all pages?
Create a reusable element for your navigation bar. Add a Text element with the dynamic value 'Do a Search for CartItems (user = Current User):count'. This auto-updates as items are added or removed.
What happens if a product price changes after it is in the cart?
Since line_total is stored as a field, it reflects the price at add time. Decide on your business logic: either update line totals when prices change (using a database trigger), or lock in the price at add-to-cart time.
How do I handle cart items for products that get deleted?
When deleting a product, first delete all associated CartItems, or soft-delete the product (mark as inactive). Add conditional formatting to show 'This product is no longer available' in the cart.
Can I add product variants (size, color) to the cart?
Yes. Create a ProductVariant data type linked to Product with fields for size, color, SKU, and price. Link CartItem to ProductVariant instead of (or in addition to) Product.
Is building a complete e-commerce checkout in Bubble complex?
A basic cart is straightforward, but full e-commerce (variants, shipping, tax rules, inventory management, order processing) gets complex. Teams like RapidDev specialize in building production-ready e-commerce systems in Bubble.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation