Skip to content
Decoding OTF Data
Share
Explore
Decoding OTF Data

icon picker
Ep 2: Really getting the class count

Entry Date:
7/19/2022

Idea

Write one line of JavaScript to get class count & other summarized data.

Update on 2023-06-23: You can now get your class count in Orangetheory’s app!

Open your Orangetheory app
Under Base (which should be your default tab), scroll down and you should see a Brag Board → And that’s your class count!

tl;dr

💡 Members API Endpoint (https://api.orangetheory.co/member/members/<member ID>?include=memberClassSummary) gives us some solid high-level metrics around class count. (Credit to )
💡 Auth tokens & member IDs are stored in localStorage once you logged on to otlive.orangetheory.com.
🟡 Once you logged in to otlive.orangetheory.com, you can open up Chrome Dev Tools, and run the following script in Console to get your first OTF visit, total # of classes booked, attended, and the # studios visited.
await fetch(`https://api.orangetheory.co/virtual-class/proxy-cors/?url=https://api.orangetheory.co/member/members/${Object.entries(window.localStorage).filter(([key, value]) => { if (key.endsWith('LastAuthUser')) { return value } })[0][1]
}?include=memberClassSummary`, {
"headers": {
"accept": "application/json",
"accept-language": "en-US,en;q=0.9",
"authorization": Object.entries(window.localStorage).filter(([key, value]) => { if (key.endsWith('idToken')) { return value } })[0][1],
"cache-control": "no-cache",
"content-type": "application/json",
"sec-ch-ua": "\".Not/A)Brand\";v=\"99\", \"Google Chrome\";v=\"103\", \"Chromium\";v=\"103\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"macOS\"",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "cross-site",
"Referer": "https://otlive.orangetheory.com/"
},
"body": null,
"method": "GET"
}).then(response => response.json()).then(data => data['data']['memberClassSummary']).then(summary => {
console.log(`Total Classes Booked: ${summary.totalClassesBooked}`);
console.log(`Total Classes Attended: ${summary.totalClassesAttended}`);
console.log(`# Studios Visited: ${summary.totalStudiosVisited}`);
console.log(`First visit: ${summary.firstVisitDate}`);
});

Legend

💡 = Insight 🟢 = Do-able by anyone 🟡 = Hack by running Javascript via Chrome Debugger 🔴 = Hack that requires some level of Web coding experience

What’s next?

Really crack open Workout Summary data (Now that we finally get an accurate class count.)

Raw Notes

Getting Class Summary Data

brought up we can use a different API endpoint to there’s another API endpoint that gives us class summary data. ()
Looks like the API was made when visiting - I don’t need to go to the summary page even.
Looking at the network tab, it’s making a call to this following URL - Exactly like Fireislander mentioned.
https://api.orangetheory.co/virtual-class/proxy-cors/?url=https://api.orangetheory.co/member/members/<member ID>?include=memberClassSummary
image.png
💡 memberClassSummary contains exactly what I want for class count, and more.
image.png
Need to figure out how to make it easy so we can just run a single Javascript in Chrome Dev console and get the data.
Copy Node.js fetch command and see what’s involved.
image.png
The fetch call looks pretty simple — Except the authorization header could be a bit tricky.
image.png
OK. We can’t set pragma and Referrer-Policy in header.
image.png
The call works once those 2 keys are removed from the header blob.
Added await and some .then(...) chain, and we can already get some pretty interesting data with a single line of code in Chrome DevTools.
Two pieces missing: How to get the token? How to get the member ID

Getting Token

Let’s see if session storage/local storage give us anything related to auth data.
There are 2 keys - idToken and accessToken - that contains the value that appears to match the payload.
image.png
Ugh. The key itself contains some UUID - I need to do an .endsWith(...) match to get the data.
This is it I think.
Replaced <token> with the line above - Bingo.
Now on to member ID.

Getting Member ID

Also in Local storage, it looks like we store member ID in LastAuthUser key - We can probably just reuse the same code from the idToken.
image.png
Boom
Putting everything together - Bingo
image.png
Ha. Looks like I’ve missed 10 classes. 🤣

Final Code

Feedback? Got ideas? Found a bug?

Let me know on this .

Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.