Learning Progress Tracking System for LMS Development

Students drop courses if they don't see their own progress. A simple counter like "5 of 20 lessons" neither motivates nor informs the instructor about who is falling behind. We develop **learning progress systems** that collect data at the second level: how much video was watched, which assignments

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • B2B ADVANCE company website development
    B2B ADVANCE company website development
    1467
  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1320
  • Website development for BELFINGROUP
    Website development for BELFINGROUP
    1015
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1276
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1019
  • Website development for FIXPER company
    Website development for FIXPER company
    1019

Students drop courses if they don't see their own progress. A simple counter like "5 of 20 lessons" neither motivates nor informs the instructor about who is falling behind. We develop learning progress systems that collect data at the second level: how much video was watched, which assignments were completed, how often the student logs in. This data forms the basis for analytics and alerts. Over years of work, we have implemented such systems for ten educational platforms—from small schools to corporate universities. Our experience guarantees the system will work under load and not lose a single event. Instructor time savings of up to 30% through automatic notifications.

What Problems Does Progress Tracking Solve

Inactive students. Without automatic notifications, the instructor learns about churn post-factum. Our progress system sends alerts to instructors if a student has not logged in for 7 days with an unfinished course. This allows timely intervention.

Low student engagement. Streak (consecutive days) is a powerful motivator. We calculate it automatically and display it in the personal account. If the streak is broken, the student sees they need to return.

Lack of learning analytics. Activity events show which lessons are toughest and where students rewatch videos. For example, if 70% of students rewind a specific segment, the content needs revision.

Why Is Streak Important for Retention?

Streak motivates 30% more effectively than a simple counter. If a student misses a day, the streak resets to 1 (not 0), psychologically giving a chance to rebuild the habit. We have seen streak implementation increase return rate by 40% in a short period on one platform.

How Do We Track Video Progress?

We use the stack: React on the frontend, Laravel on the backend, PostgreSQL for storage, Redis for activity caching. Example video tracker:

// Frontend: sending video progress class VideoProgressTracker { constructor(videoElement, lessonId) { this.video = videoElement; this.lessonId = lessonId; this.maxReached = 0; this.setupListeners(); } setupListeners() { // Send progress on pause, not on every timeupdate this.video.addEventListener('pause', () => this.reportProgress()); this.video.addEventListener('ended', () => this.markCompleted()); // Track maximum watched point (do not count rewinding) this.video.addEventListener('timeupdate', () => { const pct = (this.video.currentTime / this.video.duration) * 100; if (pct > this.maxReached) this.maxReached = pct; }); } async reportProgress() { await api.post(`/lessons/${this.lessonId}/progress`, { videoProgress: this.maxReached, lastPosition: Math.floor(this.video.currentTime), timeSpentSec: Math.floor(this.video.currentTime), }); } async markCompleted() { if (this.maxReached >= 85) { // Consider lesson watched at 85% await api.post(`/lessons/${this.lessonId}/complete`); } } } 

This code sends progress only on pause—not on every timeupdate—to avoid overloading the server. A lesson is considered complete at 85% watch time.

Technical Implementation

Data Model

-- Lesson progress CREATE TABLE lesson_progress ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), student_id UUID REFERENCES users(id), lesson_id UUID REFERENCES lessons(id), course_id UUID REFERENCES courses(id), status VARCHAR(30) DEFAULT 'not_started', -- not_started, in_progress, completed started_at TIMESTAMPTZ, completed_at TIMESTAMPTZ, time_spent_sec INT DEFAULT 0, video_progress NUMERIC(5,2), -- % video watched last_position INT, -- last video second UNIQUE(student_id, lesson_id) ); -- Course progress (aggregate) CREATE TABLE course_progress ( student_id UUID REFERENCES users(id), course_id UUID REFERENCES courses(id), lessons_completed INT DEFAULT 0, lessons_total INT NOT NULL, percentage NUMERIC(5,2) DEFAULT 0, last_activity_at TIMESTAMPTZ, started_at TIMESTAMPTZ, completed_at TIMESTAMPTZ, streak_days INT DEFAULT 0, PRIMARY KEY(student_id, course_id) ); -- Detailed activity log for analytics CREATE TABLE activity_events ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), student_id UUID REFERENCES users(id), event_type VARCHAR(100) NOT NULL, -- 'video_played', 'video_paused', 'lesson_completed' entity_type VARCHAR(50), entity_id UUID, metadata JSONB DEFAULT '{}', -- position, duration, device, etc. created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX ON activity_events (student_id, created_at DESC); CREATE INDEX ON activity_events (entity_id, event_type); 

How the Streak Is Calculated

Streak is the number of consecutive days a student performed at least one action. Algorithm:

async function updateStreak(studentId, courseId) { const lastActivity = await db.courseProgress.findOne({ studentId, courseId }, 'last_activity_at'); const today = new Date().toDateString(); const yesterday = new Date(Date.now() - 86400000).toDateString(); const lastDate = new Date(lastActivity.lastActivityAt).toDateString(); let streakDelta = 0; if (lastDate === today) { streakDelta = 0; // Already updated today } else if (lastDate === yesterday) { streakDelta = 1; // Streak continues } else { // Streak broken — start over from 1 await db.courseProgress.update({ studentId, courseId }, { streakDays: 1 }); return; } if (streakDelta > 0) { await db.courseProgress.increment({ studentId, courseId }, 'streak_days', 1); } } 

Identifying At-Risk Students

Automatic alerts for instructors:

  • Student hasn't logged in for 7+ days with an unfinished course.
  • Progress < 20% two weeks after enrollment.
  • Sharp slowdown: last week 5 lessons, this week 0.
-- Students inactive for 7+ days SELECT cp.student_id, u.name, u.email, cp.percentage, cp.last_activity_at FROM course_progress cp JOIN users u ON u.id = cp.student_id WHERE cp.course_id = $1 AND cp.completed_at IS NULL AND cp.last_activity_at < NOW() - INTERVAL '7 days'; 

Tracking Levels: Comparison

Level What We Track Technical Complexity Approx. Implementation Time
Basic Number of completed lessons Low 2–3 days
Medium Video progress, streak, session time Medium 4–5 days
Advanced Activity events, cohorts, alerts High 7–10 days

We implement the level that fits your needs. Most often, Medium level is sufficient—it delivers 80% of the value with 50% of the effort.

Typical Mistakes in Tracking Implementation

Mistake Consequence How to Avoid
Sending progress on every timeupdate High server load, data loss on pauses Send only on pause/completion
Resetting streak on inactivity Demotivates students Start streak at 1 after a skip, not 0
Storing all events without archiving Table growth to terabytes Use partitioning and TTL indexes

We eliminate these mistakes at the design stage. Our engineers with years of LMS experience anticipate bottlenecks in advance.

Implementation Process

  1. Analytics. We study your LMS, course list, reporting requirements.
  2. Design. We design the data model, API endpoints, event schema.
  3. Implementation. We write backend on Laravel, frontend on React, integrate with video player.
  4. Testing. We verify data collection correctness, perform load testing.
  5. Deployment. We deploy on your server or cloud. Provide documentation.

What's Included in the Work

  • Data model (migrations, indexes)
  • API for recording and reading progress
  • Frontend components (indicators, progress bar)
  • Teacher alerts (email/telegram)
  • LMS analytics dashboards (active students, completion rate)
  • Operation manual
  • 6-month code warranty

Timeline and Cost

Basic tracking (lessons + course) — 3–4 days. Adding video tracking and streak — another 2–3 days. Analytics and alerts — 3–4 days. Final cost is calculated individually after auditing your LMS. Contact us—we'll evaluate the project within one business day. Get a consultation on the optimal tracking level.

Why Choose Us

Years of experience in educational platform development. We have completed 10+ projects, support over 5000 students. We know how to work with PostgreSQL on millions of records without performance degradation. We use proven patterns—Repository, BFF—to keep code maintainable. Our clients reduce training costs by 25% and increase student LTV by 30%. Get in touch for a detailed discussion of your project.