Skip to content

Instantly share code, notes, and snippets.

@AndrewAubury
Created March 4, 2026 12:40
Show Gist options
  • Select an option

  • Save AndrewAubury/6fb63eab8a7a5b07eab487f0dcf6c05c to your computer and use it in GitHub Desktop.

Select an option

Save AndrewAubury/6fb63eab8a7a5b07eab487f0dcf6c05c to your computer and use it in GitHub Desktop.
PureGym Attendance Worker
/**
* PureGym Attendance – Cloudflare Worker (AUTHENTICATED)
*
* Set credentials as secrets:
* wrangler secret put PUREGYM_EMAIL
* wrangler secret put PUREGYM_PIN
*/
/**
* Gym list
* Key = output name
* Value = gymId (int)
*/
const GYMS = {
"dunstable": 111,
"luton": 462,
};
/**
* Authenticate and return Bearer token
*/
async function authenticate(email, pin) {
const body = new URLSearchParams({
grant_type: "password",
username: email,
password: pin,
scope: "pgcapi",
client_id: "ro.client",
});
const res = await fetch("https://auth.puregym.com/connect/token", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": "PureGym/1523 CFNetwork/1312 Darwin/21.0.0",
},
body,
});
if (!res.ok) {
throw new Error(`Auth failed: ${res.status}`);
}
const json = await res.json();
return json.access_token;
}
/**
* Fetch attendance for one gym
*/
async function fetchAttendance(token, gymId) {
const res = await fetch(
`https://capi.puregym.com/api/v2/gymSessions/gym?gymId=${gymId}`,
{
headers: {
"Authorization": `Bearer ${token}`,
"User-Agent": "PureGym/1523 CFNetwork/1312 Darwin/21.0.0",
},
}
);
if (!res.ok) {
return 0;
//throw new Error(`Attendance failed (${gymId}): ${res.status}`);
}
const json = await res.json();
if(json.TotalPeopleInGym == null){
return 0;
}else{
return json.TotalPeopleInGym;
}
}
export default {
async fetch(request, env, ctx) {
try {
const token = await authenticate(
env.PUREGYM_EMAIL,
env.PUREGYM_PIN
);
const result = {};
await Promise.all(
Object.entries(GYMS).map(async ([name, gymId]) => {
try {
result[name] = await fetchAttendance(token, gymId);
} catch {
result[name] = null;
}
})
);
return new Response(JSON.stringify(result, null, 2), {
headers: {
"Content-Type": "application/json",
"Cache-Control": "no-store",
},
});
} catch (err) {
return new Response(
JSON.stringify({ error: err.message }),
{ status: 500 }
);
}
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment