# How to build crowdfunding in Bubble

- Tool: Bubble
- Difficulty: Beginner
- Time required: 20-25 min
- Compatibility: All Bubble plans (Stripe required for payments)
- Last updated: March 2026

## TL;DR

Set up crowdfunding in Bubble by creating Campaign and Pledge data types, building campaign pages with progress bars and pledge tiers, implementing a pledge workflow with running totals, and adding deadline logic for all-or-nothing funding. This gives founders the tools to launch fundraising features without writing code.

## Overview: Setting Up Crowdfunding in Bubble

This tutorial walks you through building crowdfunding features in Bubble. You will create the data structure for campaigns and pledges, build campaign pages with goals, deadlines, and progress bars, set up pledge tier selection and payment, track pledged amounts in real time, and implement all-or-nothing vs. flexible funding models. This is ideal for platforms that host product launches, community projects, or creative endeavors.

## Before you start

- A Bubble account with an existing app
- Stripe plugin installed and configured for payments
- Basic understanding of Bubble data types and workflows
- Familiarity with Repeating Groups and conditional formatting

## Step-by-step guide

### 1. Create the Campaign and Pledge data types

Go to the Data tab and create a Campaign data type with fields: title (text), description (text), creator (User), goal_amount (number), amount_pledged (number, default 0), end_date (date), image (image), funding_type (Option Set: All-or-nothing, Flexible), and status (Option Set: Active, Funded, Failed, Closed). Then create a PledgeTier data type with fields: campaign (Campaign), name (text, e.g., Early Bird), amount (number), description (text), limit (number), and claimed_count (number, default 0). Finally, create a Pledge data type with fields: campaign (Campaign), backer (User), tier (PledgeTier), amount (number), and stripe_charge_id (text).

**Expected result:** Three data types exist: Campaign, PledgeTier, and Pledge with all required fields.

### 2. Build the campaign creation page

Create a page called create-campaign. Add input fields for title, description, goal amount, end date (Date Picker), and image (File Uploader). Add a Dropdown for funding type linked to the Option Set. Add a section for pledge tiers: a Repeating Group showing existing tiers with an Add Tier button that opens a popup form for tier name, amount, description, and limit. The workflow for saving: When Button Create Campaign is clicked — Create a new Campaign with all field values and creator = Current User. For tiers, create them in a separate workflow triggered by the Add Tier popup's save button.

**Expected result:** Creators can build a campaign with details, funding type, and multiple pledge tiers.

### 3. Design the campaign page with progress bar

Create a page called campaign with type Campaign. Display the image, title, description, creator name, end date, and funding type. For the progress bar, add two Groups: an outer Group with a fixed width and a colored background, and an inner Group whose width is set to a percentage: Current Page Campaign's amount_pledged / Current Page Campaign's goal_amount * 100 (capped at 100). Above the bar, display the amount pledged, the goal, and the percentage. Add a conditional: When Current date/time > Campaign's end_date, show Campaign Ended instead of the pledge section.

> Pro tip: Use a conditional max of 100 on the inner group width so the bar does not exceed the container when funding surpasses the goal.

**Expected result:** The campaign page shows a visual progress bar that fills as pledges come in, along with all campaign details.

### 4. Set up the pledge workflow with Stripe

Below the progress bar, add a Repeating Group showing PledgeTiers filtered by the current Campaign. Each cell shows the tier name, amount, description, remaining spots (limit minus claimed_count), and a Back This button. The workflow: When Back This is clicked — Only when Current date/time < Campaign's end_date and (tier's limit is empty or tier's claimed_count < tier's limit). Trigger Stripe Checkout with amount = tier's amount * 100. On payment success: Create a new Pledge with campaign, backer, tier, and amount. Then Make changes to Campaign: amount_pledged = amount_pledged + tier's amount. Make changes to PledgeTier: claimed_count = claimed_count + 1.

**Expected result:** Backers can select a tier, pay via Stripe, and the campaign's pledged amount and tier count update automatically.

### 5. Implement all-or-nothing deadline logic

Create a backend workflow called check_campaign_deadline with a parameter campaign_id (text). In it: Look up the Campaign by ID. If amount_pledged >= goal_amount, set status to Funded. If amount_pledged < goal_amount and funding_type is All-or-nothing, set status to Failed and trigger refund workflows for each Pledge. If funding_type is Flexible, set status to Funded regardless of amount. Schedule this backend workflow to run at each campaign's end_date using Schedule API workflow when the campaign is created.

> Pro tip: For the refund step in all-or-nothing campaigns, use the Stripe API Connector to call the refund endpoint with each pledge's stripe_charge_id.

**Expected result:** Campaigns automatically close at their deadline with the correct funded or failed status based on the funding type.

### 6. Add the backer dashboard and campaign listing

Create a my-pledges page showing a Repeating Group of Pledges where backer = Current User, displaying campaign title, tier, amount, and campaign status. Create a campaigns listing page showing all Active campaigns in a Repeating Group sorted by end_date ascending (ending soonest first). Add filter options for funding type and category. Each cell shows the image, title, progress percentage, amount pledged, and days remaining (calculated as Campaign's end_date minus Current date/time in days).

**Expected result:** Backers can view their pledge history, and visitors can browse all active campaigns with progress indicators.

## Complete code example

File: `Workflow summary`

```text
CROWDFUNDING FEATURE — WORKFLOW SUMMARY
========================================

DATA TYPES:
  Campaign
    - title (text)
    - description (text)
    - creator (User)
    - goal_amount (number)
    - amount_pledged (number, default 0)
    - end_date (date)
    - image (image)
    - funding_type (Option Set: All-or-nothing / Flexible)
    - status (Option Set: Active / Funded / Failed / Closed)

  PledgeTier
    - campaign (Campaign)
    - name (text)
    - amount (number)
    - description (text)
    - limit (number)
    - claimed_count (number, default 0)

  Pledge
    - campaign (Campaign)
    - backer (User)
    - tier (PledgeTier)
    - amount (number)
    - stripe_charge_id (text)

WORKFLOW 1: Create campaign
  Event: Button Create Campaign is clicked
  Action 1: Create new Campaign
    (all fields from form inputs)
    status = Active
  Action 2: Schedule API workflow check_campaign_deadline
    Scheduled date = Campaign's end_date
    campaign_id = Result of Step 1's unique ID

WORKFLOW 2: Back a campaign
  Event: Button Back This is clicked
  Only when: Current date/time < Campaign's end_date
    AND tier's claimed_count < tier's limit (or limit empty)
  Action 1: Stripe Checkout
    Amount = Current cell's PledgeTier's amount * 100
  On payment success:
  Action 2: Create new Pledge
    campaign = Current Page Campaign
    backer = Current User
    tier = Current cell's PledgeTier
    amount = tier's amount
    stripe_charge_id = Stripe charge ID
  Action 3: Make changes to Campaign
    amount_pledged = amount_pledged + tier's amount
  Action 4: Make changes to PledgeTier
    claimed_count = claimed_count + 1

BACKEND WORKFLOW: check_campaign_deadline
  Parameter: campaign_id (text)
  Step 1: Search for Campaign by ID
  Step 2 (funded): Make changes to Campaign
    Only when: amount_pledged >= goal_amount
    status = Funded
  Step 3 (failed — all-or-nothing): Make changes
    Only when: amount_pledged < goal_amount
      AND funding_type is All-or-nothing
    status = Failed
  Step 4 (refund): Schedule refund workflow on list
    Only when: status just set to Failed
    List = Search for Pledges (campaign = this campaign)
  Step 5 (flexible funded): Make changes
    Only when: funding_type is Flexible
    status = Funded

PROGRESS BAR:
  Outer Group: fixed width, light gray background
  Inner Group: width = (amount_pledged / goal_amount * 100)%
    Max width: 100%
    Background: green
```

## Common mistakes

- **Not updating the amount_pledged field atomically** — If two backers pledge simultaneously, both may read the same amount_pledged and overwrite each other, losing one pledge's amount Fix: Use the increment pattern: amount_pledged = amount_pledged + pledge amount. Bubble handles this server-side to minimize race conditions.
- **Allowing pledges after the campaign deadline** — Without a deadline check, users can pledge after the campaign has ended, which breaks the funding model Fix: Add Only when Current date/time < Campaign's end_date to the pledge workflow and hide the pledge buttons when the deadline has passed.
- **Forgetting to schedule the deadline check backend workflow** — Without it, campaigns never close automatically and remain in Active status indefinitely Fix: Schedule the check_campaign_deadline backend workflow at the campaign's end_date when the campaign is created.

## Best practices

- Use Option Sets for campaign status and funding type to keep values consistent
- Schedule a backend workflow at campaign creation time to handle deadline logic automatically
- Store stripe_charge_id on each Pledge so you can process refunds for failed all-or-nothing campaigns
- Cap the progress bar width at 100% so it does not overflow when campaigns exceed their goal
- Add tier limits and track claimed counts to create urgency for limited reward tiers
- Show days remaining as a countdown to create urgency on the campaign page
- Add Privacy Rules so backers can only view their own pledge details

## Frequently asked questions

### How do refunds work for failed all-or-nothing campaigns?

When the deadline check marks a campaign as Failed, a backend workflow iterates through all Pledges and calls the Stripe Refund API using each pledge's stripe_charge_id to return funds to backers.

### Can campaign creators edit their campaign after launching?

You can allow edits to description and image while the campaign is active. Do not allow changes to goal_amount or end_date after pledges have been received, as this could undermine backer trust.

### How do I display a countdown timer?

Calculate the remaining time as Campaign's end_date minus Current date/time and display it formatted as days, hours, and minutes. The value updates automatically because Current date/time is dynamic.

### Can I add stretch goals?

Yes. Create a StretchGoal data type linked to Campaign with a target_amount and reward_description. Display them on the campaign page with conditionals that highlight achieved stretch goals.

### Is Stripe required for crowdfunding?

Stripe is the most straightforward payment option in Bubble. You could use other gateways via the API Connector, but Stripe has the best plugin support and handles refunds easily.

### Can RapidDev help build a full crowdfunding platform?

Yes. RapidDev specializes in Bubble development and can help build complete crowdfunding platforms with advanced features like social sharing, backer updates, reward fulfillment tracking, and analytics dashboards.

---

Source: https://www.rapidevelopers.com/bubble-tutorial/set-up-a-crowdfunding-feature-in-bubble
© RapidDev — https://www.rapidevelopers.com/bubble-tutorial/set-up-a-crowdfunding-feature-in-bubble
