Skip to main content
RapidDev - Software Development Agency
v0-integrationsNext.js API Route

How to Integrate Learnworlds with V0

To integrate LearnWorlds with V0 by Vercel, generate a course portal or enrollment UI with V0, then create Next.js API routes that call the LearnWorlds REST API using your API key and school domain. Store credentials in Vercel environment variables to keep them server-side. Your app can display courses, check enrollments, and sync user data without exposing your API key to the browser.

What you'll learn

  • How to generate a course catalog or portal UI with V0 and connect it to LearnWorlds
  • How to create Next.js API routes that fetch LearnWorlds courses and enrollments
  • How to store LearnWorlds API credentials securely in Vercel environment variables
  • How to display course progress and completion data in a custom dashboard
  • How to receive LearnWorlds webhook events for enrollment and completion triggers
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate13 min read30 minutesOtherApril 2026RapidDev Engineering Team
TL;DR

To integrate LearnWorlds with V0 by Vercel, generate a course portal or enrollment UI with V0, then create Next.js API routes that call the LearnWorlds REST API using your API key and school domain. Store credentials in Vercel environment variables to keep them server-side. Your app can display courses, check enrollments, and sync user data without exposing your API key to the browser.

Build Custom Course Portals for LearnWorlds with V0 and Next.js API Routes

LearnWorlds differentiates itself from simpler course platforms with interactive video (clickable hotspots, in-video questions), SCORM support, and white-label customization that allows complete removal of the LearnWorlds branding. These features make it popular for corporate training, professional certification programs, and premium education businesses. The REST API extends this white-label capability to your own Next.js frontend — you can build a fully custom course portal with V0 that queries LearnWorlds as the backend, displaying courses in your own design rather than inside the LearnWorlds interface.

The LearnWorlds API is authenticated with an API key passed in the Lw-Client header alongside your school domain in the URL. Each LearnWorlds school has its own subdomain (yourschool.learnworlds.com), and API calls are scoped to a school — you interact with your school's courses, users, and enrollments specifically. This makes the integration straightforward: one API key, one school domain, all data is pre-filtered to your content.

For V0-built course portals, the most common use cases are displaying a custom course catalog on your marketing site, embedding a progress dashboard in a member area, and triggering downstream actions (sending a completion email, issuing a certificate, updating a CRM) when LearnWorlds webhooks notify your app that a student finished a course. V0's ability to quickly generate sophisticated dashboard layouts makes it well-suited for building the kind of custom analytics and progress displays that the native LearnWorlds interface does not support.

Integration method

Next.js API Route

LearnWorlds integrates with V0-generated Next.js apps through server-side API routes that call the LearnWorlds REST API. Your API credentials are stored as server-only Vercel environment variables and never reach the browser. The course catalog and enrollment UI components V0 generates fetch data through your Next.js routes, which proxy requests to the LearnWorlds API for course listings, user enrollments, and progress data. Webhooks from LearnWorlds can be received by dedicated API routes to trigger downstream actions when students complete courses or make purchases.

Prerequisites

  • A LearnWorlds account with at least the Starter plan — the API is available on all paid plans but not the free trial
  • Your LearnWorlds school domain — the subdomain of your school URL (e.g., 'yourschool' from yourschool.learnworlds.com)
  • A LearnWorlds API key — generated in LearnWorlds Dashboard → Settings → API Access → Create new API key
  • At least one course published in LearnWorlds so you have data to fetch via the API
  • A V0 account at v0.dev and a Vercel account for deploying your Next.js app

Step-by-step guide

1

Generate the Course UI with V0

Open V0 at v0.dev and describe the course portal interface you want to build. LearnWorlds course data includes title, description, thumbnail image URL, price, category, and enrollment count — describe a UI that displays these fields meaningfully. For a course catalog, a card grid with course thumbnails, titles, and enrollment CTAs works well. For a student dashboard, a list of enrolled courses with progress bars communicates learning progress clearly. Be specific about the interaction states — what happens when a user clicks a course card, how enrollment status changes the button text (Enroll vs Continue Learning), and what the loading state looks like while API data fetches. Include the API route path in your prompt (/api/learnworlds/courses for catalog data, /api/learnworlds/enrollments for student data) so V0 generates the fetch calls pointed at the correct endpoints from the start. V0 generates with Tailwind CSS and shadcn/ui, which provides card components, badge components, and progress bar components that work naturally for course catalog and student dashboard layouts. After generating the components, use V0's Git panel to push to GitHub so Vercel can deploy them.

V0 Prompt

Build a course discovery page with a hero section ('Master New Skills with Our Expert-Led Courses') and below it a responsive grid of course cards. Each card fetched from /api/learnworlds/courses should show: course image (16:9 ratio with object-cover), category badge in the top-left, course title in bold, truncated description, star rating display (4.5/5 style), student count, and price with a green 'Enroll Now' button. Add a skeleton loading state for the cards while data loads. Include a top filter bar with category pills and a search box.

Paste this in V0 chat

Pro tip: Ask V0 to generate skeleton loading cards (a pulsing gray placeholder matching the card dimensions) for the loading state. This gives your course catalog a professional feel while the LearnWorlds API data loads.

Expected result: A course catalog page renders in V0's preview with card grid layout, filter bar, loading skeletons, and enrollment buttons. The component fetches from /api/learnworlds/courses.

2

Create the LearnWorlds API Routes

Create the Next.js API routes that fetch data from the LearnWorlds REST API and return it to your frontend components. The LearnWorlds API base URL is https://{{school-domain}}.learnworlds.com/v2, where {{school-domain}} is your school's subdomain. Authentication uses two headers: Lw-Client with your API key and Accept: application/json. All responses are JSON. The courses endpoint is GET /courses and returns an array of course objects with id, title, description, image, price, and metadata. The enrollments endpoint is GET /users/{userId}/enrollments for a specific user's enrolled courses. The users endpoint is GET /users and supports filtering by email to look up a specific user's ID. For course progress, use GET /users/{userId}/progress. Most V0 course portals start with just the courses listing endpoint and add user-specific endpoints when authentication is added to the app. Note that LearnWorlds paginates responses using page and per_page query parameters — the default page size is 20. For course catalogs with more than 20 courses, implement pagination in your API route using the total_pages field in the response to fetch all pages.

app/api/learnworlds/courses/route.ts
1// app/api/learnworlds/courses/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3
4const LW_SCHOOL = process.env.LEARNWORLDS_SCHOOL_DOMAIN;
5const LW_API_KEY = process.env.LEARNWORLDS_API_KEY;
6
7function getLearnWorldsHeaders() {
8 return {
9 'Lw-Client': LW_API_KEY!,
10 Accept: 'application/json',
11 'Content-Type': 'application/json',
12 };
13}
14
15async function fetchAllCourses() {
16 const courses: unknown[] = [];
17 let page = 1;
18 let totalPages = 1;
19
20 do {
21 const url = `https://${LW_SCHOOL}.learnworlds.com/v2/courses?page=${page}&per_page=20`;
22 const response = await fetch(url, { headers: getLearnWorldsHeaders() });
23
24 if (!response.ok) {
25 throw new Error(`LearnWorlds API error: ${response.status} ${response.statusText}`);
26 }
27
28 const data = await response.json();
29 courses.push(...(data.data ?? []));
30 totalPages = data.meta?.totalPages ?? 1;
31 page++;
32 } while (page <= totalPages);
33
34 return courses;
35}
36
37export async function GET(request: NextRequest) {
38 if (!LW_SCHOOL || !LW_API_KEY) {
39 return NextResponse.json(
40 { error: 'LearnWorlds is not configured' },
41 { status: 500 }
42 );
43 }
44
45 try {
46 const courses = await fetchAllCourses();
47 return NextResponse.json({ courses }, { status: 200 });
48 } catch (error) {
49 const message = error instanceof Error ? error.message : 'Unknown error';
50 console.error('LearnWorlds courses fetch failed:', message);
51 return NextResponse.json(
52 { error: 'Failed to fetch courses', details: message },
53 { status: 500 }
54 );
55 }
56}
57
58// app/api/learnworlds/enrollments/route.ts
59// GET /api/learnworlds/enrollments?userId=USER_ID
60export async function GETEnrollments(request: NextRequest) {
61 const { searchParams } = new URL(request.url);
62 const userId = searchParams.get('userId');
63
64 if (!userId) {
65 return NextResponse.json({ error: 'userId is required' }, { status: 400 });
66 }
67
68 const url = `https://${LW_SCHOOL}.learnworlds.com/v2/users/${userId}/enrollments`;
69 const response = await fetch(url, { headers: getLearnWorldsHeaders() });
70
71 if (!response.ok) {
72 return NextResponse.json(
73 { error: 'Failed to fetch enrollments' },
74 { status: response.status }
75 );
76 }
77
78 const data = await response.json();
79 return NextResponse.json({ enrollments: data.data ?? [] });
80}

Pro tip: Cache the courses response with Next.js route segment config to avoid hitting the LearnWorlds API on every page load. Add export const revalidate = 300 at the top of your route file to cache the response for 5 minutes — course catalogs change infrequently and caching dramatically reduces API calls.

Expected result: GET /api/learnworlds/courses returns a JSON array of course objects from your LearnWorlds school. The course cards in your V0-generated frontend populate with real course data.

3

Add Environment Variables and Deploy to Vercel

Push your code to GitHub and configure LearnWorlds credentials in Vercel. Open the Vercel Dashboard, select your project, and navigate to Settings → Environment Variables. Add LEARNWORLDS_SCHOOL_DOMAIN with your school's subdomain only — for example, if your school URL is yourschool.learnworlds.com, the value should be 'yourschool' (without '.learnworlds.com'). Add LEARNWORLDS_API_KEY with your API key from LearnWorlds Dashboard → Settings → API Access. Neither variable should have the NEXT_PUBLIC_ prefix — the school domain and API key are server-side values used only in your API routes. After saving both variables, trigger a redeployment from Vercel's Deployments tab. After deployment, visit your deployed app's course catalog page and verify that real course data from LearnWorlds appears in the cards. If courses do not load, check the Vercel function logs in Vercel Dashboard → Functions → select your API route → Logs to see the specific error from the LearnWorlds API. For complex integrations requiring enrollment management and user authentication, RapidDev's team can help wire up the full student authentication flow between your Vercel app and LearnWorlds.

Pro tip: Test your API key and school domain combination locally first by running curl https://yourschool.learnworlds.com/v2/courses -H 'Lw-Client: YOUR_API_KEY' -H 'Accept: application/json' in your terminal. A successful response returns a JSON object with a data array of courses.

Expected result: The deployed Vercel app displays your LearnWorlds courses in the custom V0-generated catalog. The LEARNWORLDS_API_KEY and LEARNWORLDS_SCHOOL_DOMAIN environment variables are set and the API routes return course data.

Common use cases

Custom Course Catalog Page

A branded course catalog page built with V0 that displays your LearnWorlds courses in a custom card grid layout. Students can browse courses, see enrollment status, and click through to the actual LearnWorlds course player — with your branding throughout the discovery experience.

V0 Prompt

Create a course catalog page with a grid of course cards. Each card should show a course thumbnail image, title, description (truncated to 2 lines), difficulty badge (Beginner/Intermediate/Advanced), duration in hours, enrollment count, and an Enroll Now button. Include a filter bar at the top with category buttons and a search input. Fetch courses from /api/learnworlds/courses. Use a clean educational platform design with blue accent colors.

Copy this prompt to try it in V0

Student Progress Dashboard

An authenticated member area showing a student's enrolled courses, completion percentages, and earned certificates. The dashboard fetches enrollment and progress data from LearnWorlds via API routes and displays it in a visual progress tracker alongside upcoming lesson reminders.

V0 Prompt

Build a student dashboard showing enrolled courses as cards with circular progress indicators (percentage complete), last accessed date, and a Continue Learning button. Include a Completed Courses section with certificate download buttons. Add a stats row at the top showing total courses enrolled, completed, and hours learned. Fetch data from /api/learnworlds/enrollments for the current user.

Copy this prompt to try it in V0

Completion Webhook to CRM Sync

When a student completes a LearnWorlds course, a webhook fires to your Next.js app, which then updates the student's record in your CRM, sends a congratulations email, and logs the completion. This automation replaces manual certificate tracking with an event-driven pipeline.

V0 Prompt

Create a webhook status page at /admin/webhooks showing a table of recent LearnWorlds completion events. Each row should display student email, course title, completion date, and a processing status badge (Received/Processed/Failed). Include a Re-process button for failed events. Fetch from /api/learnworlds/webhook-log. Use a clean admin dashboard style.

Copy this prompt to try it in V0

Troubleshooting

API returns 401 Unauthorized or 403 Forbidden on all requests

Cause: The API key is incorrect, has been revoked, or the Lw-Client header name is misspelled. LearnWorlds requires the exact header name 'Lw-Client' — 'LW-Client' or 'lw-client' will not work.

Solution: Verify the API key in Vercel environment variables matches exactly what is shown in LearnWorlds Dashboard → Settings → API Access. Check that the header is exactly 'Lw-Client' (capital L, lowercase w, capital C) in your fetch call. Regenerate the API key in LearnWorlds if unsure — old keys are immediately invalidated.

typescript
1// Correct header name (case-sensitive):
2headers: {
3 'Lw-Client': process.env.LEARNWORLDS_API_KEY!,
4 'Accept': 'application/json',
5}

API returns 404 with 'school not found' or connection refused

Cause: The LEARNWORLDS_SCHOOL_DOMAIN environment variable contains the wrong subdomain or includes the full domain (learnworlds.com) instead of just the subdomain prefix.

Solution: Check that LEARNWORLDS_SCHOOL_DOMAIN contains only the subdomain part. If your school URL is https://myacademy.learnworlds.com, the value should be 'myacademy' — not 'myacademy.learnworlds.com'. Verify the value in Vercel Dashboard → Settings → Environment Variables.

Only 20 courses are returned even though more exist in LearnWorlds

Cause: LearnWorlds paginates API responses with a default limit of 20 items per page. Without implementing pagination, only the first page of results is returned.

Solution: Implement the pagination loop shown in the API route code above — check data.meta.totalPages and loop through all pages to collect the full course list. Alternatively, set per_page=100 in the query string if you have fewer than 100 courses to avoid multiple requests.

typescript
1// Add pagination to your fetch call:
2const url = `https://${LW_SCHOOL}.learnworlds.com/v2/courses?page=${page}&per_page=100`;

Course images are not loading — image URLs return 403 or broken images

Cause: LearnWorlds course image URLs may include signed tokens that expire, or the images may require authentication headers that the browser cannot send directly for <img> src attributes.

Solution: Proxy image requests through a Next.js API route or use Next.js Image component with a remotePatterns configuration that allows the LearnWorlds CDN domain. Add the LearnWorlds CDN domain to next.config.ts under images.remotePatterns.

typescript
1// next.config.ts
2const nextConfig = {
3 images: {
4 remotePatterns: [
5 { protocol: 'https', hostname: '*.learnworlds.com' },
6 { protocol: 'https', hostname: '*.lwstatic.com' },
7 ],
8 },
9};

Best practices

  • Store LEARNWORLDS_API_KEY and LEARNWORLDS_SCHOOL_DOMAIN as server-only Vercel environment variables without NEXT_PUBLIC_ prefix — the API key has full school management access
  • Cache course listing responses with Next.js route revalidation (export const revalidate = 300) since course catalogs change infrequently — this reduces LearnWorlds API calls and improves page load speed
  • Use Next.js Image component with remotePatterns for LearnWorlds course thumbnails to get automatic image optimization, WebP conversion, and proper loading behavior
  • Implement pagination from the start even if you currently have fewer than 20 courses — as your catalog grows, missing pagination will silently omit newer courses
  • Handle the difference between guest users (browsing catalog) and authenticated users (checking enrollment status) — design your API routes to work with both anonymous and user-authenticated requests
  • Use LearnWorlds webhooks for completion events rather than polling for progress — webhook-driven automations are more reliable and do not waste API quota
  • Test with your real LearnWorlds content rather than mock data from the start — course image URLs, category names, and pricing formats often differ from what you expect

Alternatives

Frequently asked questions

Does LearnWorlds have a public REST API on all plans?

The LearnWorlds API is available on all paid plans (Starter and above) but not on the free trial. The Starter plan provides full API access for course management, user management, and enrollment data. If you are on a trial, you will need to upgrade to a paid plan before the API key option appears in Settings.

Can I use the LearnWorlds API to enroll users in courses?

Yes — the LearnWorlds API supports creating enrollments via POST /users/{userId}/enrollments with the courseId in the request body. This requires the user to already exist in LearnWorlds. You can create users via POST /users and then enroll them. This pattern is useful when you sell access through your own checkout and want to automatically grant LearnWorlds enrollment on purchase completion.

How does authentication work for the student dashboard use case?

The LearnWorlds API itself uses your server-side API key for all calls — there is no separate user authentication in the API. For a student dashboard, you need to first authenticate users in your Next.js app (using Clerk, Auth0, or NextAuth), then use the authenticated user's email to look up their LearnWorlds user ID via GET /users?email={email}, and finally fetch their enrollments using that user ID. The authentication is handled by your app; LearnWorlds just provides the data.

Can I embed the actual LearnWorlds course player in my V0-generated app?

LearnWorlds does not offer an embeddable course player via iframe — the course content plays within LearnWorlds' own interface at your school URL. Your V0 integration handles the discovery, catalog, and metadata display; when a student clicks to start a course, they are redirected to the LearnWorlds school URL to access the actual video content and interactive elements.

How long does it take for LearnWorlds API responses to return?

LearnWorlds API responses typically return in 200-500ms for single-resource requests. Course listing with pagination can take 500ms-2 seconds depending on the number of courses. Cache course listings aggressively (5-10 minute revalidation in Next.js) since catalog changes are infrequent, and keep enrollment/progress requests uncached since they reflect current student state.

What webhook events does LearnWorlds support?

LearnWorlds supports webhooks for course completion, enrollment creation, enrollment cancellation, and quiz/exam completion events. Webhooks are configured in LearnWorlds Dashboard → Settings → Webhooks with a delivery URL pointing to your Next.js API route. Webhook payloads are JSON with event type, user ID, course ID, and relevant completion metadata. Verify webhook authenticity by checking the X-LW-Signature header using your webhook secret.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.