Francophone Africa's online training market is exploding: +35% per year since 2023. Tech bootcamps, professional courses, certifications. But LMS choice determines 80% of learner experience and 60% of profitability.
TL;DR
- Moodle: open-source, mature, free, but 2010s UX.
- Teachable / Thinkific: ready-to-use SaaS, perfect to start, 5-15% fees.
- Custom (Next.js): 3-6 month effort, scaling ROI, no fees.
Detailed comparison
| Criterion | Moodle | Teachable | Custom |
|---|---|---|---|
| Initial cost | €15/mo hosting | $39-149/mo | 8-25M XOF dev |
| 1000-student scale cost | €15-50/mo | $99 + 0% fees | Hosting only |
| 10K-student scale cost | €100-300/mo | $499 + 0% fees | Hosting only |
| Learner UX | Dated | Excellent | Custom |
| Mobile | OK | Excellent | Custom |
| Video | Upload + storage | Included (CDN) | Mux / BunnyCDN |
| Quiz | Very complete | Basic | To code |
| PDF certifications | ✓ plugin | ✓ included | To code |
| Wave/OM payment | Manual plugin | Stripe only | Custom |
| Multilingual | Yes (50+ languages) | Limited | Custom |
| API | Good | Limited | Custom |
When to pick Moodle
Cases:
- University / education institution
- Limited budget
- Wide functional need (forums, assignments, complex quizzes)
- Available technical team
Stack:
- Hetzner CX21 (€8/month)
- Postgres or MariaDB
- Caddy + Let's Encrypt
- Custom Wave/OM plugin
`bash
docker run -d --name moodle \
-p 80:80 \
-e MOODLE_DATABASE_TYPE=pgsql \
-e MOODLE_DATABASE_HOST=db \
-e MOODLE_DATABASE_NAME=moodle \
-e MOODLE_DATABASE_USER=moodle \
-e MOODLE_DATABASE_PASSWORD=secret \
-v moodle_data:/bitnami/moodle \
bitnami/moodle:latest
`
When to pick Teachable / Thinkific
Cases:
- Solo coach / trainer
- 1-10 courses
- Need to launch in 1-2 weeks
- No dev budget
Teachable 2026 pricing:
- Basic: $39/month + 5% transaction
- Pro: $119/month + 0% transaction
- Business: $499/month + 0% + advanced features
Pros:
- Setup in 2-3 days
- Modern UI by default
- Email automation included
- Native affiliates
Cons for Africa:
- Stripe-only payment (no native Wave / OM)
- $ pricing puts off local market
- No strong native multilingual
Solution: Teachable for premium courses (EU/US clients), custom site for XOF clients.
When to pick Custom (Next.js + Postgres)
Cases:
- 100+ students/year short-term goal
- Marketplace trainers (multi-trainer)
- Specific integrations (existing CRM, ERP)
- Strong own brand
Custom architecture
`prisma
model Course {
id String @id @default(cuid())
slug String @unique
title String
description String
thumbnail String
category String
level String
language String
duration Int
priceXof Int
priceEur Int?
priceUsd Int?
modules Module[]
enrollments Enrollment[]
instructorId String
status String
publishedAt DateTime?
}
model Module {
id String @id @default(cuid())
courseId String
course Course @relation(fields: [courseId], references: [id])
title String
order Int
lessons Lesson[]
}
model Lesson {
id String @id @default(cuid())
moduleId String
module Module @relation(fields: [moduleId], references: [id])
title String
type String
videoUrl String?
transcript String?
durationSec Int?
content String?
order Int
isFree Boolean
}
model Enrollment {
id String @id @default(cuid())
studentId String
courseId String
course Course @relation(fields: [courseId], references: [id])
enrolledAt DateTime @default(now())
completedAt DateTime?
progress Json
certificateUrl String?
Need a professional website?
Kolonell builds websites that attract clients, optimized for the Sénégalese market. Free quote in 2 minutes.
}
model QuizAttempt {
id String @id @default(cuid())
studentId String
lessonId String
answers Json
score Int
passedAt DateTime?
attemptNum Int
}
`
Video streaming
Mux or BunnyCDN for HLS streaming video hosting:
`tsx
import { MuxPlayer } from '@mux/mux-player-react';
export function LessonPlayer({ lesson, enrollment }) {
return (
streamType="on-demand"
playbackId={lesson.muxPlaybackId}
metadata={{
video_title: lesson.title,
viewer_user_id: enrollment.studentId,
}}
onTimeUpdate={(e) => {
if (Math.floor(e.target.currentTime) % 10 === 0) {
saveProgress(enrollment.id, lesson.id, e.target.currentTime);
}
}}
onEnded={() => markLessonComplete(enrollment.id, lesson.id)}
/>
);
}
`
Quizzes and certifications
`tsx
export function Quiz({ lesson, onSubmit }) {
const [answers, setAnswers] = useState({});
return (
e.preventDefault();
const result = await submitQuiz({ lessonId: lesson.id, answers });
if (result.score >= 70) {
if (result.isFinal) {
const cert = await generateCertificate(enrollmentId);
window.open(cert.url);
}
}
}}>
{lesson.questions.map(q => (
))}
);
}
`
Multi-currency payment
`tsx
function CourseCheckout({ course, currency }) {
const price = course.prices[currency];
if (currency === 'XOF') {
return
} else if (currency === 'EUR' || currency === 'USD') {
return
}
}
`
Real case — Dakar tech bootcamp (1,500 students/year)
Choice: Custom Next.js + Postgres + Mux.
| Metric | Value 2026 |
|---|---|
| Initial investment | 18M XOF (5 months dev) |
| Monthly hosting | €60 (Hetzner + Mux + Postgres) |
| Paying students/month | 125 |
| Avg course price | 95K XOF |
| Monthly revenue | 11.9M XOF |
| Gross margin | 85% |
VS Teachable scenario:
- Pro hosting: $1,428/year
- Stripe fees 2.9% × 11.9M = 345K XOF/month
- Total Teachable + Stripe fees: ~$50K/year
- No native Wave / OM = 35% conversion lost → -4M XOF/month
Custom pays back in 8 months.
FAQ
Q: Migrate from Teachable to Custom?
A: Hard. Content export OK but students/progress = headache. Starting custom = better if >500/year volume planned.
Q: Self-hosted videos vs Mux?
A: Mux = $1-3/active user. At high volume (1,000+ users), self-host BunnyCDN cheaper (~$50/month fixed).
Q: Multilingual training FR + EN?
A: If same content: synchronized subtitles (Whisper auto + review). If really different content: 2 separate courses.
Conclusion
LMS chosen = business strategy. Solo trainer starting: Teachable. University / institution: Moodle. Bootcamp / scale-up: Custom. Investing at the right level at the right time avoids costly re-migration 18 months later.
Mohamed Bah
Fondateur, Kolonell
Passionate about digital and entrepreneurship in Africa, Mohamed has been helping Sénégalese businesses with their digital transformation since 2020. Founder of Kolonell, he believes every SME deserves a professional and accessible online présence.

