Connect Retool to Google Classroom by creating a REST API Resource using Google OAuth 2.0 with the Classroom API scope. Build teacher and administrator dashboards that track course enrollment, assignment submission rates, student grades, and announcement delivery — giving school administrators and instructional coaches a faster operational view than Google Classroom's native interface.
| Fact | Value |
|---|---|
| Tool | Google Classroom |
| Category | Other |
| Method | REST API Resource |
| Difficulty | Intermediate |
| Time required | 30 minutes |
| Last updated | April 2026 |
Build a Google Classroom Management Dashboard in Retool
Google Classroom's native interface shows teachers their individual courses and assignments, but administrators and instructional coaches need cross-classroom views that Classroom doesn't provide: assignment completion rates across all teachers and courses, students who have not submitted any work in 7 days across all their classes, grade distribution analysis for a specific assessment across sections taught by different teachers, or a batch enrollment tool for adding students to multiple courses at once. Retool lets you build these views against the Google Classroom API.
The Google Classroom API provides access to courses (create, read, update), course teachers and students (roster management), coursework (assignments and questions with grade parameters), student submissions (submission content, submission state, and assigned grades), and announcements. Authentication uses Google OAuth 2.0 — you authorize the Classroom API scope for a Google account and use the resulting token for all API calls.
The most powerful Retool use case for Google Classroom is an instructional coach dashboard that aggregates student submission rates across all courses in a school. Coaches can see which students have consistently low submission rates across multiple teachers, identify courses with high late submission percentages, and cross-reference this with other student data from the SIS to prioritize intervention. This cross-teacher view is impossible in Classroom's native interface where each teacher sees only their own courses.
Integration method
Google Classroom connects to Retool via a REST API Resource using Google OAuth 2.0 with the Classroom API enabled in a Google Cloud project. Authentication uses an OAuth 2.0 Bearer token (obtained via the authorization code flow or service account for domain-wide delegation). All API calls go to https://classroom.googleapis.com/v1/. Retool proxies requests server-side, keeping credentials secure.
Prerequisites
- A Google Workspace for Education account with Google Classroom enabled (personal Gmail accounts have limited Classroom API access)
- A Google Cloud project with the Google Classroom API enabled
- OAuth 2.0 client credentials (client ID and client secret) from Google Cloud Console
- An OAuth 2.0 refresh token obtained by authorizing the Classroom API for a teacher or admin Google account
- A Retool account with permission to create Resources
Step-by-step guide
Enable Google Classroom API and obtain OAuth 2.0 credentials
Navigate to https://console.cloud.google.com and create a new project (or use an existing Google Workspace project). In APIs & Services → Library, search for 'Google Classroom API' and click Enable. Next, configure the OAuth consent screen: APIs & Services → OAuth consent screen. Select 'Internal' if using with Google Workspace accounts within your domain (recommended for school use — this skips external review). Fill in app name, support email, and add the following scopes: - https://www.googleapis.com/auth/classroom.courses.readonly (list courses) - https://www.googleapis.com/auth/classroom.coursework.students.readonly (read assignments and grades) - https://www.googleapis.com/auth/classroom.rosters.readonly (read enrollments) - https://www.googleapis.com/auth/classroom.announcements.readonly (read announcements) - Add write scopes (without .readonly) if you need to create/update resources Go to APIs & Services → Credentials → Create Credentials → OAuth 2.0 Client ID. Select Web Application. Add your Retool URL as an authorized redirect URI. Copy the client ID and client secret. To obtain a refresh token, use Google OAuth Playground (https://developers.google.com/oauthplayground): authorize the above scopes for a teacher or admin account, and copy the refresh_token from Step 2. Store in Retool Configuration Variables: CLASSROOM_CLIENT_ID, CLASSROOM_CLIENT_SECRET (secret), CLASSROOM_REFRESH_TOKEN (secret).
Pro tip: For school-wide admin access to all teachers' courses, use a domain admin Google account to authorize OAuth. A teacher account only provides access to courses where that teacher is enrolled. For Retool dashboards that need cross-teacher visibility, authorize with an admin account that has Google Workspace domain-wide authority.
Expected result: Google Classroom API is enabled, OAuth credentials are created, and a refresh token for the appropriate Google account is stored in Retool Configuration Variables.
Set up OAuth token refresh and create the REST API Resource
Google OAuth 2.0 access tokens expire after 1 hour. Create a token refresh mechanism in Retool. Create a refreshClassroomToken JavaScript query (set to run on page load): POST https://oauth2.googleapis.com/token with a URL-encoded body: grant_type=refresh_token&client_id=CLASSROOM_CLIENT_ID&client_secret=CLASSROOM_CLIENT_SECRET&refresh_token=CLASSROOM_REFRESH_TOKEN. Store the returned access_token in a Retool app variable called classroomToken. Now create the REST API Resource: Resources tab → Add Resource → REST API. Name: Google Classroom API Base URL: https://classroom.googleapis.com/v1 Authentication: Bearer Token → {{ classroomToken.value }} Add a default header: Content-Type: application/json. Click Create Resource. Test immediately with GET /courses?pageSize=5. A successful response returns a JSON object with a courses array containing course objects. If you get 401, the refresh token authorization may not have included all required Classroom API scopes — re-authorize using Google OAuth Playground with the complete scope list from the previous step.
1// JavaScript query: refreshClassroomToken2// Run on page load to get fresh OAuth token3const response = await fetch('https://oauth2.googleapis.com/token', {4 method: 'POST',5 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },6 body: [7 'grant_type=refresh_token',8 `client_id=${retoolContext.configVars.CLASSROOM_CLIENT_ID}`,9 `client_secret=${retoolContext.configVars.CLASSROOM_CLIENT_SECRET}`,10 `refresh_token=${retoolContext.configVars.CLASSROOM_REFRESH_TOKEN}`11 ].join('&')12});13const data = await response.json();14if (data.error) throw new Error(data.error_description);15return data.access_token;Pro tip: For school deployments, consider using a service account with domain-wide delegation instead of individual OAuth tokens. Service accounts are better for admin-level tools that need to access all teachers' courses without individual authorization flows. Requires G Suite Admin access to configure.
Expected result: The Google Classroom REST API Resource is created. GET /courses?pageSize=5 returns the 5 most recent courses for the authenticated account.
Query courses, students, and roster data
Create a getCourses query: GET /courses with parameters: - courseStates: ACTIVE (also: ARCHIVED, PROVISIONED, DECLINED — use to filter course status) - pageSize: 50 - pageToken: {{ getCourses.data.nextPageToken || '' }} (for pagination through large course lists) Google Classroom API uses cursor-based pagination with nextPageToken. For school-wide dashboards, repeatedly call getCourses with the nextPageToken from the previous response until nextPageToken is empty — collecting all pages into a combined dataset. Create a getCourseStudents query: GET /courses/{{ select_course.value }}/students?pageSize=100 — returns all enrolled students for the selected course. Each student object has: userId, profile.name.fullName, profile.emailAddress, and profile.photoUrl. Create a getCourseTeachers query: GET /courses/{{ select_course.value }}/teachers?pageSize=20 — returns all teachers (a course can have multiple co-teachers). For the enrollment report, fetch all courses and then all students for each course. Because this requires multiple sequential API calls, build a JavaScript query using async/await to fetch students for all courses in series and aggregate the results into a single student-course mapping dataset.
1// Transformer for Google Classroom courses2const courses = data?.courses || [];3return courses.map(course => ({4 id: course.id,5 name: course.name,6 section: course.section || '',7 description: (course.description || '').substring(0, 100),8 room: course.room || '',9 owner_id: course.ownerId,10 state: course.courseState,11 created_at: course.creationTime ? new Date(course.creationTime).toLocaleDateString() : '',12 alternate_link: course.alternateLink || '',13 enrollment_code: course.enrollmentCode || '',14 teacher_group_email: course.teacherGroupEmail || ''15}));Pro tip: Google Classroom API uses cursor-based pagination — always check for nextPageToken in each response. Implement a loop in a JavaScript query to fetch all pages: while(nextPageToken) { fetch next page; collect results; update nextPageToken }. Without this, you'll only see the first 50 courses in a school with many more.
Expected result: The courses Table shows all active Google Classroom courses with name, section, and enrollment code. Selecting a course populates the students Table with enrolled students.
Fetch coursework and student submissions
Create a getCoursework query: GET /courses/{{ select_course.value }}/courseWork?pageSize=50&orderBy=updateTime+desc. Each coursework item includes: id, title, description, dueDate (object with year, month, day), dueTime, maxPoints, workType (ASSIGNMENT, SHORT_ANSWER_QUESTION, MULTIPLE_CHOICE_QUESTION), and state (PUBLISHED, DRAFT, DELETED). Note: The dueDate field in Google Classroom API is an object with separate year, month, day properties — not an ISO timestamp. Build a transformer that reconstructs the date: const due = cw.dueDate ? new Date(cw.dueDate.year, cw.dueDate.month - 1, cw.dueDate.day) : null. Create a getStudentSubmissions query: GET /courses/{{ select_course.value }}/courseWork/{{ select_assignment.value }}/studentSubmissions?pageSize=100. This is the most data-rich endpoint — each submission includes: id, userId, courseWorkId, state (NEW, CREATED, TURNED_IN, RETURNED, RECLAIMED_BY_STUDENT), late (boolean), draftGrade, assignedGrade, updateTime, and submissionHistory (array of submission state changes with timestamps). The state field is critical for tracking: NEW means the student hasn't started, CREATED means the student opened it but hasn't submitted, TURNED_IN means submitted, RETURNED means the teacher returned it (with or without grade), RECLAIMED_BY_STUDENT means the student unsubmitted.
1// Transformer for student submissions with status summary2const submissions = data?.studentSubmissions || [];3const studentMap = {};45// Build student lookup from course students data6(getCourseStudents.data?.students || []).forEach(s => {7 studentMap[s.userId] = {8 name: s.profile?.name?.fullName || 'Unknown',9 email: s.profile?.emailAddress || ''10 };11});1213return submissions.map(sub => {14 const student = studentMap[sub.userId] || { name: 'Unknown', email: '' };15 const turnedInAt = sub.submissionHistory?.slice().reverse()16 .find(h => h.stateHistory?.state === 'TURNED_IN')?.stateHistory?.stateTimestamp;1718 return {19 id: sub.id,20 student_name: student.name,21 student_email: student.email,22 state: sub.state,23 is_late: sub.late ? 'Late' : 'On Time',24 draft_grade: sub.draftGrade ?? '',25 assigned_grade: sub.assignedGrade ?? '',26 submitted_at: turnedInAt ? new Date(turnedInAt).toLocaleString() : '',27 last_updated: new Date(sub.updateTime).toLocaleString(),28 needs_grading: sub.state === 'TURNED_IN' && sub.assignedGrade === undefined29 };30});Pro tip: Google Classroom's getStudentSubmissions endpoint returns submissions for ALL students enrolled in the course — including students who haven't opened the assignment at all (state: NEW). This is useful for identifying missing work since you can detect every student without a TURNED_IN state.
Expected result: The submissions Table shows all students with their assignment submission status, grade, and whether the submission was late. Needs-grading indicator highlights ungraded turned-in work.
Build the cross-course attendance and grade reporting view
Build the multi-course reporting view that aggregates data across courses. Create a JavaScript query (allCoursesSummary) that fetches coursework and submissions for each course in getCourses.data and computes summary statistics. For each course, compute: - submission_rate: (TURNED_IN count + RETURNED count) / total students × 100 - on_time_rate: non-late submissions / total submitted × 100 - average_grade: mean of assignedGrade values for returned submissions - missing_count: students with state === 'NEW' or state === 'CREATED' Display these per-course metrics in an aggregate Table sortable by submission rate. Add a drill-down pattern: clicking a course row shows the individual assignment-level breakdown for that course. For the student missing work view, build a transformer that inverts the data structure: instead of course → students, produce student → courses with missing work. Group submission records by student email and count MISSING states per student to generate the at-risk student list. For returning grades to students, create an updateGrade query: PATCH /courses/{courseId}/courseWork/{courseWorkId}/studentSubmissions/{submissionId} with body: { "assignedGrade": {{ input_grade.value }}, "draftGrade": {{ input_grade.value }} }. Follow this with a return query: POST /courses/{courseId}/courseWork/{courseWorkId}/studentSubmissions/{submissionId}:return to make the grade visible to the student. For school districts building comprehensive academic monitoring dashboards combining Google Classroom, SIS grade book data, and attendance records across hundreds of teachers, RapidDev's team can help architect the complete Retool solution.
1// JavaScript query: compute per-course submission summary2const courses = getCourses.data || [];3const results = [];45for (const course of courses.slice(0, 20)) { // limit to first 20 courses6 const cwResp = await getCourseWorkForCourse.trigger({ course_id: course.id });7 const assignments = cwResp?.courseWork || [];89 let totalSubmissions = 0, turnedIn = 0, lateCount = 0, gradeSum = 0, gradedCount = 0;1011 for (const assignment of assignments.slice(0, 5)) { // last 5 assignments per course12 const subResp = await getSubmissionsForAssignment.trigger({13 course_id: course.id,14 assignment_id: assignment.id15 });16 const subs = subResp?.studentSubmissions || [];17 totalSubmissions += subs.length;18 turnedIn += subs.filter(s => ['TURNED_IN', 'RETURNED'].includes(s.state)).length;19 lateCount += subs.filter(s => s.late).length;20 subs.filter(s => s.assignedGrade != null).forEach(s => {21 gradeSum += s.assignedGrade;22 gradedCount++;23 });24 }2526 results.push({27 course_id: course.id,28 course_name: course.name,29 section: course.section || '',30 submission_rate: totalSubmissions > 0 ? ((turnedIn / totalSubmissions) * 100).toFixed(1) : '0.0',31 late_rate: turnedIn > 0 ? ((lateCount / turnedIn) * 100).toFixed(1) : '0.0',32 avg_grade: gradedCount > 0 ? (gradeSum / gradedCount).toFixed(1) : 'N/A'33 });34}3536return results;Pro tip: Google Classroom API calls per user are subject to per-minute quotas. For the multi-course summary that makes many API calls in sequence, add a small delay between course iterations (await new Promise(r => setTimeout(r, 100))) to avoid hitting per-minute request limits on large school accounts.
Expected result: The cross-course summary Table shows all active courses with submission rate, late rate, and average grade. The missing work Table shows at-risk students with missing assignment counts by course.
Common use cases
Build a teacher assignment submission tracking dashboard
Create a Retool dashboard showing all assignments for a selected course with submission counts, on-time submission rate, and grade distribution. Teachers can see at a glance which students haven't submitted, click to view submission details, and grade pending submissions — all without navigating through Classroom's individual assignment views.
Build a Retool teacher dashboard for Google Classroom. Show all courses for the authenticated teacher. When a course is selected, show all assignments with: title, due date, total students, submitted count, missing count, and average grade. When an assignment is selected, show a Table of all students with their submission status (Submitted, Late, Missing), submission time, and grade. Add a Filter by Status dropdown.
Copy this prompt to try it in Retool
Build a school-wide enrollment and course management panel
Build a Retool admin panel showing all Google Classroom courses across the school with teacher name, student enrollment count, and course status. Administrators can add or remove students from multiple courses at once, archive inactive courses, and generate enrollment reports for compliance reporting — tasks that would require logging into individual teachers' Classroom accounts otherwise.
Build a Retool school-wide Classroom admin panel. Show all courses with: course name, teacher name, student count, creation date, and status (Active/Archived/Provisioned). Add bulk actions: select multiple courses and archive them, or add a student (by email) to all selected courses. Show a student enrollment report: for each student email, list all their enrolled courses and sections.
Copy this prompt to try it in Retool
Build a student missing work intervention tracker
Create a Retool tool that identifies students with multiple missing assignments across all their enrolled Google Classroom courses. School counselors and intervention teams can see each at-risk student's missing work count, teachers affected, and last submission date — enabling early intervention before absences or missing work escalate.
Build a Retool missing work intervention dashboard. Query all courses and their assignments from the last 30 days. For each student, count missing submissions across all courses. Show students with 3+ missing assignments sorted by missing count descending. Include: student name, email, number of missing assignments, courses affected, and last submission date. Add an export CSV button for the counselor's weekly intervention meeting.
Copy this prompt to try it in Retool
Troubleshooting
401 Unauthorized or 'Request had invalid authentication credentials' error
Cause: The OAuth 2.0 access token has expired (tokens last 1 hour) or the refresh token was not authorized with the correct Classroom API scopes.
Solution: Re-run the token refresh query to get a new access token. If the refresh itself fails, the refresh token may have been revoked or the authorized scopes are insufficient. Re-authorize using Google OAuth Playground with all required Classroom API scopes: classroom.courses.readonly, classroom.coursework.students.readonly, and classroom.rosters.readonly.
403 Forbidden with 'PERMISSION_DENIED' when accessing courses or submissions
Cause: The authenticated user account does not have permission to view the requested course. Classroom API access is scoped to courses where the user is a teacher, student, or domain admin — a teacher account cannot access another teacher's courses without admin authorization.
Solution: For cross-teacher visibility, authorize the API with a Google Workspace domain admin account, or enable domain-wide delegation using a service account. A teacher's OAuth token can only access their own courses. Configure domain-wide delegation in Google Workspace Admin console to grant a service account access to all users' Classroom data.
Student names show as 'Unknown' in submission data
Cause: The getStudentSubmissions endpoint returns userId values but not student profile information. Without a separate call to GET /courses/{id}/students, you cannot resolve userId to names and emails.
Solution: Always fetch the course roster (GET /courses/{id}/students) before fetching submissions. Build a userId-to-profile lookup map from the roster response, then use it in the submissions transformer: const student = studentMap[sub.userId] || { name: 'Unknown', email: '' }. Ensure getStudentSubmissions depends on getCourseStudents completing first.
1// Build student lookup map:2const studentMap = {};3(getCourseStudents.data?.students || []).forEach(s => {4 studentMap[s.userId] = {5 name: s.profile?.name?.fullName || 'Unknown',6 email: s.profile?.emailAddress || ''7 };8});getCourses returns only a partial list of courses for a school
Cause: Google Classroom API paginates results using cursor-based pagination with pageSize (max 500) and nextPageToken. The default pageSize is typically 20-50, and a single request only returns one page.
Solution: Increase pageSize to 500 (the API maximum) and implement pagination: check for nextPageToken in the response and make additional requests until nextPageToken is null or empty. For schools with hundreds of courses, a JavaScript query loop is needed to collect all pages.
1// URL parameters for maximum page size:2// pageSize: 5003// pageToken: {{ getCourses.data.nextPageToken || '' }}4// Implement pagination in a JavaScript query to fetch all pagesBest practices
- Store Google OAuth credentials (client ID, client secret, refresh token) in Retool Configuration Variables marked as secret — never hardcode OAuth tokens in resource or query configurations.
- Implement token refresh on a 50-minute schedule using a Retool Workflow — Google OAuth access tokens expire after 1 hour and stale tokens cause dashboard failures in active school day use.
- Use a domain admin Google account (or service account with domain-wide delegation) for school-wide dashboards — teacher accounts can only access their own courses, making cross-teacher reporting impossible.
- Always fetch the course roster before fetching submissions — Google Classroom's submission endpoint returns user IDs, not names or emails, requiring the roster lookup map to display meaningful student information.
- Use pageSize: 500 (the maximum) for all list endpoints and implement nextPageToken pagination — schools with many courses will get incomplete data from default page sizes.
- Cache getCourses for 5 minutes and getStudentSubmissions for 2 minutes — Classroom data doesn't change second-to-second, and caching prevents hitting per-minute API quotas during multi-course aggregation queries.
- For missing work identification, filter submissions by state: NEW (not opened) and state: CREATED (opened but not submitted) — do not rely on missing assignedGrade alone, as returned submissions may have grades while other states don't.
- When building grade write-back workflows, always follow the PATCH grade update with the :return action — updating the assignedGrade alone does not notify students or mark the submission as returned. The :return endpoint is required to make grades visible to students.
Alternatives
Canvas LMS uses token-based API auth without OAuth complexity and provides more comprehensive LMS features for higher education — choose it over Google Classroom if your institution needs a dedicated LMS with advanced course management beyond Google Workspace's ecosystem.
Moodle is an open-source LMS with a comprehensive REST API and full data ownership — choose it over Google Classroom if your school needs a self-hosted learning platform with complete control over student data and course content.
Schoology provides more advanced assessment and analytics features than Google Classroom — choose it if your district needs detailed learning outcome tracking and SIS integration beyond what the Classroom API supports.
Frequently asked questions
Does Retool have a native Google Classroom connector?
No, Retool does not have a dedicated native connector for Google Classroom. You connect via a REST API Resource using Google Classroom API OAuth 2.0 authentication. Setup takes about 30 minutes including the Google Cloud project configuration and OAuth flow. Once configured, you have full access to courses, coursework, student submissions, grades, and roster management endpoints.
Can I see all teachers' courses from one Retool dashboard?
Yes, but it requires the right authentication. A teacher's OAuth token only provides access to their own courses. For school-wide visibility across all teachers, authenticate with a Google Workspace domain administrator account, or configure a service account with domain-wide delegation in the Google Workspace Admin console. With admin-level access, the courses endpoint returns all courses across the domain.
Can Retool read student grades from Google Classroom?
Yes. The studentSubmissions endpoint (GET /courses/{id}/courseWork/{id}/studentSubmissions) returns both draftGrade (teacher's working grade, not visible to students) and assignedGrade (the official returned grade). Your OAuth scopes must include classroom.grades.readonly for draft grades or classroom.grades for write access. Always check assignedGrade for the official grade — draftGrade is only visible to teachers.
How do I identify students with missing assignments in Google Classroom from Retool?
Fetch all student submissions for an assignment using GET /courses/{id}/courseWork/{id}/studentSubmissions. Google Classroom returns a submission record for every enrolled student — even those who haven't opened the assignment (state: NEW). Students with state: NEW or state: CREATED and a past due date are effectively missing the assignment. The late boolean field marks submissions that were turned in after the due date.
What Google Classroom API scopes do I need for a full Retool management dashboard?
For a comprehensive read-only dashboard, request these scopes: classroom.courses.readonly (list and view courses), classroom.rosters.readonly (view student and teacher lists), classroom.coursework.students.readonly (view assignments and submissions), and classroom.grades.readonly (view grade data). Add the write equivalents (without .readonly) only if your Retool tool needs to create, update, or grade assignments. Using the minimum required scopes is a security best practice.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation