Skip to main content
RapidDev - Software Development Agency
lovable-integrationsEdge Function Integration

How to Integrate Lovable with Moodle

Integrate Moodle with Lovable by creating an Edge Function that calls Moodle's Web Services REST API using a token stored in Cloud → Secrets. Moodle exposes courses, users, grades, assignments, and completion data through a function-based API system. You can build custom learning portals, grade dashboards, and enrollment management tools on top of any self-hosted or cloud Moodle instance.

What you'll learn

  • How to enable Moodle Web Services and create a web service token in your Moodle admin panel
  • How to store your Moodle token and site URL securely in Lovable's Cloud → Secrets
  • How Moodle's wsfunction API calling convention works and which functions expose what data
  • How to build a Deno Edge Function that proxies Moodle Web Services REST calls
  • How to display courses, grades, and enrollment data in a Lovable React frontend
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate16 min read45 minutesEducationMarch 2026RapidDev Engineering Team
TL;DR

Integrate Moodle with Lovable by creating an Edge Function that calls Moodle's Web Services REST API using a token stored in Cloud → Secrets. Moodle exposes courses, users, grades, assignments, and completion data through a function-based API system. You can build custom learning portals, grade dashboards, and enrollment management tools on top of any self-hosted or cloud Moodle instance.

Build custom Moodle frontends and dashboards in Lovable

Moodle is the most widely deployed open-source LMS in the world, powering universities, K-12 schools, and corporate training programs across more than 240 countries. Unlike SaaS platforms, Moodle is self-hosted — your institution runs its own Moodle instance on its own servers. This means the integration points to your specific Moodle installation URL, not a shared API endpoint. The trade-off is complete data ownership and fine-grained configuration control.

Moodle's Web Services API uses a distinctive calling pattern: instead of different URL paths for different resources (GET /courses, GET /grades), all requests go to a single endpoint — typically yoursite.edu/webservice/rest/server.php — with the specific operation specified as a wsfunction query parameter. For example, to get all courses a user is enrolled in, you call ?wstoken={token}&wsfunction=core_enrol_get_users_courses&userid={id}&moodlewsrestformat=json. Learning this pattern is the key to working with Moodle's API.

For Lovable developers, this means a single generic Edge Function can handle all Moodle API operations by accepting the wsfunction name and parameters as inputs. Your frontend components call the Edge Function with the specific Moodle function they need, and the Edge Function constructs the correct Moodle API request, injects the token, and returns the data. This architecture is both secure (token never leaves the server) and flexible (works with any Moodle web service function your instance has enabled).

Integration method

Edge Function Integration

Moodle does not have a Lovable shared connector. The integration uses Moodle's Web Services REST API with token authentication — your Moodle web service token is stored in Cloud → Secrets and a Deno Edge Function proxies all calls to your Moodle instance server-side. Moodle's API uses a unique function-based calling convention (wsfunction parameter) rather than standard REST endpoint paths.

Prerequisites

  • A Lovable account with at least one project created and deployed
  • A running Moodle instance (self-hosted or Moodle Cloud) with admin access
  • Moodle version 2.2 or later (Web Services are available in all modern versions)
  • The URL of your Moodle installation (e.g., https://learn.myschool.edu)
  • Moodle admin or manager role to enable Web Services and create tokens

Step-by-step guide

1

Enable Moodle Web Services and create an API token

Before storing credentials in Lovable, you need to enable Moodle's Web Services feature and create a token for API access. This is done entirely in your Moodle admin panel. Log in to your Moodle site as an administrator. Go to Site Administration (the cog icon or Administration menu). Navigate to Advanced Features. Find the 'Enable web services' toggle and turn it on. Click 'Save changes'. Next, enable the REST protocol. Go to Site Administration → Plugins → Web services → Manage protocols. Find 'REST protocol' in the list and click the eye icon to enable it. This activates the /webservice/rest/server.php endpoint. Now create a web service. Go to Site Administration → Plugins → Web services → External services. Click 'Add'. Name it (e.g., 'Lovable Integration'). Enable it. Under 'Functions', click the service you just created, then 'Add functions'. Add the functions your app needs — common ones include: core_course_get_courses, core_enrol_get_users_courses, core_enrol_get_enrolled_users, gradereport_user_get_grade_items, mod_assign_get_assignments, mod_assign_get_submissions, core_user_get_users. Save. Finally, create a token. Go to Site Administration → Plugins → Web services → Manage tokens. Click 'Add'. Select the user whose permissions the API calls will use (typically an admin account or a dedicated service user). Select the web service you just created. Optionally set an expiry date. Click 'Save changes'. The token is now shown in the token list — copy it. Note: The token inherits the permissions of the user you selected. Use a dedicated service account user with only the permissions needed for your integration — not your personal admin account.

Pro tip: Create a dedicated Moodle user (e.g., 'api-service') with Manager or specific role permissions for the API, rather than using your personal admin token. This way, if the token is ever compromised, you can revoke it without affecting your admin account.

Expected result: Moodle Web Services are enabled. The REST protocol is active. A web service with the required functions is created. A token is generated and ready to store in Lovable's Secrets panel.

2

Store Moodle credentials in Cloud → Secrets

With your Moodle token and site URL ready, store them in Lovable's Cloud → Secrets panel. These encrypted environment variables are accessible only from Edge Functions and never from client-side code. In Lovable, click the '+' icon at the top of the editor to open the Cloud panel. Click the Secrets tab. Click 'Add new secret' and add the following two secrets: - Name: MOODLE_TOKEN — Value: the web service token you generated in Step 1 (a long alphanumeric string) - Name: MOODLE_URL — Value: the base URL of your Moodle installation, without trailing slash (e.g., https://learn.myschool.edu) The MOODLE_URL should be the root URL of your Moodle site — not the API endpoint path. The Edge Function will construct the full API URL by appending /webservice/rest/server.php. Verify the MOODLE_URL is accessible from the public internet. If your Moodle site is behind a firewall or VPN, the Edge Function (which runs on Deno Deploy's infrastructure) will not be able to reach it. For internal Moodle instances, you may need to whitelist Supabase/Deno Deploy IP ranges in your firewall, or expose a specific API proxy endpoint publicly. Lovable's security system actively prevents approximately 1,200 API keys from being hardcoded in application code per day. Using Cloud → Secrets ensures your Moodle token is encrypted and isolated — it is only readable by Edge Functions via Deno.env.get(), not from any frontend code or GitHub repository.

Pro tip: If your Moodle URL uses HTTP (not HTTPS), the Deno Edge Function will still make the request, but this is insecure — your token will be transmitted in plaintext. Always use HTTPS on your Moodle instance when using the API from external services.

Expected result: MOODLE_TOKEN and MOODLE_URL are stored in Cloud → Secrets with masked values. Your Edge Function will read them via Deno.env.get('MOODLE_TOKEN') and Deno.env.get('MOODLE_URL').

3

Create the Moodle Web Services proxy Edge Function

Now create the Edge Function that proxies Moodle Web Services requests. Moodle's API uses GET requests with query parameters rather than a JSON body — each call includes wstoken (the API token), wsfunction (the Moodle function to call), and moodlewsrestformat=json (to get JSON responses instead of XML). Paste this prompt into Lovable's chat to generate the Edge Function: 'Create a Supabase Edge Function at supabase/functions/moodle-api/index.ts. It should accept a POST request with JSON body { wsfunction: string, params: object }. The function should read MOODLE_TOKEN and MOODLE_URL from Deno.env. Construct a GET request to {MOODLE_URL}/webservice/rest/server.php with query parameters: wstoken={token}, wsfunction={wsfunction}, moodlewsrestformat=json, and all entries from params as additional query parameters. Return the Moodle API response as JSON with CORS headers. Handle Moodle exception responses (which have errorcode field instead of normal data) by returning them as 4xx HTTP responses with the Moodle error message.' Moodle API error responses look like: { exception: 'dml_missing_record_exception', errorcode: 'invalidrecord', message: 'Can not find data record...' }. These still return HTTP 200 from Moodle's server — your Edge Function should check for the exception field and return an appropriate error HTTP status (400 or 404) with the error details. Common Moodle functions and their required parameters: - core_course_get_courses — no required params (returns all courses) - core_enrol_get_users_courses — userid (integer) - core_enrol_get_enrolled_users — courseid (integer) - gradereport_user_get_grade_items — courseid (integer), userid (integer) - mod_assign_get_assignments — courseids[0], courseids[1], etc. - core_user_get_users — criteria[0][key]='email', criteria[0][value]='student@school.edu'

Lovable Prompt

Create a Supabase Edge Function at supabase/functions/moodle-api/index.ts. Accept POST requests with body { wsfunction: string, params: Record<string, string|number> }. Read MOODLE_TOKEN and MOODLE_URL from Deno.env. Build a URL: {MOODLE_URL}/webservice/rest/server.php?wstoken={token}&wsfunction={wsfunction}&moodlewsrestformat=json&{params as query string}. Fetch it with GET. If the response JSON contains an 'exception' field, return status 400 with the Moodle error. Otherwise return the data with CORS headers.

Paste this in Lovable chat

supabase/functions/moodle-api/index.ts
1// supabase/functions/moodle-api/index.ts
2const corsHeaders = {
3 'Access-Control-Allow-Origin': '*',
4 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
5};
6
7Deno.serve(async (req) => {
8 if (req.method === 'OPTIONS') {
9 return new Response('ok', { headers: corsHeaders });
10 }
11
12 try {
13 const moodleToken = Deno.env.get('MOODLE_TOKEN');
14 const moodleUrl = Deno.env.get('MOODLE_URL');
15
16 if (!moodleToken || !moodleUrl) {
17 return new Response(
18 JSON.stringify({ error: 'Moodle credentials not configured' }),
19 { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
20 );
21 }
22
23 const { wsfunction, params = {} } = await req.json();
24
25 if (!wsfunction) {
26 return new Response(
27 JSON.stringify({ error: 'wsfunction is required' }),
28 { status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
29 );
30 }
31
32 const queryParams = new URLSearchParams({
33 wstoken: moodleToken,
34 wsfunction,
35 moodlewsrestformat: 'json',
36 });
37
38 // Add all additional params
39 for (const [key, value] of Object.entries(params)) {
40 queryParams.set(key, String(value));
41 }
42
43 const apiUrl = `${moodleUrl}/webservice/rest/server.php?${queryParams.toString()}`;
44
45 const response = await fetch(apiUrl, {
46 headers: { 'User-Agent': 'LovableApp/1.0' },
47 });
48
49 const data = await response.json();
50
51 // Moodle returns errors as HTTP 200 with exception field
52 if (data && data.exception) {
53 return new Response(
54 JSON.stringify({ error: data.message, errorcode: data.errorcode }),
55 { status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
56 );
57 }
58
59 return new Response(JSON.stringify(data), {
60 headers: { ...corsHeaders, 'Content-Type': 'application/json' },
61 });
62 } catch (error) {
63 return new Response(
64 JSON.stringify({ error: error.message }),
65 { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
66 );
67 }
68});

Pro tip: Moodle's array parameters (like courseids[]) use bracket notation in the query string: courseids%5B0%5D=123&courseids%5B1%5D=456. If your Edge Function needs to support array params, handle this by checking if a param value is an array and expanding it into indexed keys before adding to URLSearchParams.

Expected result: The Moodle proxy Edge Function is deployed and visible in the Cloud tab. When called with a valid wsfunction and params, it returns data from your Moodle instance. Moodle error responses are converted to HTTP error status codes.

4

Build course and grade display components

With the Edge Function deployed, build the React components that display Moodle data in your Lovable app. The architecture is the same for all Moodle data: call the Edge Function with the desired wsfunction, handle loading and error states, and render the response data. Paste this prompt into Lovable's chat: 'Create a MoodleDashboard React component with two sections: (1) My Courses: call the moodle-api Edge Function with wsfunction core_enrol_get_users_courses and params { userid: currentMoodleUserId } to fetch enrolled courses. Display each course as a card with fullname, shortname, category, and a progress percentage if available from wsfunction core_completion_get_course_completion_status. (2) Recent Grades: call the moodle-api Edge Function with wsfunction gradereport_user_get_grade_items and params { courseid: selectedCourseId, userid: currentMoodleUserId } for the currently selected course. Show grades in a table with item name, grade value, max grade, and percentage. Highlight failing grades (below 50%) in red.' You will need to map your Lovable app's logged-in user to a Moodle user ID. The cleanest way is to store the Moodle user ID in your Supabase user profile table. When a user first connects, call wsfunction core_user_get_users with criteria[0][key]=email and criteria[0][value]={userEmail} to look up their Moodle ID and store it in your profiles table. For the grade display, Moodle returns grades as a graderaw field (raw numeric value), grademin, grademax, and gradeformatted (display string). Use gradeformatted for display as it includes Moodle's configured grade formatting (letter grades, percentages, etc.). For complex Moodle integrations across multiple sites or with custom Moodle plugins, RapidDev's team can help configure the web service functions and data mapping for your specific institutional setup.

Lovable Prompt

Create a MoodleDashboard page with a course selector showing the user's enrolled courses (from moodle-api Edge Function with wsfunction core_enrol_get_users_courses). When a course is selected, show a grade table below using wsfunction gradereport_user_get_grade_items. Style passing grades green and failing grades red. Add a loading spinner during data fetches and error toast messages if the API call fails.

Paste this in Lovable chat

Pro tip: Moodle course names often contain HTML entities (e.g., &amp; for &). Use a simple decode function in React: const decodeHtml = (html: string) => { const txt = document.createElement('textarea'); txt.innerHTML = html; return txt.value; } before displaying course names.

Expected result: A Moodle dashboard appears in your app showing the user's enrolled courses. Selecting a course loads the grade table with real data from your Moodle instance. The display correctly formats grades and highlights any failing marks.

5

Add assignment tracking and completion monitoring

Extend the dashboard with assignment tracking — showing upcoming assignments with due dates, submission status, and completion data across courses. This requires calling several Moodle functions in sequence. Paste this prompt into Lovable's chat: 'Add an Upcoming Assignments section to the MoodleDashboard. For each enrolled course, call the moodle-api Edge Function with wsfunction mod_assign_get_assignments and params { courseids[0]: courseId } to get assignments. Filter assignments with duedate greater than the current timestamp. Show them in a timeline view sorted by duedate: assignment name, course shortname, due date, and a status badge showing SUBMITTED, DUE SOON (within 3 days), or UPCOMING. Get submission status by calling wsfunction mod_assign_get_submission_status with params { assignid: assignmentId } for each assignment.' Moodle assignment due dates are Unix timestamps (seconds, not milliseconds). Convert them with new Date(duedate * 1000) before displaying or comparing with the current date. For completion tracking at the course level (useful for showing overall progress), use wsfunction core_completion_get_activities_completion_status with params { courseid: courseId, userid: userId }. This returns a list of all activities in the course and their completion status for the given user. Be mindful of Moodle API call volume. Loading assignments for 10 courses requires 10+ separate API calls. Consider batching course IDs in mod_assign_get_assignments (it accepts multiple courseids) rather than calling it once per course. The function accepts courseids[0], courseids[1], etc. — you can pass up to 10-20 courses in a single call.

Lovable Prompt

Add an Upcoming Assignments section to the Moodle dashboard. Fetch assignments using the moodle-api Edge Function with wsfunction mod_assign_get_assignments and all enrolled course IDs. Show assignments due in the next 14 days in a list sorted by due date. Display course name, assignment title, due date formatted as 'Mon Jan 15', and a colored status badge: red for overdue, orange for due within 3 days, green for upcoming.

Paste this in Lovable chat

Pro tip: If mod_assign_get_assignments returns an empty array even though assignments exist, check that the web service function was added to your Moodle web service in the admin panel. Moodle only allows functions that were explicitly added to the service — if you added core_course_get_courses but not mod_assign_get_assignments, the latter will return an error.

Expected result: The dashboard shows upcoming assignments across all enrolled courses with due dates and status indicators. Overdue assignments are highlighted in red. The data reflects the actual assignment state in Moodle including any already-submitted items.

Common use cases

Student course and grade portal

Build a personalized student portal where students see their enrolled courses, current grades, upcoming assignments, and completion progress — a cleaner, faster interface than Moodle's default UI.

Lovable Prompt

Create a student portal that calls my moodle-api Edge Function with wsfunction core_enrol_get_users_courses to get the logged-in student's enrolled courses. Show courses as cards with name, category, and progress percentage (using wsfunction core_completion_get_course_completion_status). Clicking a course shows grades from gradereport_user_get_grade_items. Display an upcoming assignments widget using wsfunction mod_assign_get_assignments filtered to assignments with duedate in the next 7 days.

Copy this prompt to try it in Lovable

Teacher grade book dashboard

Build a teacher-facing dashboard that aggregates grade data across all their courses, shows submission rates for each assignment, and highlights students at risk of failing based on low grades or missing submissions.

Lovable Prompt

Build a grade book dashboard for teachers. Fetch the teacher's courses with wsfunction core_course_get_courses. For each course, get all enrolled students with wsfunction core_enrol_get_enrolled_users and their grades with gradereport_user_get_grades_table. Flag students with an average grade below 60% in red. Show submission counts for each assignment using wsfunction mod_assign_get_submissions. Export the grade data to CSV when the teacher clicks Export.

Copy this prompt to try it in Lovable

Enrollment management admin panel

Build an administrative interface for managing student enrollments — bulk enrolling students into courses, unenrolling them, and tracking enrollment history across the institution.

Lovable Prompt

Create an enrollment management panel that lists all courses from wsfunction core_course_get_courses. Admins can search students by name or email using wsfunction core_user_get_users, see their current enrollments, and enroll or unenroll them from courses using wsfunction enrol_manual_enrol_users and wsfunction enrol_manual_unenrol_users. Show a confirmation modal before bulk changes and log all enrollment actions to a Supabase audit table.

Copy this prompt to try it in Lovable

Troubleshooting

Edge Function returns 'invalidtoken' error from Moodle

Cause: The MOODLE_TOKEN secret is incorrect, has been revoked in Moodle, or the web service associated with the token was disabled.

Solution: Go to your Moodle admin panel → Site Administration → Plugins → Web Services → Manage tokens. Verify the token still exists and is not expired. If it was revoked, create a new token and update the MOODLE_TOKEN secret in Lovable's Cloud → Secrets. Also check that the web service associated with the token is still enabled in Site Administration → Plugins → Web Services → External services.

The Edge Function returns 'accessexception: Access control exception' from Moodle

Cause: The web service token user does not have permission to call the requested wsfunction, or the function was not added to the web service in Moodle's admin panel.

Solution: In Moodle admin, go to Site Administration → Plugins → Web Services → External services. Click on your service and then 'Functions'. Verify the function you are calling (e.g., gradereport_user_get_grade_items) appears in the list. If not, click 'Add functions' and add it. Also verify the token user has the appropriate Moodle role to access the data — a student token cannot read other students' grades.

API calls time out or return network errors in the Edge Function

Cause: The Moodle instance is behind a firewall, on a private network, or uses a self-signed SSL certificate that Deno's fetch does not accept.

Solution: Verify your Moodle URL is accessible from the public internet by pasting it in a browser outside your school network. If Moodle is internal-only, you need to either expose the /webservice/rest/server.php endpoint publicly (via firewall rule or reverse proxy) or set up a VPN connection — which is not possible in Lovable's Edge Function environment. For self-signed SSL, you cannot disable certificate validation in Deno without custom flags, so the best solution is to install a proper Let's Encrypt certificate on your Moodle server.

grade data returns null or empty even though the student has grades in Moodle

Cause: The gradereport_user_get_grade_items function requires both courseid and userid parameters. Calling it without a valid userid returns empty results.

Solution: Verify you are passing the correct Moodle user ID (integer) as the userid parameter, not a UUID or email address. If you are looking up users by email first with core_user_get_users, check that the user exists in Moodle and that your token user has permission to read user data. Also verify that grades are visible to the token user's role — Moodle's grade visibility settings can hide grades from non-teacher accounts even via the API.

Best practices

  • Enable only the Moodle web service functions your app actually needs — each additional function expands the security surface area, so add only what is required
  • Use a dedicated Moodle service user with limited permissions rather than an admin account token — this limits the damage if the token is ever compromised
  • Cache frequently accessed Moodle data (course lists, user profiles) in your Supabase database with a refresh interval rather than calling Moodle on every page load
  • Handle Moodle's Unix timestamp format (seconds) consistently — always multiply by 1000 when creating JavaScript Date objects from Moodle date fields
  • Check that your Moodle token is not set to expire (or set a generous expiry) before deploying to production — expired tokens silently fail with invalidtoken errors
  • Add the moodlewsrestformat=json parameter to all API calls — without it, Moodle returns XML by default which is harder to parse in TypeScript
  • For high-traffic dashboards, implement Supabase-based caching with a last_synced_at column and only refresh data older than 5-10 minutes to avoid overwhelming your Moodle instance
  • Test all wsfunction calls against your specific Moodle version — function availability and parameter formats vary between Moodle 3.x and 4.x versions

Alternatives

Frequently asked questions

Does Moodle have a native Lovable connector?

No. Moodle is not one of Lovable's 17 shared connectors as of March 2026. You integrate it manually using Moodle's Web Services REST API with a token stored in Cloud → Secrets and a Deno Edge Function as a proxy. This tutorial covers the complete setup from enabling Moodle Web Services to building dashboard components.

Do I need to be a Moodle admin to use the API?

You need admin access to enable Web Services and create the initial web service configuration and token in the Moodle admin panel. Once set up, the token can be used with any Moodle user account's permissions. For read operations like fetching course lists and grades, a teacher or manager account is often sufficient. For enrollment management, an admin or manager account with enrolment permissions is required.

Does this integration work with Moodle Cloud (the hosted version)?

Yes. Moodle Cloud (Moodle's own hosted offering) supports Web Services with the same configuration steps. Log in to your Moodle Cloud site as admin, follow the same Web Services setup process, and use your Moodle Cloud site URL (e.g., https://yourschool.moodlecloud.com) as MOODLE_URL. Third-party Moodle hosting providers like Bitnami, Pantheon, or school-hosted instances also work the same way.

How do I handle Moodle's complex array parameters in API calls?

Moodle uses PHP array notation for multi-value parameters: courseids[0]=123&courseids[1]=456. In your Edge Function, when you need to pass an array, expand it into indexed URL parameters before adding to URLSearchParams. For example, for an array of course IDs: courseIds.forEach((id, i) => queryParams.set(`courseids[${i}]`, String(id))). This matches Moodle's expected parameter format.

What Moodle version is required for the Web Services API?

Moodle Web Services are available from Moodle 2.2 onwards. All modern Moodle installations (3.x and 4.x) fully support them. If you are on a very old Moodle installation, upgrading to at least Moodle 3.9 is recommended for API stability and security. Some functions like core_completion_get_course_completion_status require Moodle 3.6 or later.

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.