Recently, I had the pleasure of creating a Rise course for a certified leadership coach. Since the client is a solopreneur and they are just getting started with selling courses, they decided not to use an LMS for now. Instead, they opted to put the course directly on their WordPress site.
The Problem
The plan was to publish the course for the web (using Netlify), embed the course on a page of the client’s WordPress site, and use MemberPress to protect the page and control registrations/payments. Unfortunately, this solution didn’t allow us to use SCORM. The client didn’t need robust tracking, but they still wanted a general idea of how people were using the course. They wanted to be able to see how long people spent on each lesson, as well as whether or not the lessons were being completed. They didn’t need to identify users by name, but they did want to see general completion patterns.
The Solution
UsingJavaScript, I created a custom course tracker in Google Sheets. Every time a user accesses a lesson in the course, a new entry is created. It logs a time stamp, lesson title, anonymous user ID, status (complete or incomplete), total time spent (in minutes), and locale.
I originally tried adding the tracker using Rise custom HTML blocks inside each lesson. While this works in simple cases, it caused layout gaps and navigation issues once exported. Instead, I moved the tracking script to the root of the exported web files and loaded it from index.html. This makes the tracker part of the application itself rather than part of the lesson content, which is far more stable and scalable.
If this is something you want to try for your own project, read on to see how I did it!
Step-by-Step Directions
Part 1: Set Up the Google Sheet
This is where the data will eventually be displayed.
- Open a new Google Sheet.
- Rename the tab to Tracker.
- Add the headers as shown in the screenshot below:

4. Under the Extensions menu in Google Sheets, open Apps Script.

5. Paste the following code:
const SHEET_NAME = 'Tracker';function doGet(e) { try { const p = e.parameter; if (!p.lessonTitle || !p.anonId || !p.status) { return ContentService.createTextOutput('ignored'); } const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME); sheet.appendRow([ new Date(), p.lessonTitle, p.anonId, p.status, Number(p.totalMinutes || 0), p.locale || 'unknown' ]); return ContentService.createTextOutput('ok'); } catch (err) { return ContentService.createTextOutput('error'); }}
- Click Deploy > New Deployment.
- Use the following settings:
- Type: Web app
- Execute as: Me
- Who has access: Anyone
- Click Deploy again.
- Copy the web app URL. Later on, you will need this in order to connect the Google Sheet with the course.
Part 2: Export the Rise Course
- In Rise, publish your course for the web.
- Unzip the exported file. You should see a folder structure similar to this:
content/ index.html assets/ lib/
Part 3: Create the Java Script Tracker
- Create a new file inside the content folder named tracker.js.
- Paste the following code in the file, replacing PASTE_YOUR_WEB_APP_URL_HERE with your web app URL from Part 1.
(() => { const WEB_APP_URL = "PASTE_YOUR_WEB_APP_URL_HERE"; const NS = "riseTracker.v1"; const MIN_SECONDS = 10; const uuid = () => (crypto.randomUUID?.() ?? `id-${Math.random().toString(16).slice(2)}-${Date.now()}`); const getOrCreate = (k, session) => { const store = session ? sessionStorage : localStorage; let v = store.getItem(k); if (!v) { v = uuid(); store.setItem(k, v); } return v; }; const anonId = () => getOrCreate(`${NS}.anonId`, false); const sessionId = () => getOrCreate(`${NS}.sessionId`, true); const state = { lesson: document.title, activeMs: 0, since: document.hidden ? 0 : Date.now(), reachedEnd: false, sent: false }; const minutes1 = ms => Math.round(ms / 6000) / 10; const flush = () => { if (!document.hidden && state.since) { state.activeMs += Date.now() - state.since; state.since = Date.now(); } }; document.addEventListener("visibilitychange", () => { if (document.hidden) flush(); else state.since = Date.now(); }); const findContinue = () => [...document.querySelectorAll("a,button")] .find(el => /continue/i.test(el.textContent || "")); setInterval(() => { if (state.reachedEnd) return; const btn = findContinue(); if (!btn) return; const r = btn.getBoundingClientRect(); if (r.top < innerHeight && r.bottom > 0) state.reachedEnd = true; }, 700); const send = status => { if (state.sent) return; state.sent = true; flush(); const mins = minutes1(state.activeMs); if (status === "incomplete" && mins * 60 < MIN_SECONDS) return; const p = { lessonTitle: state.lesson, anonId: anonId(), sessionId: sessionId(), status, totalMinutes: mins, locale: navigator.language || "unknown", _t: Date.now() }; new Image().src = WEB_APP_URL + "?" + new URLSearchParams(p); }; document.addEventListener("click", e => { const el = e.target.closest("a,button"); if (!el) return; if (/continue/i.test(el.textContent || "")) { state.reachedEnd = true; send("complete"); } }, true); addEventListener("pagehide", () => send(state.reachedEnd ? "complete" : "incomplete"), true);})();
Part 4: Edit the index.html File
- Open the index.html file. You should be able to find this in the content folder from your Rise export.
- Scroll to the very bottom. Find the closing body tag:
</body>
- Paste the following code immediately before the closing body tag:
<script src="./tracker.js"></script>
- Save the file.
Part 5: Deploy
Drag the unzipped folder to Netlify.
Part 6: Test
- Complete a lesson and confirm that a new row appears in the Google Sheet.
- Begin a new lesson and stay for at least 10 seconds. Leave before completing the lesson. Confirm that an new row appears and is marked incomplete.
This solution worked in my original project, but you may need to tweak the tracker code depending on your setup. Differences in how a Rise course is built can affect how the final output behaves. If something isn’t working as expected, small adjustments to the code or timing may be needed.
When to Use This Approach
This solution is great for solopreneurs or anyone who wants to track general completion patterns. It would also work well for people who want to collect basic data about how people interact with their portfolio projects. On the other hand, teams that need to track data for individual employees would probably benefit from an LMS or more robust solution.
Your Turn
Now that you know how to connect Google Sheets to your Rise courses, what other types of data would you want to collect? Feel free to modify this process for your own needs. You can even collaborate with your LLM of choice to edit the code. I’d love to hear what you come up with!
About Ayla Blacklaw
Ayla Blacklaw is an eLearning designer who helps organizations solve workplace problems through thoughtful learning solutions. She designs training and resources that help employees perform their work more effectively.


Leave a Reply