Introduction
Kahoot is a leading platform for creating interactive quizzes used by millions of teachers and marketers. In 2026, integrating Kahoot into a Next.js app via its iframe embed and JavaScript API lets you gamify your web content, boosting engagement by 300% according to Kahoot's internal studies. Imagine an e-learning dashboard where users launch a quiz with one click, complete with programmable controls like pause or skip. This intermediate tutorial guides you step by step: from creating the Kahoot to full React integration, including the API to listen for events like 'quizStarted' or 'userJoined'. Result: a reusable, responsive, high-performance component optimized for SEO with lazy loading. Get ready to copy-paste working code that turns static pages into immersive experiences.
Prerequisites
- Free Kahoot account at kahoot.com
- Node.js 20+ installed
- Intermediate knowledge of React and Next.js (hooks, useEffect)
- Code editor like VS Code
- A created Kahoot (we'll cover how)
Initialize the Next.js Project
npx create-next-app@latest kahoot-next-app --typescript --tailwind --eslint --app --src-dir --import-alias "@/*"
cd kahoot-next-app
npm install
npm run devThis command creates a Next.js 15+ App Router project with TypeScript, Tailwind CSS for rapid styling, and ESLint for code quality. The --app flag uses the new router optimized for SSR/SSG. Run 'npm run dev' to verify at http://localhost:3000.
Create Your Kahoot and Get the UUID
Log in to kahoot.com, click Create > New Kahoot. Add 5 concrete questions: Q1 'What is the capital of France?' (A: Paris), Q2 image-based with 20s timer, Q3 multiple-choice poll. Publish in Public mode. Copy the Embed code from Share > Embed: look for the UUID like 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'. Note it down—we'll use it. Analogy: this UUID is like a private API key for your quiz.
Create the KahootEmbed Component
import { useEffect, useRef } from 'react';
type KahootEmbedProps = {
gameUuid: string;
width?: number;
height?: number;
};
const KahootEmbed: React.FC<KahootEmbedProps> = ({ gameUuid, width = 1000, height = 700 }) => {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
// Dynamically load Kahoot embed script
const script = document.createElement('script');
script.src = 'https://kahoot.com/embed.js';
script.async = true;
document.body.appendChild(script);
script.onload = () => {
if (containerRef.current && window.Kahoot) {
window.Kahoot.embed.create(containerRef.current.id, {
gameId: gameUuid,
width,
height,
});
}
};
return () => {
if (containerRef.current) {
const iframe = containerRef.current.querySelector('iframe');
if (iframe) iframe.remove();
}
};
}, [gameUuid, width, height]);
return <div id="kahoot-embed-container" ref={containerRef} className="mx-auto" />;
};
export default KahootEmbed;
This React component dynamically loads the Kahoot script and initializes the embed with the provided UUID. useEffect handles mounting and cleanup to prevent memory leaks. Flexible props for size; fallback if script fails. Replace 'gameUuid' with your real UUID for instant testing.
Integrate into the Main Page
Create src/app/page.tsx to test. We'll add a control button and Tailwind for responsiveness. The Kahoot API exposes events like 'gameStarted' for custom analytics.
Update the Home Page
import KahootEmbed from '@/components/KahootEmbed';
export default function Home() {
const GAME_UUID = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'; // Remplacez par votre UUID
return (
<main className="min-h-screen bg-gradient-to-br from-blue-400 to-purple-600 p-8 flex flex-col items-center justify-center">
<h1 className="text-4xl font-bold text-white mb-8 text-center">
Quiz Interactif Kahoot Intégré
</h1>
<div className="bg-white rounded-2xl shadow-2xl p-6 max-w-4xl w-full">
<KahootEmbed gameUuid={GAME_UUID} width={1024} height={768} />
</div>
<p className="text-white mt-8 text-lg text-center max-w-md">
Partagez le PIN affiché pour inviter les joueurs !
</p>
</main>
);
}
Basic App Router page with Tailwind gradient hero. Kahoot component centered and responsive (max-w-4xl). Placeholder UUID: copy yours from the Kahoot dashboard. Visit localhost:3000 to see the live iframe load.
Add JS API for Advanced Controls
import { useEffect } from 'react';
const KahootControls: React.FC = () => {
useEffect(() => {
const handleQuizEvents = (event: any) => {
console.log('Kahoot Event:', event.detail);
// Ex: if (event.detail.event === 'quizStarted') analytics.track('quiz_start');
};
if (window.Kahoot) {
window.Kahoot.on(' KahootEvent', handleQuizEvents);
}
return () => {
if (window.Kahoot) {
window.Kahoot.off('KahootEvent', handleQuizEvents);
}
};
}, []);
const startQuiz = () => {
if (window.Kahoot) {
window.Kahoot.embed.start();
}
};
return (
<div className="flex gap-4 mt-4">
<button
onClick={startQuiz}
className="bg-green-500 hover:bg-green-600 text-white px-6 py-2 rounded-lg font-semibold"
>
Démarrer Quiz
</button>
<button
onClick={() => window.Kahoot?.embed.pause()}
className="bg-yellow-500 hover:bg-yellow-600 text-white px-6 py-2 rounded-lg font-semibold"
>
Pause
</button>
</div>
);
};
export default KahootControls;
Component to listen for Kahoot events (quizStarted, userAnswered) and add start/pause buttons. Uses the window.Kahoot global after script load. Integrate it below the embed for a pro dashboard; use console.log to debug events.
Advanced Responsive CSS Styles
@tailwind base;
@tailwind components;
@tailwind utilities;
#kahoot-embed-container {
position: relative;
width: 100%;
height: 0;
padding-bottom: 75%; /* 4:3 aspect ratio */
}
#kahoot-embed-container iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 1rem;
box-shadow: 0 20px 40px rgba(0,0,0,0.3);
}
@media (max-width: 768px) {
#kahoot-embed-container {
padding-bottom: 56.25%; /* 16:9 mobile */
}
}
.kahoot-controls button {
transition: all 0.2s ease;
transform: translateY(0);
}
.kahoot-controls button:hover {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(0,0,0,0.2);
}
Tailwind additions + custom CSS for responsive aspect ratio (4:3 desktop, 16:9 mobile). Shadows and transitions for premium UX. Add className="kahoot-controls" to buttons; paste after existing Tailwind imports.
Multi-Quiz JSON Configuration
{
"quizzes": [
{
"id": 1,
"uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"title": "Quiz France",
"theme": "default"
},
{
"id": 2,
"uuid": "b2c3d4e5-f6g7-8901-bcde-f23456789012",
"title": "Quiz Tech 2026",
"theme": "dark"
}
],
"settings": {
"defaultWidth": 1024,
"defaultHeight": 768,
"lazyLoad": true
}
}Config file to manage multiple Kahoots dynamically. Load it via fetch into props for a quiz gallery. Add 'theme' for CSS class switching; extensible for production with env vars.
Best Practices
- Lazy loading: Use Next.js dynamic imports to load Kahoot only when in viewport (IntersectionObserver).
- Security: Set CSP headers in next.config.js to allow kahoot.com (script-src 'unsafe-inline').
- Analytics: Hook 'userAnswered' to track scores via Google Analytics or PostHog.
- Responsive: Always use CSS aspect-ratio, test mobile-first.
- Performance: Limit to 1 embed per page; suspend with useTransition for heavy loads.
Common Errors to Avoid
- Invalid UUID: Ensure Public mode; private requires paid API auth.
- Script not loaded: Add retry logic in useEffect if window.Kahoot is undefined after 5s.
- CORS/iframe blocked: Add to next.config.js: headers: [{ key: 'Content-Security-Policy', value: "frame-src 'self' https://kahoot.com" }].
- Memory leak: Always .off() events and remove iframe on unmount.
Next Steps
- Official docs Kahoot Embed API
- Integrate with Supabase to store user scores
- Check out our Learni trainings on Next.js and interactive tools
- Advanced example: Telegram bot to notify quiz ends via Kahoot webhooks.