LMS migration engineering insights
How We Migrated 691 Videos from Thinkific to S3 Without Vimeo
Thinkific's GraphQL API exposes direct MP4 CDN URLs through VideoContent types. Here's how we used that to bypass Vimeo entirely and migrate 691 course videos to self-hosted S3 with CloudFront delivery.
The Enrollment Bug That Almost Ruined Our Migration
Thinkific's REST API returns all enrollments for users in a queried course — not just enrollments for that specific course. We discovered this cross-contamination bug affecting 1,439 records across 13 courses.
Why Vimeo Upload Quotas Make S3 the Better Choice for Course Videos
At $65/month, Vimeo Advanced limits you to 240 video uploads per year per seat. With 1,000+ course videos, that's nearly two years of uploading. S3 has no upload limits and costs a fraction per GB.
Video Protection Without DRM: A Layered Approach for Course Creators
Full DRM is overkill for educational content. Here's our layered stack: S3 bucket policies with referrer restrictions, HTML5 controlsList attributes, CloudFront signed cookies, and player-level hardening.
WordPress Hook Suspension: Why LearnDash Imports Crash and How to Fix It
LearnDash and BuddyBoss hooks trigger template rendering during CLI bulk post creation, crashing the import process. The fix: suspend dangerous hooks during import with targeted hook removal and restoration.
Does LearnWorlds Have an API Good Enough for Migration?
LearnWorlds provides a REST v2 API with OAuth2 covering courses, users, enrollments, progress, assessments, and certifications across 15+ endpoint categories — comparable to Thinkific's API depth.
Why API-Driven Migration Beats Scraping, CSV, and Manual Rebuild
There are four ways to migrate an LMS: manual rebuild, CSV export/import, web scraping, and API-driven extraction. Only one preserves 100% of your data with zero guesswork. Here's why.
Quizzes Are a Lesson Type in Thinkific. They're Not in LearnDash. Here's How We Bridge It.
In Thinkific a quiz is a lesson — `lessonType: QUIZ` sitting alongside videos and PDFs in a chapter. In LearnDash, sfwd-quiz is a separate post type. The mismatch is the single most consequential design decision in any Thinkific-to-LearnDash migration.
Thinkific GraphQL Rate Limits: A Field Guide to Cost Budgets
Thinkific's GraphQL API has two ceilings that aren't documented prominently: 1000 cost units per query and 2000 cost units per minute. Hit either and you get RATE_LIMITED or MAX_QUERY_COST_EXCEEDED. Here's how the numbers actually behave and what to do about them.
Thinkific Has Two APIs. Here's What's in Each One.
Thinkific exposes both a REST API and a GraphQL API. Most exporters use one or the other and lose information. A complete migration uses both — REST for enrollments and custom fields, GraphQL for course structure and quizzes.
Stop Calling It 'Protected PDF.' Here's What's Actually Possible in the Browser.
You can't prevent a logged-in student from saving a PDF they're allowed to view. What you can do is raise the cost of casual copying enough that it stops happening — and stop selling clients on protection you can't deliver.
Why We Built a Re-Runnable LMS Exporter (And Why You Should Too)
Every migration we've inherited from another vendor has had the same bug: it was a one-shot script. The source platform kept selling courses during the migration window and 200 last-minute purchases got dropped. Idempotency is the cheapest insurance you can write.
Mapping Thinkific Users to WordPress When You Already Have a User Base
If WordPress already has users — newsletter subscribers, blog commenters, old students — you can't just bulk-insert Thinkific users. Email collisions are the rule, not the exception. Here's the merge policy we use.
Bundling PDF.js in a WordPress Plugin (Without a CDN)
Why Composer isn't the right tool, why CDNs are out for clients with strict third-party policies, and how to ship pdf.js + the worker locally with wp_localize_script. A working pattern for any production WordPress plugin that needs to render PDFs.
Three of Three Questions Correct, Zero of Zero Points: The LearnDash ProQuiz Points Bug
A migrated quiz that grades every answer correctly but reports '0 of 0 points' looks like a frontend bug and is actually a one-column DB problem. Here's the full diagnosis, the fix, and the importer patch so it doesn't happen again.
Importing Quizzes by Position Instead of by ID: A Cardinal Mistake
The first quiz bug we caught after launch wasn't about grading at all — it was about which question a student was actually seeing. Our importer was wiring questions to answers by position (the cardinal number) instead of by the real ProQuiz question ID. Some students got the wrong question on the wrong screen.
Recovering Course Progress After You've Already Cut Over: Merge, Never Overwrite
Most migrations skip historical course progress on purpose — it's expensive to reconstruct and rarely missed. But if you decide later that you want it back, and your students have already been using the new system, you can't just import. You have to merge. Here's the pattern that works.
Theory Time: Migrating 6.5 Years of Music Education from Thinkific to LearnDash
13 courses. 1,439 enrollments. 691 videos. 63 quizzes. 6.5 years of purchase history preserved per-user. A music education platform's full move from Thinkific to LearnDash — shipped to production, including the two post-launch bugs we caught and fixed.