Skip to Content
📧 Join the Teacharium waitlist to get access. 
Guides & TutorialsEmbeddingEmbedding Lessons on External Websites

Embedding Lessons on External Websites

Learn how to embed Teacharium lessons on your website or application using secure iframe-based embedding with JWT authentication.

Overview

Teacharium provides a complete solution for embedding interactive lessons on external websites. The embedding system uses:

  • JWT tokens for secure, time-limited access
  • Iframe embedding for isolated, secure content delivery
  • JavaScript SDK for easy integration
  • PostMessage API for communication between the embedded lesson and parent page

Prerequisites

Before you begin, you’ll need:

  1. A Teacharium account with at least one published lesson
  2. Public API credentials (public key and secret key)
  3. A website or application where you want to embed lessons

Quick Start

Step 1: Install the SDK

Install the Teacharium Embed SDK in your project:

npm install @teacharium/embed-sdk

Or include it directly via CDN:

<script src="https://unpkg.com/@teacharium/embed-sdk@latest/dist/teacharium-embed-sdk.umd.js"></script>

Step 2: Generate a Token

On your backend server, generate a signed JWT token for the lesson:

const response = await fetch('https://www.teacharium.io/api/public/sign-token', { method: 'POST', headers: { 'Authorization': `Bearer ${publicKey}.${secretKey}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ lessonId: 'your-lesson-id', learnerId: 'learner_abc123', // Required: anonymous identifier for the learner userAttributes: { userId: 'user_67890', sessionId: 'session_abc123', accountType: 'premium' }, timeout: 7200 // 2 hours }) }); const { token, expiresAt } = await response.json();

Important Security Notes:

  • Always generate tokens on your backend server. Never expose your API secret key in client-side code.
  • Do not include PII (Personally Identifiable Information) such as email addresses, full names, phone numbers, or addresses in userAttributes. Use anonymous identifiers like user IDs or session IDs instead. This protects user privacy and complies with data protection regulations.

Step 3: Embed the Lesson

Add a container element to your HTML:

<div id="lesson-container"></div>

Then embed the lesson using the SDK:

import { embedLesson } from '@teacharium/embed-sdk'; const embed = embedLesson({ container: '#lesson-container', token: token, // Token from Step 2 // baseUrl defaults to https://www.teacharium.io // lessonId is automatically extracted from the token width: '100%', height: '600px', onLoad: () => console.log('Lesson loaded'), onComplete: (data) => console.log('Lesson completed', data), onProgress: (data) => console.log('Progress update', data), onError: (error) => console.error('Error', error) });

Note: The SDK automatically uses https://www.teacharium.io as the base URL and extracts the lessonId from the token, so you typically don’t need to specify these values unless you’re using a self-hosted instance.

Detailed Guide

Token Generation

Tokens are generated using the /api/public/sign-token endpoint. See the Sign Token API documentation for complete details.

Key points:

  • Tokens are tied to a specific lesson and organization
  • Default expiration is 2 hours (configurable up to 24 hours)
  • User attributes are embedded in the token for tracking and personalization
  • Tokens cannot be modified without re-signing

SDK Options

The embedLesson() function accepts the following options:

OptionTypeRequiredDescription
containerHTMLElement | stringYesContainer element or CSS selector
tokenstringYesJWT token from sign-token endpoint (lessonId is automatically extracted from this token)
baseUrlstringNoBase URL of your Teacharium instance (default: “https://www.teacharium.io ”)
widthstringNoIframe width (default: “100%“)
heightstringNoIframe height (default: “600px”)
classNamestringNoAdditional CSS classes for iframe
onLoadfunctionNoCallback when lesson loads
onCompletefunctionNoCallback when lesson completes
onProgressfunctionNoCallback for progress updates
onErrorfunctionNoCallback for errors

Event Handling

The SDK provides several event callbacks for tracking user progress:

onLoad

Fired when the lesson iframe has finished loading:

onLoad: () => { console.log('Lesson is ready to play'); // Hide loading indicator, etc. }

onComplete

Fired when the user completes the entire lesson:

onComplete: (data) => { console.log('Lesson completed!'); console.log('Lesson ID:', data.lessonId); console.log('Completed at:', data.completedAt); console.log('Total steps:', data.totalSteps); // Track completion in your system trackCompletion(data); }

onProgress

Fired when the user progresses through the lesson:

onProgress: (data) => { const percent = (data.currentStep / data.totalSteps) * 100; console.log(`Progress: ${percent.toFixed(1)}%`); // Update progress bar updateProgressBar(percent); }

onError

Fired when an error occurs:

onError: (error) => { console.error('Lesson error:', error.message); // Show error message to user showErrorNotification(error.message); }

Advanced Examples

React Integration

import { useEffect, useRef } from 'react'; import { embedLesson } from '@teacharium/embed-sdk'; function LessonEmbed({ token, onComplete }) { const containerRef = useRef(null); const embedRef = useRef(null); useEffect(() => { if (containerRef.current && token) { embedRef.current = embedLesson({ container: containerRef.current, token: token, // baseUrl and lessonId are handled automatically onComplete: (data) => { console.log('Lesson completed!', data); onComplete?.(data); }, onProgress: (data) => { console.log(`Progress: ${data.currentStep}/${data.totalSteps}`); } }); } // Cleanup on unmount return () => { if (embedRef.current) { embedRef.current.destroy(); } }; }, [token, onComplete]); return ( <div ref={containerRef} style={{ width: '100%', height: '600px' }} /> ); } export default LessonEmbed;

Vue.js Integration

<template> <div ref="lessonContainer" class="lesson-embed"></div> </template> <script> import { embedLesson } from '@teacharium/embed-sdk'; export default { name: 'LessonEmbed', props: { token: { type: String, required: true } }, data() { return { embed: null }; }, mounted() { this.embed = embedLesson({ container: this.$refs.lessonContainer, token: this.token, // baseUrl and lessonId are handled automatically onComplete: (data) => { this.$emit('complete', data); } }); }, beforeUnmount() { if (this.embed) { this.embed.destroy(); } } }; </script> <style scoped> .lesson-embed { width: 100%; height: 600px; } </style>

Responsive Embedding

Create a responsive embed that adjusts to different screen sizes:

embedLesson({ container: '#lesson', token: token, width: '100%', height: '80vh', // 80% of viewport height className: 'responsive-lesson-iframe' });
.responsive-lesson-iframe { max-width: 1200px; margin: 0 auto; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } @media (max-width: 768px) { .responsive-lesson-iframe { height: 100vh !important; border-radius: 0; } }

Progress Tracking

Implement a visual progress bar that updates as the user progresses:

<div class="progress-container"> <div class="progress-bar" id="progress-bar"></div> <div class="progress-text" id="progress-text">0%</div> </div> <div id="lesson-container"></div>
embedLesson({ container: '#lesson-container', token: token, onProgress: (data) => { const percent = (data.currentStep / data.totalSteps) * 100; document.getElementById('progress-bar').style.width = `${percent}%`; document.getElementById('progress-text').textContent = `${Math.round(percent)}%`; }, onComplete: (data) => { // Redirect to success page or show completion message window.location.href = '/lesson-complete'; } });
.progress-container { width: 100%; height: 30px; background: #e0e0e0; border-radius: 4px; position: relative; margin-bottom: 20px; } .progress-bar { height: 100%; background: linear-gradient(90deg, #4caf50, #8bc34a); border-radius: 4px; transition: width 0.3s ease; width: 0%; } .progress-text { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-weight: bold; color: #333; }

Server-Side Token Generation (Node.js/Express)

Example backend endpoint for generating tokens:

const express = require('express'); const app = express(); app.post('/api/embed-token', async (req, res) => { const { lessonId, learnerId, userId, sessionId } = req.body; try { const response = await fetch('https://www.teacharium.io/api/public/sign-token', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.TEACHARIUM_PUBLIC_KEY}.${process.env.TEACHARIUM_SECRET_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ lessonId: lessonId, learnerId: learnerId, // Required: anonymous identifier for the learner userAttributes: { userId: userId, sessionId: sessionId, timestamp: new Date().toISOString() }, timeout: 7200 }) }); if (!response.ok) { throw new Error('Failed to generate token'); } const { token, expiresAt } = await response.json(); res.json({ token, expiresAt }); } catch (error) { console.error('Error generating token:', error); res.status(500).json({ error: 'Failed to generate embed token' }); } });

Important: Do not pass PII such as email addresses in userAttributes. Use anonymous identifiers like user IDs or session IDs instead.

Security Best Practices

  1. Never expose API keys in client-side code

    • Always generate tokens on your backend server
    • Store API credentials in environment variables
  2. Do not include PII in tokens

    • Never include personally identifiable information such as email addresses, full names, phone numbers, or addresses in userAttributes
    • Use anonymous identifiers like user IDs, session IDs, or account numbers
    • This protects user privacy and helps comply with data protection regulations (GDPR, CCPA, etc.)
    • Embedded tokens may be visible in browser URLs or logs
  3. Use appropriate token expiration times

    • Set timeout based on expected lesson duration
    • Default 2 hours is suitable for most lessons
    • Maximum 24 hours for longer courses
  4. Include user identification in tokens

    • Use userAttributes to track which user is taking the lesson
    • Include anonymous identifiers like user IDs or session IDs
    • This data is securely embedded in the token
  5. Validate token ownership

    • The API automatically validates that tokens match the requested lesson
    • Tokens cannot be reused for different lessons
  6. Use HTTPS

    • Always serve your embedding page over HTTPS
    • Teacharium requires HTTPS for API requests

Troubleshooting

Token Invalid or Expired

Error: “Token verification failed: Token expired”

Solution: Generate a new token. Tokens expire after the specified timeout period.

Lesson Not Found

Error: “Lesson not found or access denied”

Causes:

  • The lesson ID is incorrect
  • The lesson hasn’t been published
  • The lesson belongs to a different organization

Solution: Verify the lesson ID and ensure the lesson is published.

CORS Errors

Error: “Cross-origin request blocked”

Solution: The embed player page includes proper CORS headers. Ensure you’re using the correct base URL and the lesson ID matches the token.

Iframe Not Loading

Causes:

  • Content Security Policy (CSP) restrictions on your page
  • X-Frame-Options preventing embedding

Solution: Ensure your page allows iframe embedding:

<meta http-equiv="Content-Security-Policy" content="frame-src 'self' https://your-teacharium-domain.com">

API Reference

For detailed API documentation, see:

SDK Reference

For complete SDK documentation, see the @teacharium/embed-sdk README .

Next Steps

Last updated on