# How to build a leaderboard in Bubble

- Tool: Bubble
- Difficulty: Beginner
- Time required: 15-20 min
- Compatibility: All Bubble plans
- Last updated: March 2026

## TL;DR

Build a leaderboard in Bubble by creating a Score data type, sorting users by points in a Repeating Group, calculating ranks with the :sorted and :item # operators, and adding time-based resets using scheduled backend workflows. This gives your app a competitive element that drives engagement without writing any code.

## Overview: Building a Leaderboard in Bubble

This tutorial walks you through building a leaderboard system in Bubble. You will create the data structure for tracking scores, display a ranked list of top users in a Repeating Group, add rank numbers, implement top-N filtering, and set up scheduled resets for time-based competitions. This is ideal for gamified apps, quiz platforms, or any app with competitive features.

## Before you start

- A Bubble account with an existing app
- A mechanism in your app that awards points (e.g., completing a quiz or task)
- Basic understanding of Bubble data types and Repeating Groups
- Familiarity with Bubble workflows

## Step-by-step guide

### 1. Create the Score data type

Go to the Data tab and click New type. Name it Score and add fields: user (type: User), points (type: number), period (text, e.g., 2026-W13 for week 13 or 2026-03 for March), and last_updated (date). Alternatively, you can add a total_points field directly on the User data type for a simpler approach. The separate Score type is better if you want time-based leaderboards with historical data.

> Pro tip: Using a period field lets you run weekly and monthly leaderboards simultaneously by filtering on different period formats.

**Expected result:** A Score data type exists with user, points, period, and last_updated fields.

### 2. Build the leaderboard Repeating Group

Go to the Design tab and create a new page called leaderboard. Click the + icon, search for Repeating Group, and drag it onto the page. Set the data type to Score and the data source to: Do a search for Scores where period = Current period value, sorted by points in descending order. Inside each cell, add Text elements to display: the user's name (Current cell's Score's user's name), the score (Current cell's Score's points), and a profile image if available.

**Expected result:** A Repeating Group displays scores sorted from highest to lowest for the current period.

### 3. Add rank numbers to each row

In each Repeating Group cell, add a Text element at the left side for the rank number. Set its content to: Current cell's index. This gives you 1, 2, 3, etc. based on the position in the sorted list. For visual emphasis, add conditionals: When Current cell's index is 1, change the background to gold. When Current cell's index is 2, change to silver. When Current cell's index is 3, change to bronze. Limit the Repeating Group to show the top 10 or 25 entries by setting the number of rows.

> Pro tip: For tie-breaking, add a secondary sort by last_updated (ascending) so the user who reached the score first ranks higher.

**Expected result:** Each leaderboard row shows a rank number (1, 2, 3...) with gold, silver, and bronze highlights for the top three.

### 4. Create the score update workflow

When a user earns points in your app (e.g., completes a quiz), add a workflow step to update their score. Search for an existing Score where user = Current User and period = the current period string. If it exists (count > 0), use Make changes to a thing to add the earned points to the existing record. If it does not exist (count is 0), Create a new Score with user = Current User, points = earned amount, and period = current period. Always set last_updated = Current date/time.

**Expected result:** User scores are created or incremented in the Score data type whenever they earn points.

### 5. Set up weekly or monthly resets with backend workflows

Go to the Workflow tab and access Backend workflows from the Pages dropdown. Create a backend workflow called reset_leaderboard. In Settings tab, go to API and enable Workflow API. The reset workflow does not need to delete old scores — since each Score has a period field, simply changing the current period value starts a fresh leaderboard. To calculate the current period, use Current date/time formatted as YYYY-[W]ww for weekly or YYYY-MM for monthly. Old periods remain in the database as historical records.

> Pro tip: Schedule the reset workflow to run at midnight on Monday (weekly) or the 1st of the month using the Schedule API workflow action with a calculated date.

**Expected result:** The leaderboard automatically starts fresh each week or month while preserving historical scores.

### 6. Add a current user highlight and personal rank

In the Repeating Group, add a conditional on each cell: When Current cell's Score's user is Current User, change the background color to a highlight color (e.g., light blue). Below or above the leaderboard, add a section showing the current user's rank. Display: Search for Scores (period = current, sorted by points descending):find this Score's index where this Score's user is Current User. Show their points and rank even if they are not in the top 10 visible list.

**Expected result:** The current user's row is highlighted in the leaderboard, and their rank and score are always visible even if they are not in the top entries.

## Complete code example

File: `Workflow summary`

```text
LEADERBOARD SYSTEM — WORKFLOW SUMMARY
======================================

DATA TYPES:
  Score
    - user (User)
    - points (number)
    - period (text)       — e.g. "2026-W13" or "2026-03"
    - last_updated (date)

OPTION SET: Leaderboard Period Type
  - Weekly  (format: YYYY-[W]ww)
  - Monthly (format: YYYY-MM)

PAGE: leaderboard
  Elements:
    - Dropdown: Period selector (This week / This month / All time)
    - Repeating Group (type: Score, rows: 10)
      Data source: Do a search for Scores
        period = Current period string
        Sort: points descending, last_updated ascending
      Cell contents:
        - Text: Current cell's index (rank)
        - Image: Current cell's Score's user's photo
        - Text: Current cell's Score's user's name
        - Text: Current cell's Score's points
    - Group: Current User Stats
      - Text: Your Rank — calculated index
      - Text: Your Points — current user's score

CONDITIONALS:
  Repeating Group cell:
    When Current cell's index is 1 → background gold
    When Current cell's index is 2 → background silver
    When Current cell's index is 3 → background bronze
    When Current cell's Score's user is Current User
      → background light blue

WORKFLOW 1: Award points
  Event: Quiz completed / Task finished
  Step 1: Search for Score
    (user = Current User, period = current period)
  Step 2 (Only when count > 0): Make changes
    points = existing points + earned points
    last_updated = Current date/time
  Step 3 (Only when count is 0): Create new Score
    user = Current User
    points = earned points
    period = current period string
    last_updated = Current date/time

WORKFLOW 2: Period calculation
  Weekly: Current date/time formatted as YYYY-[W]ww
  Monthly: Current date/time formatted as YYYY-MM
  All time: fixed string "all-time"

BACKEND WORKFLOW: archive_period (optional)
  Runs on schedule (Monday 00:00 or 1st of month)
  Step 1: Create LeaderboardArchive record
    period = previous period
    winner = top Score's user
    top_score = top Score's points
```

## Common mistakes

- **Deleting old scores when resetting the leaderboard** — Deleting data loses historical records. Users cannot see their past performance or verify past winners Fix: Use a period field on Score records so old periods are preserved. Filter the leaderboard by the current period to show fresh results.
- **Using a search inside each Repeating Group cell to calculate rank** — A search per cell multiplies database queries and workload units, making the leaderboard slow with many entries Fix: Use Current cell's index which gives the position in the already-sorted Repeating Group list without additional queries.
- **Not handling ties in the leaderboard** — Two users with the same score appear in an unpredictable order if there is no secondary sort Fix: Add a secondary sort by last_updated (ascending) so the user who reached the score first ranks higher.

## Best practices

- Use a period field on Score records to support weekly, monthly, and all-time leaderboards simultaneously
- Sort by points descending with a secondary sort by last_updated ascending for tie-breaking
- Limit the Repeating Group to 10-25 rows to keep page load fast
- Highlight the current user's row for quick identification
- Show the current user's rank separately so they can see their position even if outside the top entries
- Archive leaderboard winners at the end of each period for historical records
- Use conditionals to style the top three positions with gold, silver, and bronze colors

## Frequently asked questions

### Can I show an all-time leaderboard alongside weekly?

Yes. Create a separate Score record with period set to all-time that accumulates points across all periods. Display it in a second Repeating Group or toggle between views with a dropdown.

### How do I handle hundreds of users on the leaderboard?

Limit the displayed Repeating Group to the top 10-25. For the current user's rank, do a single search sorted by points and find their index. This keeps the page fast regardless of total user count.

### Can I add different leaderboard categories?

Yes. Add a category field (text or Option Set) to the Score data type and filter the Repeating Group by the selected category. This lets you run separate leaderboards for different activities.

### Will the leaderboard update in real time?

Yes. Bubble's database searches on page elements auto-update via WebSocket when data changes. New scores will appear on the leaderboard without a page refresh.

### How do I reset scores automatically?

You do not need to delete scores. Simply change the period value (e.g., from 2026-W12 to 2026-W13) and the leaderboard search automatically shows only the new period's results.

### Can RapidDev help build a gamification system?

Yes. RapidDev specializes in Bubble development and can help you build complete gamification systems including leaderboards, badges, streaks, achievements, and reward tiers.

### Should I store scores on the User data type or a separate Score type?

A separate Score type is better for time-based leaderboards because it preserves historical data. If you only need an all-time cumulative score, a field on the User type is simpler.

---

Source: https://www.rapidevelopers.com/bubble-tutorial/build-a-hiscores-leaderboard-in-bubble
© RapidDev — https://www.rapidevelopers.com/bubble-tutorial/build-a-hiscores-leaderboard-in-bubble
