Skip to main content
RapidDev - Software Development Agency
bubble-tutorial

How to display dynamic ads in Bubble.io: Step-by-Step Guide

Build a dynamic ad display system in Bubble by creating an Ad Data Type that stores creatives, targeting rules, and schedule dates. Use conditional searches to rotate ads based on page context or user demographics, track impressions and clicks with workflow counters, and build an advertiser dashboard for managing campaigns — all without writing code.

What you'll learn

  • How to create a data model for storing and managing ad campaigns
  • How to display ads dynamically based on targeting rules and rotation logic
  • How to track ad impressions and clicks with Bubble workflows
  • How to build a basic advertiser dashboard for campaign management
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner7 min read20-25 minAll Bubble plansMarch 2026RapidDev Engineering Team
TL;DR

Build a dynamic ad display system in Bubble by creating an Ad Data Type that stores creatives, targeting rules, and schedule dates. Use conditional searches to rotate ads based on page context or user demographics, track impressions and clicks with workflow counters, and build an advertiser dashboard for managing campaigns — all without writing code.

Displaying Dynamic Ads in Your Bubble App

Whether you are building a content platform, a marketplace, or a community app, displaying ads is a common monetization strategy. This tutorial shows you how to build your own ad system in Bubble — storing ad creatives in the database, rotating them based on rules, tracking performance metrics, and giving advertisers a management interface. This is an alternative to embedding third-party ad networks like Google AdSense.

Prerequisites

  • A Bubble account with an app open in the editor
  • User authentication set up for advertisers and admins
  • Basic understanding of Data Types, searches, and workflows

Step-by-step guide

1

Create the Ad and Campaign Data Types

Go to Data tab → Data types. Create 'AdCampaign' with fields: name (text), advertiser (User), start_date (date), end_date (date), budget (number), status (text: active/paused/ended), target_category (text). Create 'Ad' with fields: campaign (AdCampaign), image (image), headline (text), destination_url (text), placement (text: banner/sidebar/inline), impressions (number, default 0), clicks (number, default 0), is_active (yes/no).

Expected result: Two Data Types (AdCampaign and Ad) are created with fields for targeting, tracking, and management.

2

Build the ad display element on content pages

On the page where you want ads to appear, add a Group element sized for your ad placement (e.g., 728x90 for a banner). Set the Group's Type of content to 'Ad' and its Data source to: 'Do a search for Ads' with constraints: is_active = yes, placement = 'banner', and campaign's status = 'active', campaign's start_date <= Current date/time, campaign's end_date >= Current date/time. Add ':random item' at the end to select a random ad from eligible ones. Inside the group, add an Image element showing 'Parent group's Ad's image' and a Text element for the headline.

Pro tip: Use ':random item' for simple rotation. For weighted rotation based on budget, add a 'priority' number field and sort by it descending, then take the first item.

Expected result: A random active ad appears in the banner slot, respecting date ranges and status filters.

3

Track impressions when ads are displayed

Add a 'Page is loaded' workflow (or a 'Do when condition is true' event that fires when the ad group's data source is not empty). In this workflow, add the action: 'Make changes to a thing' → Thing to change: the ad group's data source (the Ad displayed) → impressions = impressions + 1. This increments the impression counter each time the ad is shown to a user. To avoid counting the same user twice per session, add a custom state 'impression_tracked' (yes/no) and check it in the Only when condition.

Expected result: Each time an ad is displayed to a user, its impression count increases by one.

4

Track clicks when users interact with ads

Make the ad group clickable by adding a workflow: 'When Group Ad is clicked.' In this workflow, add two actions in order: (1) Make changes to Parent group's Ad → clicks = clicks + 1, (2) Open an external website → URL = Parent group's Ad's destination_url. This records the click and then sends the user to the advertiser's landing page. The click-through rate (CTR) can be calculated as clicks / impressions in your reporting.

Expected result: Clicking an ad increments its click counter and redirects the user to the advertiser's destination URL.

5

Build a basic advertiser dashboard

Create a page called 'advertiser-dashboard.' Add a Repeating Group with Type 'AdCampaign' and Data source: 'Do a search for AdCampaigns where advertiser = Current User.' Each cell shows: campaign name, status, start/end dates, and aggregate metrics. For metrics, add Text elements showing: 'Do a search for Ads where campaign = Current cell's AdCampaign:each item's impressions:sum' for total impressions and similar for clicks. Add buttons for 'Pause Campaign' (Make changes → status = 'paused') and 'Edit Campaign.'

Expected result: Advertisers see all their campaigns with performance metrics and can pause or manage them.

6

Add category-based ad targeting

To show relevant ads based on page content, pass a category context to your ad search. On a blog post page, for example, the post has a category field. Update your ad search constraint to include: target_category = Current Page Post's category (or target_category is empty for untargeted ads). Use 'Ignore empty constraints' if you want ads with no target_category to show everywhere. This ensures software ads appear on tech articles and food ads appear on recipe pages.

Expected result: Ads are filtered by category relevance, showing targeted ads on matching content pages and general ads elsewhere.

Complete working example

Workflow summary
1DYNAMIC AD SYSTEM DATA MODEL & WORKFLOWS
2=============================================
3
4Data Types:
5 AdCampaign: name, advertiser (User), start_date, end_date,
6 budget, status (active/paused/ended), target_category
7 Ad: campaign (AdCampaign), image, headline, destination_url,
8 placement (banner/sidebar/inline), impressions (number),
9 clicks (number), is_active (yes/no)
10
11Ad Display Logic:
12 Group Ad Banner (728x90)
13 Type: Ad
14 Data source: Search Ads where
15 is_active = yes
16 placement = 'banner'
17 campaign's status = 'active'
18 campaign's start_date <= now
19 campaign's end_date >= now
20 campaign's target_category = page context category
21 :random item
22
23Impression Tracking:
24 Trigger: Page is loaded (or Do when ad group data is not empty)
25 Only when: page's impression_tracked is no
26 Action 1: Make changes to Group Ad's Ad impressions + 1
27 Action 2: Set state impression_tracked = yes
28
29Click Tracking:
30 Trigger: When Group Ad is clicked
31 Action 1: Make changes to Group Ad's Ad clicks + 1
32 Action 2: Open external website Ad's destination_url
33
34Advertiser Dashboard:
35 Page: advertiser-dashboard
36 RG: AdCampaigns where advertiser = Current User
37 Metrics: sum of impressions, sum of clicks per campaign
38 Actions: Pause/Resume campaign, Edit ads, View stats
39
40Admin Review:
41 Page: admin-ads
42 RG: All AdCampaigns sorted by creation date
43 Actions: Approve/Reject campaigns, Flag policy violations

Common mistakes when displaying dynamic ads in Bubble.io: Step-by-Step Guide

Why it's a problem: Not filtering ads by date range

How to avoid: Always include date constraints in your ad search: start_date <= Current date/time AND end_date >= Current date/time.

Why it's a problem: Counting impressions on every page reload for the same user

How to avoid: Use a custom state or session cookie check to track whether the impression has already been counted in the current session.

Why it's a problem: Opening the destination URL without recording the click first

How to avoid: Place the 'Make changes to Ad' action before the 'Open external website' action in the workflow sequence.

Best practices

  • Always filter ads by active status, date range, and placement to show only relevant, current ads
  • Track both impressions and clicks to calculate click-through rates for advertisers
  • Use ':random item' for simple ad rotation or a priority field for weighted display
  • Implement session-based impression deduplication to avoid inflating metrics
  • Give advertisers a self-service dashboard to manage campaigns and view performance
  • Add admin approval workflows so ads are reviewed before going live
  • Use category targeting to show relevant ads based on page content context

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I want to build a dynamic ad display system in Bubble.io. How do I create Data Types for campaigns and ads, display rotating ads based on targeting rules, track impressions and clicks, and build an advertiser dashboard?

Bubble Prompt

Build an ad management system. Create AdCampaign and Ad data types with targeting and tracking fields. Display random active ads on content pages filtered by placement and date. Track impressions on page load and clicks when the ad is clicked. Build an advertiser dashboard showing campaign performance metrics.

Frequently asked questions

Should I build my own ad system or use Google AdSense?

Build your own if you want to sell ad space directly to advertisers and keep 100% of revenue. Use AdSense if you want automated ad filling without managing advertiser relationships. Many apps use both.

How do I prevent the same ad from showing repeatedly?

Store recently shown ad IDs in a custom state list. Add a constraint to your ad search: unique id is not in page's shown_ads list. After displaying an ad, add its ID to the list.

Can I charge advertisers based on impressions or clicks?

Yes. With impression and click tracking built in, you can calculate costs as cost-per-thousand-impressions (CPM) or cost-per-click (CPC). Deduct from the campaign budget accordingly using a backend workflow.

How do I handle ad-blockers?

Since your ads are served from Bubble's own database (not an external ad network), most ad-blockers will not detect them. Your custom ad system is inherently ad-blocker resistant.

Can I display video ads?

Yes. Add a 'video_url' field to the Ad Data Type and use a Video element or HTML5 video tag in the ad group. Set it to autoplay (muted) for a richer ad experience.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.