← Home

Add live classes to your website

Your backend decides who may join and with which role by issuing a join token. The media server checks every token and enforces the facilitator's permissions, so nothing in the browser can grant extra rights.

1. Issue join tokens from your backend

// app/api/class-token/route.ts (Next.js) — after checking the student is enrolled
import { RtcServer } from "@trovesuite/rtc-server";

const rtc = new RtcServer({
  url: process.env.RTC_URL!,            // https://media.example.com
  apiKey: process.env.RTC_API_KEY!,
  apiSecret: process.env.RTC_API_SECRET!,
});

export async function POST(req: Request) {
  const user = await getSessionUser(req);              // your auth
  const { classId } = await req.json();
  if (!(await isEnrolled(user.id, classId))) return new Response("Forbidden", { status: 403 });
  const { token, url } = rtc.createJoinToken({
    roomId: classId,
    userId: user.id,
    name: user.fullName,
    role: user.isTeacher ? "host" : "student",
  });
  return Response.json({ token, url });
}

2a. Any website: embed with one script

Works with plain HTML, WordPress, PHP, Laravel or any framework. The class runs in an iframe with camera, microphone and screen sharing allowed.

<div id="live-class" style="height: 640px"></div>
<script src="{APP_URL}/embed.js"></script>
<script>
  TroveMeet.mount("#live-class", {
    // Fetched from your backend when the class opens:
    getToken: () => fetch("/api/class-token", { method: "POST", body: JSON.stringify({ classId: "maths-jhs2" }) }).then(r => r.json()),
    name: "Ama Mensah",
    primary: "#0f766e",            // school colour
    onEvent: (type, data) => console.log(type, data),   // joined, left, handRaised, ...
  });
</script>

2b. React or Next.js: use the components

Full control over layout. Components are styled with Tailwind; add the package to your Tailwind sources.

import { Room } from "@trovesuite/rtc-client";
import { Classroom, RtcThemeProvider } from "@trovesuite/rtc-react";

const room = new Room();
await room.connect(url, token, { audio: true, video: true });

<RtcThemeProvider appName="MyEduGuard" primaryColor="#0f766e">
  <Classroom room={room} onLeave={(reason) => router.push("/learning")} />
</RtcThemeProvider>

3. Keep attendance, reports and recordings in your system

// The media server has no database: what happened arrives as signed webhooks,
// and you keep it in yours.
const event = rtc.webhooks.verify(rawBody, req.headers.get("x-rtc-signature"));
switch (event.event) {
  case "participant_left": await db.sessions.close(event.data.sessionId, event.data); break; // with engagement
  case "room_finished":    await db.classRuns.save(event.roomId, event.data); break;        // attendance, talk time, polls
  case "recording_ready":  await copyToYourStorage(event.data.mediaUrl, event.data.timelineUrl); break;
}

No code at all? Send people to a join link (rtc.joinUrl()), or add the LTI tool to Moodle, Canvas, Blackboard, Brightspace or Schoology. Get a key in the developer console and read the full guide (React, Next.js, plain HTML/JS, Vue, Angular, Svelte, WordPress, PHP, Python, Go, .NET, Java, Ruby, React Native, Flutter, LTI).