A learning management system in Bubble requires Data Types for courses, modules, lessons, quizzes, enrollments, and progress tracking. This tutorial covers the complete LMS architecture from course creation to student enrollment, lesson delivery with video hosting, progress tracking, and certificate generation.
Overview: Building a Learning Management System in Bubble
An LMS is a complex but highly valuable application — and one of Bubble's strongest use cases given its data-rich, multi-role nature. This tutorial walks you through building a complete LMS with course management, student enrollment, lesson delivery, progress tracking, quizzes, and certificates.
Prerequisites
- A Bubble app on Growth plan or above
- Basic experience with Data Types, workflows, and Repeating Groups
- A video hosting service account (YouTube, Vimeo, or Loom)
Step-by-step guide
Design the LMS data structure
Design the LMS data structure
Create these Data Types. Course: title (text), description (text), instructor (User), thumbnail (image), price (number), published (yes/no), category (Option Set). Module: course (Course), title (text), order (number). Lesson: module (Module), title (text), content (text — rich text HTML), video_url (text), order (number), duration_minutes (number). Enrollment: course (Course), student (User), enrolled_date (date), completed (yes/no), completion_date (date). LessonProgress: enrollment (Enrollment), lesson (Lesson), completed (yes/no), completed_date (date).
Expected result: A hierarchical data structure: Course → Modules → Lessons with enrollment and progress tracking.
Build the course catalog and enrollment flow
Build the course catalog and enrollment flow
Create a courses page with a Repeating Group showing published courses. Each cell displays the thumbnail, title, instructor name, price, and an Enroll button. The Enroll button workflow creates an Enrollment record linking the current user to the course. For paid courses, redirect to Stripe Checkout first, then create the enrollment on successful payment via a webhook.
Expected result: Students can browse courses and enroll for free or paid access.
Create the course player with lesson navigation
Create the course player with lesson navigation
Create a page called course-player with page type Course. Show a sidebar with all Modules (Repeating Group sorted by order) and nested Lessons within each module. The main content area shows the current lesson — embed the video using an HTML element with an iframe pointing to the video_url, and display the lesson content below using an HTML element for rich text. Use a custom state to track the current lesson.
Pro tip: Use a Group with type Lesson to display the current lesson content, and update it by changing the data source when the user clicks a lesson in the sidebar.
Expected result: A course player with lesson navigation sidebar and main content area showing video and text.
Track lesson progress and course completion
Track lesson progress and course completion
When a student finishes a lesson (clicks a Mark as Complete button or watches the video to the end), create a LessonProgress record with completed = yes. After marking a lesson complete, check if all lessons in the course have progress records — if so, update the Enrollment to completed = yes and set the completion_date. Display progress visually using a progress bar (completed lessons / total lessons * 100).
Expected result: Student progress is tracked per lesson, and course completion is detected automatically.
Generate completion certificates
Generate completion certificates
When an enrollment is marked as completed, create a certificate page that displays the student name, course title, completion date, and instructor name in a styled layout. Use the page as a printable certificate by styling it with a border, certificate-style fonts, and the course branding. Add a Print button that triggers window.print() via a Run JavaScript action. Alternatively, use a PDF generation plugin to create downloadable certificates.
Expected result: Students receive a printable or downloadable certificate upon course completion.
Complete working example
1LMS ARCHITECTURE SUMMARY2=========================34DATA TYPES:5 Course: title, description, instructor (User), thumbnail, price, published, category6 Module: course (Course), title, order (number)7 Lesson: module (Module), title, content (rich text), video_url, order, duration_minutes8 Enrollment: course (Course), student (User), enrolled_date, completed (yes/no), completion_date9 LessonProgress: enrollment (Enrollment), lesson (Lesson), completed, completed_date10 Certificate: enrollment (Enrollment), issued_date, certificate_id (text)1112PAGES:13 courses — catalog with enrollment14 course-player (type: Course) — lesson viewer with sidebar nav15 certificate (type: Enrollment) — printable certificate16 instructor-dashboard — create/manage courses1718ENROLLMENT WORKFLOW:19 Free: Create Enrollment (student=Current User, course, enrolled_date=now)20 Paid: Stripe Checkout → on success webhook → Create Enrollment2122LESSON PROGRESS:23 Mark Complete button:24 1. Create LessonProgress (enrollment, lesson, completed=yes)25 2. Check: Search LessonProgress (enrollment, completed=yes) count26 = Search Lessons (course) count?27 3. If yes → Make Changes to Enrollment: completed=yes, completion_date=now28 4. If yes → Create Certificate2930PROGRESS BAR:31 Width: (completed lessons / total lessons * 100)%32 Text: "X of Y lessons completed"3334SIDEBAR NAVIGATION:35 RG Modules (course, sorted by order):36 Nested RG Lessons (module, sorted by order):37 Conditional: green checkmark when LessonProgress exists and completed=yes38 Click → Set state: current_lesson = This LessonCommon mistakes when building a learning management system in Bubble.io: Step-by-Step Guide
Why it's a problem: Not nesting modules and lessons properly in the data structure
How to avoid: Use separate Data Types for Course, Module, and Lesson with parent references, and sort by an order field
Why it's a problem: Tracking completion at the course level only
How to avoid: Create a LessonProgress record for each completed lesson so students can track their progress and resume
Why it's a problem: Hosting videos directly in Bubble
How to avoid: Host videos on YouTube (unlisted), Vimeo, or Loom and embed them via iframe in an HTML element
Best practices
- Use a hierarchical data structure: Course → Module → Lesson for clear organization
- Track progress at the lesson level for accurate completion tracking
- Host videos externally (YouTube, Vimeo) and embed via iframe to save storage
- Sort modules and lessons by an order field for consistent navigation
- Add a progress bar showing percentage completion on the course player page
- Generate certificates automatically when all lessons are marked complete
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I want to build a learning management system in Bubble.io with courses, modules, lessons, video content, progress tracking, and completion certificates. Can you outline the complete data structure and key workflows?
Build an LMS for my app. I need courses with modules and lessons, student enrollment, video lesson delivery, progress tracking per lesson, and automatic certificate generation on course completion.
Frequently asked questions
How do I embed videos from YouTube or Vimeo?
Add an HTML element and paste an iframe tag: <iframe src="https://www.youtube.com/embed/VIDEO_ID" width="100%" height="400" frameborder="0" allowfullscreen></iframe>. Make the src dynamic using the lesson's video_url field.
Can I restrict access to paid course content?
Yes. On the course player page, check if the current user has an Enrollment for the course. If not, redirect to the enrollment page or show a paywall message.
How do I handle multiple instructors?
Add an instructors field (list of Users) to the Course Data Type. Use Privacy Rules to give instructors edit access only to their own courses.
Can students leave reviews?
Yes. Create a Review Data Type with course (Course), student (User), rating (number), comment (text). Display reviews on the course catalog page.
Is Bubble suitable for a large-scale LMS?
For small to medium platforms (hundreds to low thousands of students), yes. For enterprise LMS with thousands of concurrent users, advanced reporting, and SCORM compliance, you may need hybrid architecture. RapidDev can help build and scale LMS platforms in Bubble.
Can I add downloadable resources to lessons?
Yes. Add a resources field (file, list) to the Lesson Data Type. Display download links below the lesson content using a Repeating Group of the resource list.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation