Skip to main content

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.

ActionDescriptionWhen It Fires
class_endedTeacher ended the sessionInstructor clicks "End Class"
participant_leftUser voluntarily leftStudent clicks "Leave" button
participant_removedUser was kickedTeacher removed the student
closeUser clicked close after disconnectionAfter 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.

ActionDescription
enterUser wants fullscreen
exitUser 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.