Iframe Events
When you embed a Verriflo classroom in an iframe, we send events via postMessage to let you know what's happening. Use these to keep your app in sync with the classroom state.
Listening for Eventsβ
Set up a message listener on your parent window:
window.addEventListener("message", (event) => {
// Verify origin for security
if (!event.origin.includes("verriflo.com")) return;
const { type, action } = event.data;
// Handle different event types
if (type === "verriflo_classroom") {
handleClassroomEvent(action);
}
if (type === "verriflo_fullscreen") {
handleFullscreenEvent(action);
}
});
Classroom Eventsβ
Type: verriflo_classroom
These events tell you about the classroom lifecycleβwhen it ends, when students leave, etc.
| Action | Description | When It Fires |
|---|---|---|
class_ended | Teacher ended the session | Instructor clicks "End Class" |
participant_left | User voluntarily left | Student clicks "Leave" button |
participant_removed | User was kicked | Teacher removed the student |
close | User clicked close after disconnection | After showing the "disconnected" screen |
Example Payloadβ
{
type: 'verriflo_classroom',
action: 'class_ended'
}
Handling Classroom Eventsβ
function handleClassroomEvent(action) {
switch (action) {
case "class_ended":
// Teacher ended the class
// Redirect to feedback page or course home
window.location.href = "/class-feedback";
break;
case "participant_removed":
// Student was kicked by teacher
showNotification("You were removed from the class");
window.location.href = "/dashboard";
break;
case "participant_left":
// User left voluntarily
// Maybe just close the modal or navigate back
closeClassroomModal();
break;
case "close":
// User acknowledged disconnection
// Clean up and navigate away
navigateBack();
break;
}
}
Fullscreen Eventsβ
Type: verriflo_fullscreen
The classroom UI has a fullscreen button. Since iframes can't control fullscreen on their parent, we send a message asking you to do it.
| Action | Description |
|---|---|
enter | User wants fullscreen |
exit | User wants to exit fullscreen |
Handling Fullscreenβ
function handleFullscreenEvent(action) {
const iframe = document.getElementById("verriflo-iframe");
if (action === "enter") {
// Enter fullscreen
if (iframe.requestFullscreen) {
iframe.requestFullscreen();
} else if (iframe.webkitRequestFullscreen) {
// Safari
iframe.webkitRequestFullscreen();
}
}
if (action === "exit") {
// Exit fullscreen
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
}
}
}
Sending Commandsβ
You can also control the classroom by sending messages to the iframe.
Force Leaveβ
Force the current user to disconnect. Useful for custom "Leave Class" buttons in your app.
const iframe = document.getElementById("verriflo-iframe");
iframe.contentWindow.postMessage(
{
type: "verriflo_force_leave",
reason: "Class dismissed", // Optional
},
"*"
);
This will disconnect the user and trigger a disconnected event.
Complete Integration Exampleβ
Here's a full example of embedding a Verriflo classroom with event handling:
HTMLβ
<div id="classroom-container">
<iframe
id="verriflo-iframe"
src="https://live.verriflo.com/live?token=YOUR_TOKEN"
allow="camera; microphone; fullscreen; display-capture"
allowfullscreen
style="width: 100%; height: 600px; border: none;"
></iframe>
</div>
JavaScriptβ
// Store reference to iframe
const iframe = document.getElementById("verriflo-iframe");
// Set up event listener
window.addEventListener("message", (event) => {
// Security: verify the origin
if (!event.origin.includes("verriflo.com")) {
return;
}
const { type, action } = event.data;
console.log("Verriflo event:", type, action);
// Classroom lifecycle events
if (type === "verriflo_classroom") {
switch (action) {
case "class_ended":
showToast("Class has ended");
redirectToFeedback();
break;
case "participant_removed":
showToast("You were removed from the class");
redirectToDashboard();
break;
case "participant_left":
case "close":
// User initiated leave
closeClassroom();
break;
}
}
// Fullscreen events
if (type === "verriflo_fullscreen") {
if (action === "enter") {
enterFullscreen(iframe);
} else if (action === "exit") {
exitFullscreen();
}
}
});
// Fullscreen helpers
function enterFullscreen(element) {
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.webkitRequestFullscreen) {
element.webkitRequestFullscreen();
} else if (element.msRequestFullscreen) {
element.msRequestFullscreen();
}
}
function exitFullscreen() {
if (document.fullscreenElement) {
document.exitFullscreen();
} else if (document.webkitFullscreenElement) {
document.webkitExitFullscreen();
}
}
// Navigation helpers
function redirectToFeedback() {
setTimeout(() => {
window.location.href = "/class-feedback";
}, 2000); // Give time for toast to show
}
function redirectToDashboard() {
window.location.href = "/dashboard";
}
function closeClassroom() {
// If in a modal, close it
// If in a page, navigate back
history.back();
}
React Exampleβ
import { useEffect, useRef } from "react";
import { useNavigate } from "react-router-dom";
import { toast } from "react-hot-toast";
function ClassroomEmbed({ token }) {
const iframeRef = useRef(null);
const navigate = useNavigate();
useEffect(() => {
function handleMessage(event) {
if (!event.origin.includes("verriflo.com")) return;
const { type, action } = event.data;
if (type === "verriflo_classroom") {
switch (action) {
case "class_ended":
toast.success("Class has ended");
navigate("/feedback");
break;
case "participant_removed":
toast.error("You were removed from the class");
navigate("/dashboard");
break;
case "participant_left":
case "close":
navigate(-1);
break;
}
}
if (type === "verriflo_fullscreen") {
if (action === "enter") {
iframeRef.current?.requestFullscreen();
} else if (action === "exit") {
document.exitFullscreen();
}
}
}
window.addEventListener("message", handleMessage);
return () => window.removeEventListener("message", handleMessage);
}, [navigate]);
return (
<iframe
ref={iframeRef}
src={`https://live.verriflo.com/live?token=${token}`}
allow="camera; microphone; fullscreen; display-capture"
allowFullScreen
className="w-full h-[600px] border-none"
/>
);
}
Vue Exampleβ
<template>
<iframe
ref="iframeRef"
:src="`https://live.verriflo.com/live?token=${token}`"
allow="camera; microphone; fullscreen; display-capture"
allowfullscreen
class="classroom-iframe"
/>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from "vue";
import { useRouter } from "vue-router";
const props = defineProps(["token"]);
const router = useRouter();
const iframeRef = ref(null);
function handleMessage(event) {
if (!event.origin.includes("verriflo.com")) return;
const { type, action } = event.data;
if (type === "verriflo_classroom") {
if (action === "class_ended") {
router.push("/feedback");
} else if (action === "participant_removed") {
router.push("/dashboard");
} else {
router.back();
}
}
if (type === "verriflo_fullscreen") {
if (action === "enter") {
iframeRef.value?.requestFullscreen();
} else if (action === "exit") {
document.exitFullscreen();
}
}
}
onMounted(() => {
window.addEventListener("message", handleMessage);
});
onUnmounted(() => {
window.removeEventListener("message", handleMessage);
});
</script>
<style scoped>
.classroom-iframe {
width: 100%;
height: 600px;
border: none;
}
</style>
Security Considerationsβ
Always verify the message origin before processing events:
// β
Good - verify origin
if (!event.origin.includes("verriflo.com")) return;
// β Bad - processing any message
window.addEventListener("message", (event) => {
// Processing without origin check is dangerous!
handleEvent(event.data);
});
This prevents malicious sites from sending fake events to your app.
Next: Error Codes β Complete reference for all error responses.