# How to create a video streaming platform in Bubble.io: Step-by-Step Guide

- Tool: Bubble
- Difficulty: Beginner
- Time required: 30-40 min
- Compatibility: All Bubble plans (paid plan recommended for custom domain and video hosting)
- Last updated: March 2026

## TL;DR

Build a video streaming platform in Bubble by embedding videos from Vimeo, YouTube, or Mux, organizing them into a content library with categories and playlists, and gating premium content behind subscription tiers. This tutorial covers the complete architecture from video embedding to monetization.

## Overview: Video Streaming Platform in Bubble

Building a video platform in Bubble means hosting videos on external services like Vimeo, YouTube, or Mux, then building the browsing, organization, and access control layers in Bubble. This tutorial covers creating a Netflix-style content library with categories, playlists, watch progress tracking, and premium content gating — all without writing code.

## Before you start

- A Bubble account with user authentication set up
- A video hosting account (Vimeo Pro, YouTube, or Mux)
- Videos uploaded to your hosting service
- Basic understanding of Data Types, Workflows, and Repeating Groups

## Step-by-step guide

### 1. Create the content data model

Go to Data tab and create these Data Types. 'Video': title (text), description (text), embed_url (text), thumbnail (image), duration (text), category (Option Set: Tutorial/Course/Webinar/Entertainment), is_premium (yes/no), order (number). 'Playlist': title (text), description (text), videos (list of Video), creator (User). 'WatchProgress': user (User), video (Video), watched_seconds (number), completed (yes/no). Create the Category Option Set with your content categories.

**Expected result:** Three Data Types and one Option Set are created for the video platform.

### 2. Build the video library browsing page

Create a 'library' page. Add a row of category filter buttons using a Repeating Group of Category options (horizontal layout). When a category is clicked, set a custom state 'selected_category' on the page. Below, add a Repeating Group with data source: Do a search for Video (constraint: category = selected_category, or no constraint if 'All' is selected), sorted by order. In each cell, display the thumbnail as an Image, title, duration, and a premium badge icon (conditional: visible when Video's is_premium is yes).

**Expected result:** A browsable video library with category filters and thumbnail grid showing all available content.

### 3. Create the video player page

Create a 'watch' page that receives a Video unique ID via URL parameter. Add an HTML element for the video embed. Set its content dynamically: for Vimeo, use an iframe with the embed URL from the Video record. For YouTube, use the standard YouTube embed format. Below the player, display the video title, description, and a Repeating Group showing related videos (same category, exclude current video). Add Previous and Next buttons that navigate to adjacent videos.

```
<iframe src="DYNAMIC_EMBED_URL" width="100%" height="500" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe>
```

**Expected result:** A video player page displays the selected video with description and related content.

### 4. Track watch progress for each user

When the watch page loads, search for an existing WatchProgress record (user = Current User, video = Current page's Video). If none exists, create one with watched_seconds = 0. To update progress, use a 'Do every X seconds' workflow event (set to every 30 seconds) that makes changes to the WatchProgress record, incrementing watched_seconds. When watched_seconds exceeds 90% of the video duration, set completed = yes. Display a progress bar on library thumbnails showing completion percentage.

**Expected result:** The system tracks how far each user has watched each video and shows progress on the library page.

### 5. Gate premium content behind subscriptions

Add a 'subscription_tier' field to the User data type (Option Set: Free/Basic/Premium). On the video player page, add a conditional: When Current page's Video's is_premium is yes AND Current User's subscription_tier is Free → hide the video player and show a 'Subscribe to Watch' message with a button linking to your pricing page. For the library, show a lock icon on premium video thumbnails when the user's tier does not grant access.

> Pro tip: Use privacy rules on the Video type to prevent the embed_url from being exposed to non-subscribers, even through the API.

**Expected result:** Free users see premium content thumbnails but cannot play the videos until they upgrade.

### 6. Build the playlist feature

Allow users to create playlists. Add a 'Create Playlist' button that opens a popup with a title input and a multi-select for videos. The workflow: Create Playlist → title, creator = Current User, videos = selected videos. On the library page, add a 'Add to Playlist' button on each video card. This opens a popup listing the user's playlists — clicking one adds the video: Make changes to Playlist → videos add Current cell's Video. Create a 'playlists' page showing the user's playlists with click-to-play functionality.

**Expected result:** Users can create, manage, and play playlists of their favorite videos.

## Complete code example

File: `Workflow summary`

```text
VIDEO STREAMING PLATFORM — ARCHITECTURE SUMMARY
=================================================

DATA TYPES:
  Video: title, description, embed_url, thumbnail, duration,
         category (Option Set), is_premium (yes/no), order (number)
  Playlist: title, description, videos (list of Video), creator (User)
  WatchProgress: user, video, watched_seconds, completed (yes/no)
  User (modified): + subscription_tier (Option Set: Free/Basic/Premium)

PAGES:
  library    — Video grid with category filters + search
  watch      — Video player + description + related videos
  playlists  — User's playlist list + playlist detail view
  pricing    — Subscription tier comparison + payment

KEY WORKFLOWS:
  Play Video: Navigate to watch page → load embed in HTML element
  Track Progress: Do every 30 seconds → update WatchProgress
  Mark Complete: When watched_seconds > 90% of duration → completed = yes
  Create Playlist: popup form → Create Playlist with selected videos
  Add to Playlist: Make changes to Playlist → videos add Video
  Gate Content: Conditional on watch page hides player for free users

PRIVACY RULES:
  Video embed_url: visible only when user's tier matches (or video is free)
  WatchProgress: visible only when user = Current User
  Playlist: visible to creator (private) or all users (if shared)

EMBED FORMATS:
  Vimeo: https://player.vimeo.com/video/{VIDEO_ID}
  YouTube: https://www.youtube.com/embed/{VIDEO_ID}
  Mux: https://stream.mux.com/{PLAYBACK_ID}.m3u8
```

## Common mistakes

- **Hosting videos directly in Bubble's file storage** — Bubble is not optimized for video delivery — files are served without adaptive bitrate streaming, causing buffering Fix: Always host videos on a dedicated service (Vimeo, Mux, YouTube) and embed them via URL in Bubble
- **Exposing embed_url in the API for premium content** — Users could extract the direct video URL and bypass your paywall entirely Fix: Add a privacy rule on Video that hides embed_url when the user's subscription tier does not have access
- **Not paginating the video library** — Loading 200+ video thumbnails at once causes slow page loads and high bandwidth usage Fix: Set the library Repeating Group to display 12-20 videos per page with pagination or infinite scroll

## Best practices

- Host videos on Vimeo Pro or Mux for adaptive bitrate streaming and analytics
- Use privacy rules to hide embed URLs from non-subscribers at the database level
- Paginate the video library to 12-20 items per page for fast loading
- Compress and optimize thumbnail images for quick library browsing
- Track watch progress to enable 'Continue Watching' recommendations
- Use Option Sets for categories to enable fast, WU-free filtering
- Add a search bar with title-based constraints for finding specific videos

## Frequently asked questions

### Can I use YouTube for free video hosting?

Yes, but YouTube adds its own branding and recommendations. For a branded experience without YouTube UI, use Vimeo Pro (hides branding) or Mux (developer-friendly, no UI overlay).

### How do I prevent users from sharing video links?

Use Vimeo's domain-level privacy (restrict embedding to your domain only) or Mux's signed URLs that expire. Combine with Bubble privacy rules that hide embed URLs from unauthorized users.

### Can I upload videos directly from Bubble?

Not recommended for streaming. You can upload files to Bubble's storage, but they will not have adaptive streaming. Use the Mux or Vimeo API via API Connector to upload directly from Bubble to a streaming service.

### How do I add subtitles to videos?

Upload subtitle files (SRT or VTT) to your video hosting service. Vimeo and Mux both support subtitle tracks that appear automatically in the embedded player.

### What video hosting service is best for Bubble?

Mux is the most developer-friendly with clean APIs. Vimeo Pro is easiest for non-technical users. YouTube is free but adds branding. Choose based on your budget and branding needs.

### Can RapidDev help build a video platform in Bubble?

Yes. RapidDev builds video platforms with advanced features like DRM protection, analytics dashboards, content recommendation engines, and multi-tier subscription management.

---

Source: https://www.rapidevelopers.com/bubble-tutorial/create-a-video-streaming-platform-in-bubble
© RapidDev — https://www.rapidevelopers.com/bubble-tutorial/create-a-video-streaming-platform-in-bubble
