To integrate the Khan Academy API with a V0 by Vercel app, use Khan Academy's open REST API to fetch topic trees, exercises, and video content via a Next.js API route. The API is publicly accessible without authentication for content browsing. Generate your learning portal UI with V0, create an API route that fetches Khan Academy subjects and exercises, and display structured educational content in your app.
Build Custom Learning Portals Powered by Khan Academy Content
Khan Academy hosts over 10,000 video lessons, 100,000+ practice exercises, and a structured topic tree covering mathematics from pre-K through college, science, computing, humanities, and test preparation. All of this content is accessible via a public REST API, making it one of the most valuable free data sources for building educational applications.
A common use case is building a custom learning portal that curates Khan Academy content for a specific audience — a company's onboarding program built around Khan Academy's business math content, a tutoring center dashboard showing students their recommended Khan Academy exercises, or a school's blended learning app that surfaces relevant Khan Academy videos alongside teacher-created content.
The Khan Academy API provides a hierarchical topic tree starting from domains (math, science, etc.) down through subjects, topics, tutorials, and individual content items (videos, exercises, articles). Your V0-generated frontend can navigate this tree to display curated learning paths, while the Next.js API route handles the data fetching and caching to keep the interface fast.
Integration method
Khan Academy's REST API is publicly accessible for reading content — no API key is required for browsing topics, videos, and exercises. Your V0 app creates Next.js API routes that proxy Khan Academy API calls, transform the response data into a frontend-friendly format, and serve it to the V0-generated learning portal UI. User progress tracking requires OAuth 1.0a authentication if you want to access individual student data.
Prerequisites
- No Khan Academy API key is required for public content browsing — the content API is open
- For accessing user progress data, you need a Khan Academy OAuth 1.0a consumer key (apply at khanacademy.org/api/auth2)
- A V0 project exported to GitHub and deployed on Vercel
- Basic understanding of Next.js API routes and React data fetching
- Familiarity with hierarchical data structures (Khan Academy's topic tree uses nested objects)
Step-by-step guide
Generate the Learning Portal UI with V0
Generate the Learning Portal UI with V0
Before writing any API code, use V0 to generate the UI components for your learning portal. Khan Academy's content structure (domain → subject → topic → content item) naturally maps to breadcrumb navigation with a content grid, so describe this structure explicitly in your V0 prompt. The key UI components you'll need are: a topic navigation breadcrumb showing the current path in the Khan Academy hierarchy, a content grid displaying videos and exercises as cards, and an individual content view that either embeds a YouTube video (Khan Academy videos are hosted on YouTube) or an exercise iframe. V0 generates these components well when you specify the data shape in TypeScript interfaces upfront. For the content cards, Khan Academy provides thumbnail URLs for videos and icon URLs for exercises. Include these in your component design. Each card should show: title, content type badge (Video/Exercise/Article), duration for videos, difficulty for exercises, and a primary action button. Consider also generating a search interface — Khan Academy's topic title search is valuable for users who know what they're looking for. A search input at the top of the page that filters displayed content by title provides immediate value before you implement the full topic tree navigation.
Create a learning content browser page. At the top: a search bar with subject filter dropdown (Math, Science, Computing, Test Prep). Below: a content grid with cards showing: colored icon by content type (blue for Video, orange for Exercise, green for Article), title, short description, content type badge, and a blue 'Start Learning' button. Include a breadcrumb nav at the top: Home > Subject > Topic. Show 12 skeleton cards while loading.
Paste this in V0 chat
Pro tip: Khan Academy exercise content is best embedded using an iframe pointing to the Khan Academy exercise URL rather than trying to render exercises natively. Ask V0 to generate a modal with an embedded iframe for exercise content.
Expected result: A polished learning portal UI with content cards, search bar, breadcrumb navigation, and skeleton loading states using placeholder data.
Create the Khan Academy API Route
Create the Khan Academy API Route
Create a Next.js API route at `app/api/khan-academy/route.ts` that proxies requests to Khan Academy's REST API. The Khan Academy API v1 base URL is `https://www.khanacademy.org/api/v1/` and its key endpoints are: - `GET /topictree` — the full topic tree (very large, ~10MB, cache aggressively) - `GET /topic/{topic_slug}` — topic details and child list by slug (e.g., `algebra`, `geometry`) - `GET /topic/{topic_slug}/exercises` — exercises under a topic - `GET /topic/{topic_slug}/videos` — videos under a topic - `GET /exercises/{exercise_name}` — specific exercise details - `GET /videos/{youtube_id}` — specific video details The API route should accept a `resource` query parameter to select which endpoint to call, plus additional parameters like `slug` for topic-specific requests. This keeps your API surface manageable without creating dozens of separate routes. Khan Academy's API does not require authentication for public content, but it does apply rate limiting. Proxying through your API route also lets you add server-side caching — the topic tree rarely changes, so caching it for hours is safe. Use Next.js's built-in fetch caching with `next: { revalidate: 3600 }` for topic data. The topic slug system is the key to navigating Khan Academy content. Top-level subject slugs include: `math`, `science`, `computing`, `humanities`, `test-prep`, `college-careers-more`. Each has sub-topic slugs you can discover by fetching the parent topic.
1// app/api/khan-academy/route.ts2import { NextRequest, NextResponse } from 'next/server';34const KA_BASE = 'https://www.khanacademy.org/api/v1';56async function fetchKA(path: string, cacheSeconds = 3600) {7 const res = await fetch(`${KA_BASE}${path}`, {8 headers: { Accept: 'application/json' },9 next: { revalidate: cacheSeconds },10 });11 if (!res.ok) throw new Error(`Khan Academy API error: ${res.status} ${res.statusText}`);12 return res.json();13}1415export async function GET(request: NextRequest) {16 const { searchParams } = new URL(request.url);17 const resource = searchParams.get('resource');18 const slug = searchParams.get('slug');1920 try {21 switch (resource) {22 case 'topic': {23 if (!slug) return NextResponse.json({ error: 'slug required' }, { status: 400 });24 const data = await fetchKA(`/topic/${slug}`);25 // Return normalized subset to reduce payload size26 return NextResponse.json({27 id: data.id,28 title: data.translated_title || data.title,29 description: data.translated_description || data.description,30 slug: data.node_slug,31 children: (data.children || []).map((c: any) => ({32 id: c.id,33 title: c.translated_title || c.title,34 slug: c.node_slug,35 kind: c.kind,36 thumbnail: c.image_url || null,37 duration: c.duration || null,38 ka_url: c.ka_url || null,39 })),40 });41 }42 case 'videos': {43 if (!slug) return NextResponse.json({ error: 'slug required' }, { status: 400 });44 const data = await fetchKA(`/topic/${slug}/videos`);45 return NextResponse.json(data);46 }47 case 'exercises': {48 if (!slug) return NextResponse.json({ error: 'slug required' }, { status: 400 });49 const data = await fetchKA(`/topic/${slug}/exercises`);50 return NextResponse.json(data);51 }52 default:53 return NextResponse.json({ error: 'Invalid resource. Use: topic, videos, exercises' }, { status: 400 });54 }55 } catch (err: any) {56 return NextResponse.json({ error: err.message }, { status: 500 });57 }58}Pro tip: Avoid fetching the full /topictree endpoint — it returns a ~10MB JSON blob of all Khan Academy content. Instead, navigate the tree hierarchically starting from specific subject slugs, fetching only one level at a time.
Expected result: A working API route that fetches Khan Academy topics, videos, and exercises with server-side caching, returning normalized content data.
Configure Environment Variables and Deploy
Configure Environment Variables and Deploy
Khan Academy's public content API does not require any API key for reading topics, videos, and exercises. However, if you plan to track user progress or access learner data, you'll need OAuth credentials from Khan Academy's developer program. For a public content browsing app, you only need one environment variable: `NEXT_PUBLIC_APP_URL` set to your Vercel deployment URL (e.g., `https://your-app.vercel.app`). This is used for absolute URL construction in server components when calling your own API routes. If you plan to implement user progress tracking via Khan Academy's user API (which requires OAuth 1.0a with user authorization), add `KHAN_ACADEMY_CONSUMER_KEY` and `KHAN_ACADEMY_CONSUMER_SECRET` as server-only environment variables. Apply for API access at khanacademy.org/api/auth2 — note that Khan Academy's developer program approval can take several weeks. Navigate to your Vercel project → Settings → Environment Variables to add these values. For a content-only integration, you may not need any Vercel environment variables at all — just deploy and the API route will work with the public Khan Academy API without any credentials. Vercel's edge caching will also cache your API route responses at the CDN level when you use fetch with `next: { revalidate }`. This means repeated requests to the same Khan Academy topic slug will be served from Vercel's edge cache rather than hitting Khan Academy's servers every time.
Pro tip: Add `export const revalidate = 3600;` at the top of your API route file to apply a 1-hour cache to all GET responses from that route, reducing Khan Academy API calls significantly.
Expected result: App deployed to Vercel with Khan Academy content loading correctly from the API route. No credentials needed for public content access.
Connect the UI Components to the API Route
Connect the UI Components to the API Route
Update the V0-generated components to fetch content from your `/api/khan-academy` route. Start with a specific subject slug (like `algebra`) to verify the integration works end-to-end before building the full navigation. For a React Server Component approach, fetch the topic data directly in the server component and pass it as props to client components. This gives you server-side rendering of the content list with no client-side loading spinner on initial page load. Use Next.js's `generateStaticParams` for popular subject pages to pre-render them at build time. For the client-side navigation (clicking into sub-topics), use a client component that maintains the current slug in state and calls `/api/khan-academy?resource=topic&slug={currentSlug}` via `fetch`. Update the breadcrumb trail as users navigate deeper into the topic hierarchy by pushing slug history into an array. For embedding videos, extract the YouTube video ID from Khan Academy's `youtube_id` field and use `https://www.youtube.com/embed/{youtube_id}` in an iframe. Khan Academy video thumbnails are available at `https://img.youtube.com/vi/{youtube_id}/mqdefault.jpg`. For exercises, the Khan Academy exercise URL format is `https://www.khanacademy.org/e/{exercise_name}` which can be embedded in an iframe for in-page practice. Cache the fetched topic data in React state as users navigate so that going back to a previously visited topic doesn't re-fetch — a simple `Map<slug, topicData>` cache in a React context or Zustand store works well for this.
Update the learning portal to fetch from /api/khan-academy?resource=topic&slug=algebra on load. Map the children array to content cards: show a YouTube thumbnail for Video items using https://img.youtube.com/vi/{youtube_id}/mqdefault.jpg, and a book icon for Exercise and Article items. When a Topic child is clicked, re-fetch with that topic's slug and update the breadcrumb. Add a back button that goes up one level in the breadcrumb.
Paste this in V0 chat
1// Example: Client component with topic navigation2'use client';3import { useState, useEffect } from 'react';45interface KAItem {6 id: string;7 title: string;8 slug: string;9 kind: 'Topic' | 'Video' | 'Exercise' | 'Article';10 thumbnail: string | null;11 ka_url: string | null;12}1314export function TopicBrowser({ initialSlug = 'algebra' }: { initialSlug?: string }) {15 const [slugHistory, setSlugHistory] = useState<string[]>([initialSlug]);16 const [items, setItems] = useState<KAItem[]>([]);17 const [loading, setLoading] = useState(true);1819 const currentSlug = slugHistory[slugHistory.length - 1];2021 useEffect(() => {22 setLoading(true);23 fetch(`/api/khan-academy?resource=topic&slug=${currentSlug}`)24 .then(r => r.json())25 .then(data => { setItems(data.children || []); setLoading(false); })26 .catch(() => setLoading(false));27 }, [currentSlug]);2829 const navigateTo = (slug: string) => setSlugHistory(h => [...h, slug]);30 const goBack = () => setSlugHistory(h => h.slice(0, -1));3132 return (33 <div>34 {slugHistory.length > 1 && (35 <button onClick={goBack} className="mb-4 text-blue-600 hover:underline">36 ← Back to {slugHistory[slugHistory.length - 2]}37 </button>38 )}39 {loading ? <p>Loading...</p> : (40 <div className="grid grid-cols-2 md:grid-cols-3 gap-4">41 {items.map(item => (42 <div key={item.id} className="border rounded-lg p-4 cursor-pointer hover:border-blue-500"43 onClick={() => item.kind === 'Topic' ? navigateTo(item.slug) : window.open(item.ka_url || '#', '_blank')}>44 {item.thumbnail && <img src={item.thumbnail} alt={item.title} className="w-full rounded mb-2" />}45 <span className="text-xs font-medium text-blue-600">{item.kind}</span>46 <h3 className="font-semibold text-sm mt-1">{item.title}</h3>47 </div>48 ))}49 </div>50 )}51 </div>52 );53}Pro tip: Khan Academy's `kind` field distinguishes between 'Topic' (navigable sub-category), 'Video', 'Exercise', and 'Article' content items. Use different card styles or icons for each kind to give users visual cues about what they'll get when they click.
Expected result: The learning portal displays real Khan Academy content with working navigation through the topic hierarchy and clickable links to videos and exercises.
Common use cases
Subject Learning Path Explorer
Build an explorer interface where users browse Khan Academy's topic tree for a specific subject — say, Algebra — and see a structured path of videos and exercises to complete. V0 generates the tree navigation UI and progress tracking components.
Create a learning path explorer with a left sidebar showing a topic tree (subject → unit → lesson), and a main content area showing the selected lesson's videos and exercises as cards. Each card has a title, description, video thumbnail or exercise icon, and an 'Open' button. Add a progress bar at the top showing completion percentage.
Copy this prompt to try it in V0
Student Homework Helper
Build a homework helper where students enter a math topic and the app displays relevant Khan Academy videos and practice exercises. The search feature queries the Khan Academy topic API and returns the most relevant content for the student to review.
Build a homework help search page with a large search input at the top. Below, show two columns: 'Watch Videos' (video cards with thumbnail and duration) and 'Practice Exercises' (exercise cards with difficulty level and topic name). Show empty state illustrations when no search has been made. Include a 'Suggested Topics' section with common subjects.
Copy this prompt to try it in V0
Teacher Resource Dashboard
Create a teacher dashboard where educators can browse Khan Academy content by subject, bookmark specific videos or exercises for their class, and generate shareable links to Khan Academy content for student assignments.
Create a teacher resource browser with a subject filter dropdown, a content grid showing Khan Academy videos and exercises as cards with title and description, a bookmark toggle button on each card, and a 'My Bookmarks' sidebar panel. Bookmarked items should persist and show a share link button.
Copy this prompt to try it in V0
Troubleshooting
API returns 404 for topic slugs that appear to exist on khanacademy.org
Cause: Khan Academy periodically restructures its topic tree and slug formats change. The API slug may differ from the URL slug shown in the browser.
Solution: Use the /api/v1/topic/{slug} endpoint with the slug from the Khan Academy URL path. If a topic is not found, try the parent topic slug and navigate down. You can also start from a top-level subject slug and traverse the children array to find the correct slug.
API route returns stale content even after Khan Academy updates its content
Cause: The Next.js fetch cache is serving the cached version based on the revalidate interval you set.
Solution: Use on-demand revalidation to force refresh specific cached routes when needed. Alternatively, reduce the revalidate interval for rapidly-changing content, or use `cache: 'no-store'` for content that must always be fresh.
1// For fresh content on every request:2const res = await fetch(`${KA_BASE}/topic/${slug}`, { cache: 'no-store' });34// Or use shorter cache interval:5const res = await fetch(`${KA_BASE}/topic/${slug}`, { next: { revalidate: 600 } });Exercise iframe shows 'Refused to connect' or content security policy error
Cause: Khan Academy exercises may not allow embedding in iframes from unknown domains due to X-Frame-Options or CSP headers.
Solution: Instead of embedding exercises in an iframe, link directly to the Khan Academy exercise page that opens in a new tab. Khan Academy's own embed widget or a deep link to the exercise page (`https://www.khanacademy.org/e/{exercise_name}`) is the recommended approach.
1<a href={`https://www.khanacademy.org/e/${exercise.name}`} target="_blank" rel="noopener noreferrer">2 Practice on Khan Academy3</a>Rate limiting errors (429) from the Khan Academy API
Cause: Your app is making too many requests to Khan Academy's API without caching, hitting rate limits.
Solution: Implement aggressive server-side caching using Next.js fetch revalidate. Topic content almost never changes — 1-24 hour caches are appropriate. Also implement client-side caching in a React context so navigating back to a visited topic doesn't re-fetch.
1// Cache for 24 hours for stable topic tree data2const res = await fetch(`${KA_BASE}/topic/${slug}`, {3 next: { revalidate: 86400 }4});Best practices
- Cache topic tree responses for at least 1 hour using Next.js fetch revalidation — Khan Academy content rarely changes and aggressive caching dramatically improves performance
- Never fetch the full /topictree endpoint — it is ~10MB and slow. Navigate the hierarchy by fetching one topic level at a time.
- Link to Khan Academy exercise pages rather than trying to embed them — embedding is unreliable due to iframe restrictions
- Normalize the API response before sending to the frontend to strip large unused fields and reduce payload sizes
- Build the topic browsing with client-side slug history so users can navigate back without triggering new API calls for previously loaded topics
- Display the Khan Academy attribution clearly — their terms of service require crediting Khan Academy when using their content
- For user progress tracking features, apply for API access through Khan Academy's developer program well in advance — approval takes time
Alternatives
Schoology is an institutional LMS with real course management, grade tracking, and assignments — choose Schoology if you need a full school management system rather than a content library.
Teachable lets you sell your own custom courses — choose Teachable if you want to monetize original educational content rather than surface existing free Khan Academy material.
Alternative integration option for educational content.
Frequently asked questions
Do I need an API key to use the Khan Academy API?
No API key is required to access Khan Academy's public content API. You can fetch topics, videos, and exercises without any credentials. An API key is only needed if you want to access user-specific data like progress, completed exercises, or badges — and that requires applying for developer access through Khan Academy's OAuth program.
Can I use Khan Academy content commercially in my app?
Khan Academy content is licensed under Creative Commons (CC BY-NC-SA 4.0) for non-commercial use. Commercial use of their content requires a separate license agreement with Khan Academy. If you're building a commercial product, contact Khan Academy's partnerships team. For non-commercial educational tools, you can use the API freely while crediting Khan Academy.
How do I find the right topic slug for a specific subject?
Start with a top-level subject slug — 'math', 'science', 'computing', 'humanities', or 'test-prep'. Fetch that topic and examine the children array to find sub-topic slugs. Each child has a node_slug field that you can use to navigate deeper. You can also look at the Khan Academy URL for any topic — the slug is the last path segment before the content item.
Does Khan Academy have an official npm package or SDK?
Khan Academy does not publish an official npm package or SDK. The REST API at khanacademy.org/api/v1 is the primary integration method. You'll call it directly with fetch from your Next.js API routes. No third-party SDK is widely used either — the API is simple enough that direct fetch calls with proper caching are the standard approach.
Can I track which Khan Academy exercises students have completed in my app?
User progress tracking requires OAuth 1.0a authentication with user authorization. Students would need to authorize your app to access their Khan Academy account, and you'd need approved developer credentials from Khan Academy. For simpler tracking without Khan Academy integration, store completion data in your own database — a simple table recording which exercise slugs a user has opened or marked complete.
How large is the Khan Academy topic tree?
The full topic tree returned by /api/v1/topictree is approximately 10MB of JSON containing all domains, subjects, topics, and content items. It is too large to fetch on every request. The recommended approach is hierarchical navigation — fetch one topic level at a time using the /topic/{slug} endpoint, which returns a manageable subset with just the children of that specific topic.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation