Once we integrated webinars into an LMS with 2000 students: the teacher manually created meetings, forgot to enable recording, and had to cross-check attendance via screenshots. After automation via API, administrative costs dropped by 8 hours per week. This approach not only saves time but also eliminates human errors — students receive links on time, recordings are available right after the webinar, and the attendance log is filled automatically.
How to Choose a Video Platform for LMS?
| Platform | API | Self-hosted | Recording | Attendance | Features |
|---|---|---|---|---|---|
| Zoom | REST API, Webhooks | No | Cloud | Via webhook | Standard, broad API, good recording |
| BigBlueButton | REST API (checksum) | Yes | Yes | Detailed logs | Designed for education, whiteboard, breakout rooms |
| Jitsi Meet | REST API (Jibri) | Yes | Yes | Via webhook | Free, full control |
| Daily.co | REST API + SDK | No | No | Built-in | Embeddable video call directly in LMS |
| Whereby | REST API | No | No | No | Simple embedding, iframe |
BigBlueButton — recommended for educational LMS: built-in whiteboard, polls, breakout rooms, participant-split recording. Self-hosted. Zoom — if clients already use it and don't want to change habits. Daily.co — if you need to embed video directly into the LMS interface without navigating to an external site.
How to Automate Webinar Creation?
Integration with Zoom API is one of the most straightforward paths. Below is an example JavaScript class that creates a meeting with auto-recording and waiting room settings.
class ZoomIntegration {
constructor(accountId, clientId, clientSecret) {
this.tokenUrl = 'https://zoom.us/oauth/token';
this.apiUrl = 'https://api.zoom.us/v2';
this.credentials = { accountId, clientId, clientSecret };
}
async getAccessToken() {
const response = await fetch(this.tokenUrl, {
method: 'POST',
headers: {
'Authorization': `Basic ${Buffer.from(`${this.credentials.clientId}:${this.credentials.clientSecret}`).toString('base64')}`,
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `grant_type=account_credentials&account_id=${this.credentials.accountId}`,
});
const data = await response.json();
return data.access_token;
}
async createMeeting({ topic, startTime, durationMin, agenda, hostEmail }) {
const token = await this.getAccessToken();
const response = await fetch(`${this.apiUrl}/users/${hostEmail}/meetings`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
topic,
type: 2,
start_time: startTime.toISOString(),
duration: durationMin,
agenda,
settings: {
host_video: true,
participant_video: false,
waiting_room: true,
auto_recording: 'cloud',
mute_upon_entry: true,
approval_type: 0,
},
}),
});
return response.json();
}
}
For BigBlueButton the approach is different — it uses checksum-signed requests. Example in PHP:
class BigBlueButtonService {
private string $url;
private string $secret;
public function createMeeting(string $meetingId, string $name, array $options = []): array {
$params = array_merge([
'meetingID' => $meetingId,
'name' => $name,
'record' => 'true',
'autoStartRecording' => 'false',
'allowStartStopRecording' => 'true',
'webcamsOnlyForModerator' => 'false',
'lockSettingsDisableMic' => 'false',
], $options);
$queryString = http_build_query($params);
$checksum = sha1('create' . $queryString . $this->secret);
$params['checksum'] = $checksum;
$response = Http::get("{$this->url}/api/create", $params);
return $response->json();
}
public function getJoinUrl(string $meetingId, string $fullName, string $role, string $userId): string {
$password = $role === 'moderator' ? $this->moderatorPw : $this->attendeePw;
$params = "meetingID={$meetingId}&fullName=" . urlencode($fullName) .
"&password={$password}&userID={$userId}";
$checksum = sha1('join' . $params . $this->secret);
return "{$this->url}/api/join?{$params}&checksum={$checksum}";
}
}
What Does Attendance Tracking via Webhooks Provide?
Automatic tracking via webhooks solves the problem of attendance fraud. Zoom Webhooks send meeting.participant_joined and meeting.participant_left events. BigBlueButton provides detailed logs through Recording API. We save each student's entry and exit time, compute presence duration, and generate a report.
app.post('/webhooks/zoom', async (req, res) => {
const { event, payload } = req.body;
if (event === 'meeting.participant_joined') {
await db.webinarAttendance.upsert({
webinarId: payload.object.id,
userId: await findUserByEmail(payload.object.participant.email),
joinedAt: new Date(payload.object.participant.join_time),
});
}
if (event === 'meeting.participant_left') {
await db.webinarAttendance.update({
webinarId: payload.object.id,
userId: await findUserByEmail(payload.object.participant.email),
}, {
leftAt: new Date(payload.object.participant.leave_time),
durationMin: payload.object.participant.duration,
});
}
res.status(200).json({ status: 'ok' });
});
Webinar Recordings
After the webinar ends, Zoom/BBB generates a recording. Process:
- Webhook
recording.completed→ receive download link - Download and upload to S3 (Zoom stores recordings for a limited time)
- Create a video lesson in LMS with the recording link
- Notify students who missed the webinar
async function processWebinarRecording(meetingId, downloadUrl, token) {
const s3Key = `recordings/${meetingId}.mp4`;
const response = await fetch(downloadUrl, {
headers: { Authorization: `Bearer ${token}` }
});
await s3.upload({ Bucket: process.env.S3_BUCKET, Key: s3Key, Body: response.body }).promise();
const videoUrl = `https://${process.env.CDN_DOMAIN}/${s3Key}`;
await db.webinars.update({ meetingId }, { recordingUrl: videoUrl });
await notifyAbsentStudents(meetingId, videoUrl);
}
Embedded Video Call via Daily.co
If you need to embed video directly into LMS without navigating to an external page:
import DailyIframe from '@daily-co/daily-js';
function WebinarRoom({ roomUrl, token }) {
const callFrame = useRef(null);
useEffect(() => {
callFrame.current = DailyIframe.createFrame({
url: roomUrl,
token,
iframeStyle: { width: '100%', height: '600px' },
});
callFrame.current.on('participant-counts-updated', ({ present }) => {
trackAttendance(present);
});
callFrame.current.join();
return () => callFrame.current.destroy();
}, [roomUrl]);
return <div id="daily-container" />;
}
Use Case Scenarios: Platform Comparison
| Scenario | Recommended Platform | Reason |
|---|---|---|
| Course with 50+ students, need whiteboard and polls | BigBlueButton | Specialized for education, self-hosted, detailed statistics |
| Corporate training, already using Zoom | Zoom | No migration needed, standard API |
| Embedding video directly in interface | Daily.co | Lightweight SDK, no external site navigation |
Common Integration Mistakes
Expand list
- Webhooks not configured — meeting created but events not received.
- Missing retry handling on API errors (rate limit).
- Timezone not accounted for when scheduling meetings.
- Recording not uploaded if
recording.completedwebhook not processed. - Moderator and attendee passwords swapped in BigBlueButton.
What's Included in the Work
- API integration of the chosen platform (Zoom/BBB/Jitsi).
- Automatic webinar creation based on schedule.
- Sending links to students (email/notifications).
- Webinar recording and upload to S3/CDN.
- Attendance tracking with reports.
- API documentation and admin instructions.
- 1 month technical support.
Work Process
- Requirements analysis: select platform, configure API, agree on data flow scheme.
- Design: design webhook handlers, recording and attendance storage schemas.
- Implementation: integrate via API, code, write tests.
- Testing: verify meeting creation, webhooks, recording, attendance.
- Deploy and train: deploy on server, provide admin instructions.
Approximate Timelines
Zoom API integration: create meetings, send links to students, basic attendance — 4–5 days. Webinar recording with upload to S3 and notifications — 2–3 days. Self-hosted BigBlueButton with full integration and embedding into LMS — 7–10 days. Daily.co embedded video — 3–4 days.
Experience and Guarantees
We have completed over 30 integrations with Zoom, BigBlueButton, and Jitsi for LMS on Laravel, Node.js, and Python. Our engineers are certified in Zoom API. We guarantee compatibility with any modern LMS and provide 1 month support after deployment.
For an accurate timeline and cost estimate, contact us — we will select the optimal platform for your tasks.
See official documentation: Zoom REST API, BigBlueButton API.







