# How to implement an audio player in Bubble.io: Step-by-Step Guide

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

## TL;DR

You can implement a custom audio player in Bubble using the HTML Audio element or a plugin like Audio Player by Zerocode. This tutorial covers adding play/pause/seek controls, building a progress bar, displaying track metadata, creating a playlist queue, and handling background playback — all through Bubble's visual editor with minimal custom code.

## Overview: Implementing an Audio Player in Bubble

This tutorial shows how to build a functional audio player in your Bubble app. Whether you are building a podcast app, music platform, or e-learning tool with audio lessons, you will learn to play audio files, build custom controls, display track information, and manage playlists. We use a combination of Bubble plugins and HTML elements to create a polished audio experience.

## Before you start

- A Bubble account with an app
- Audio files uploaded to Bubble's file manager or hosted externally
- Basic familiarity with Bubble plugins and Custom States
- Optional: an audio player plugin from the Bubble marketplace

## Step-by-step guide

### 1. Install an audio player plugin or set up HTML audio

Go to the Plugins tab and search for audio player. Install a plugin like Audio Player by Zeroqode or BDK Native Audio. If you prefer a code-free approach, you can use Bubble's HTML element with a standard HTML5 audio tag. For the plugin approach, install it and add the Audio Player element to your page from the Element Palette. For the HTML approach, add an HTML element and enter: <audio id='myPlayer' src='dynamic_url'></audio>. The plugin approach is recommended as it provides more control without writing code.

**Expected result:** An audio player element or HTML audio element is on your page ready for configuration.

### 2. Create the Track data type and configure the data source

Go to the Data tab and create a Track data type with fields: title (text), artist (text), album (text), duration (number in seconds), audio_file (file), cover_image (image), track_number (number), playlist (Playlist type if applicable). Upload your audio files via the File Manager or through the app's upload interface. On your player page, set the audio player's source to the current track's audio_file URL. Add a Custom State called current_track (type Track) on the page to track which song is playing.

**Expected result:** A Track data type stores audio metadata, and the player is connected to a track's audio file.

### 3. Build custom playback controls

Add visual elements for your player controls: a Play/Pause toggle button (use an Icon element that switches between play and pause icons based on a Custom State is_playing), Previous and Next buttons, and a volume slider (use a SliderInput element). Create workflows: When Play button is clicked → set is_playing state to yes and trigger the plugin's Play action. When Pause is clicked → set is_playing to no and trigger Pause. For volume, when the SliderInput value changes → set the player's volume. Style the controls in a horizontal row resembling a standard media player.

> Pro tip: Use Conditional formatting on the play/pause button: When is_playing is yes → show the pause icon. When is_playing is no → show the play icon.

**Expected result:** Play, pause, skip, and volume controls work and update their visual state in real time.

### 4. Add a progress bar with seek functionality

Add a Group element as the progress bar container (full width, 4-8px height, grey background). Inside it, add another Group as the progress fill (same height, colored background). Set the fill width dynamically using the plugin's current time / track duration * 100 percent. If using the HTML approach, use JavaScript to update a Custom State with the current playback time every second. For seek functionality, add a click event on the container Group: calculate the click position as a percentage of the bar width and set the player's current time to that percentage of the duration.

**Expected result:** A progress bar shows the current playback position and users can click to seek to any point in the track.

### 5. Display track metadata and album art

Above or below the controls, add display elements: an Image element bound to current_track's cover_image, a Text element for current_track's title (large, bold), a Text for current_track's artist, and time displays showing current time / total duration in MM:SS format. For the time format, use a text expression that converts seconds to minutes:seconds (e.g., floor(seconds/60):formatted as 0 + ':' + seconds mod 60:formatted as 00). Update these displays dynamically as the track changes.

**Expected result:** The player displays album art, track title, artist name, and current/total time for the playing track.

### 6. Create a playlist queue with navigation

Add a Repeating Group below or beside the player showing a list of Tracks. Highlight the currently playing track using a Conditional: When Current cell's Track is page's current_track → background color change. When a user clicks a track in the list, set current_track to the clicked track and start playback. For Next and Previous buttons, find the current track's position in the playlist and navigate to the next or previous item. Create a workflow: Get current_track's track_number, search for Track where track_number = current + 1 and playlist = current playlist. For more advanced audio features like streaming and DRM, RapidDev can assist with custom integrations.

**Expected result:** A playlist shows all tracks, highlights the current one, and next/previous buttons navigate through the queue.

## Complete code example

File: `Workflow summary`

```text
AUDIO PLAYER WORKFLOW SUMMARY
==============================

DATA TYPES:
  Track: title, artist, album, duration (seconds),
    audio_file, cover_image, track_number
  Playlist: name, tracks (list of Tracks), creator (User)

CUSTOM STATES (on page):
  current_track (Track)
  is_playing (yes/no)
  current_time (number)
  volume (number, default 80)

PAGE ELEMENTS:
  - Album art Image
  - Title and artist Text elements
  - Play/Pause button (icon toggles)
  - Previous / Next buttons
  - Progress bar (Group container + fill Group)
  - Time display (current / total)
  - Volume SliderInput
  - Playlist Repeating Group

WORKFLOW 1: Play/Pause Toggle
  Event: Button Play/Pause clicked
  If is_playing = no → Play audio, set is_playing = yes
  If is_playing = yes → Pause audio, set is_playing = no

WORKFLOW 2: Next Track
  Event: Button Next clicked
  1. Find Track where track_number = current + 1
  2. Set current_track = result
  3. Set audio source = new track's audio_file
  4. Play audio

WORKFLOW 3: Previous Track
  Same as Next but track_number = current - 1

WORKFLOW 4: Select from Playlist
  Event: Track in Repeating Group clicked
  1. Set current_track = clicked track
  2. Play audio

WORKFLOW 5: Seek
  Event: Progress bar Group clicked
  1. Calculate position = click X / bar width * duration
  2. Set audio current time = position

WORKFLOW 6: Volume Change
  Event: SliderInput value changed
  Action: Set audio volume = slider value / 100
```

## Common mistakes

- **Not handling autoplay browser restrictions** — Modern browsers block autoplay of audio without user interaction. Your player will not start automatically on page load. Fix: Always require a user click (play button) to initiate audio. Never assume audio will autoplay.
- **Using large uncompressed audio files** — Large files take long to load and buffer, especially on mobile connections, creating a poor user experience Fix: Compress audio files to MP3 at 128-192kbps before uploading. This balances quality with file size.
- **Not resetting the progress bar when changing tracks** — If you do not reset, the progress bar shows the previous track's position when a new track starts Fix: In the track change workflow, reset the current_time Custom State to 0 and update the progress bar before starting playback.

## Best practices

- Use MP3 format for broad browser compatibility
- Compress audio to 128-192kbps for web delivery
- Always require user interaction before playing audio (browser autoplay policy)
- Reset progress bar and time display when changing tracks
- Highlight the currently playing track in the playlist
- Add keyboard shortcuts (space for play/pause) for better accessibility
- Show a loading state while audio buffers

## Frequently asked questions

### Which audio formats does Bubble support?

Bubble can store any file type. For playback, use MP3 for broadest browser compatibility. WAV and OGG also work in most modern browsers. Avoid FLAC for web playback.

### Can I stream audio instead of downloading the full file?

HTML5 audio elements stream by default — they begin playback before the full file is downloaded. For very large files, ensure your audio is served with proper HTTP range headers.

### Does the player keep playing when navigating to another page?

No. Navigating to a new page stops playback. To maintain playback across pages, place the player in a Reusable Element (Floating Group) that persists across page changes, or use a single-page app architecture.

### Can I add playback speed control?

Yes. HTML5 audio supports playback rate changes. Use a JavaScript action or plugin setting to adjust the playbackRate property (0.5x, 1x, 1.5x, 2x).

### How do I handle audio file storage limits?

Bubble's free plan includes 0.5GB storage. Audio files can be large — a 5-minute MP3 at 192kbps is about 7MB. For apps with many tracks, consider hosting audio on an external CDN like Cloudflare R2 or AWS S3.

### Can RapidDev help build advanced audio features?

Yes. RapidDev can help implement features like waveform visualization, audio recording, real-time streaming, transcription, and integration with music distribution APIs.

---

Source: https://www.rapidevelopers.com/bubble-tutorial/implement-an-audio-player-in-bubble
© RapidDev — https://www.rapidevelopers.com/bubble-tutorial/implement-an-audio-player-in-bubble
