Skip to content

Instantly share code, notes, and snippets.

@benhook1013
Last active January 24, 2026 02:37
Show Gist options
  • Select an option

  • Save benhook1013/9c2d27db1693ea5e5428e457a30f26b0 to your computer and use it in GitHub Desktop.

Select an option

Save benhook1013/9c2d27db1693ea5e5428e457a30f26b0 to your computer and use it in GitHub Desktop.
Tampermonkey script to show NZD cost and burn-rate stats on ChatGPT Codex usage page
// ==UserScript==
// @name Codex Credits → Cost + Stats (Correct Cards)
// @namespace ben.codex.credit.cost
// @version 8.0
// @description Show credit cost and usage stats on the Codex settings usage page.
// @match https://chatgpt.com/*
// @match https://chat.openai.com/*
// @run-at document-end
// @grant none
// ==/UserScript==
(function () {
"use strict";
if (!location.pathname.includes("/codex/settings/usage")) return;
// ================= CONFIG =================
// 1000 credits = 70 NZD
const CREDIT_COST = 0.07; // NZD per credit
const CURRENCY_CODE = "NZD";
// ==========================================
const moneyFmt = new Intl.NumberFormat("en-US", {
style: "currency",
currency: CURRENCY_CODE,
minimumFractionDigits: 2,
});
const numFmt = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 2,
});
const money = (v) => moneyFmt.format(v);
const num = (v) => numFmt.format(v);
function parseCredits(text) {
const m = text?.match(/([\d.,]+)\s*credits?/i);
return m ? Number(m[1].replace(/,/g, "")) : null;
}
// ---------------- TABLE ROW COSTS ----------------
function injectRowCosts() {
document.querySelectorAll("table tbody tr").forEach((row) => {
const span = row.querySelector("td:last-child span");
if (!span || span.dataset.costDone) return;
const credits = parseCredits(span.textContent);
if (!credits) return;
const cost = document.createElement("span");
cost.textContent = ` (${money(credits * CREDIT_COST)})`;
cost.style.marginLeft = "4px";
cost.style.opacity = "0.7";
cost.style.fontSize = "0.95em";
span.appendChild(cost);
span.dataset.costDone = "true";
});
}
function getTableStats() {
const vals = [];
document.querySelectorAll("table tbody tr").forEach((row) => {
const span = row.querySelector("td:last-child span");
const c = parseCredits(span?.textContent);
if (c) vals.push(c);
});
if (!vals.length) return null;
const total = vals.reduce((a, b) => a + b, 0);
return {
avg: total / vals.length,
};
}
// ---------------- TABLE HEADER CARD ----------------
function injectTableHeaderStats() {
document.querySelectorAll("div.flex.flex-col.items-start").forEach((col) => {
const label = col.querySelector("p");
if (label?.textContent.trim() !== "Credits remaining") return;
const numberP = col.querySelectorAll("p")[1];
if (!numberP) return;
const raw = numberP.firstChild?.nodeValue;
const remaining = Number(raw?.replace(/[^0-9.]/g, ""));
if (!remaining) return;
if (!numberP.querySelector(".codex-cost")) {
const cost = document.createElement("span");
cost.className = "codex-cost";
cost.textContent = ` (${money(remaining * CREDIT_COST)})`;
cost.style.marginLeft = "6px";
cost.style.opacity = "0.7";
numberP.appendChild(cost);
}
const stats = getTableStats();
if (!stats) return;
let statsDiv = col.querySelector(".codex-stats");
if (!statsDiv) {
statsDiv = document.createElement("div");
statsDiv.className = "codex-stats";
statsDiv.style.marginTop = "4px";
statsDiv.style.fontSize = "0.85rem";
statsDiv.style.opacity = "0.85";
col.appendChild(statsDiv);
}
statsDiv.innerHTML =
`<div>Avg credits / usage day: ${num(stats.avg)}</div>` +
`<div>Approx days remaining: ${num(remaining / stats.avg)}</div>`;
});
}
// ---------------- TOP BALANCE CARD ----------------
function injectTopCreditsCardCost() {
document.querySelectorAll("article").forEach((article) => {
const label = article.querySelector("p");
if (label?.textContent.trim() !== "Credits remaining") return;
const span = article.querySelector("span.text-2xl.font-semibold");
if (!span || span.querySelector(".codex-top-cost")) return;
const raw = span.firstChild?.nodeValue;
const remaining = Number(raw?.replace(/[^0-9.]/g, ""));
if (!remaining) return;
const cost = document.createElement("span");
cost.className = "codex-top-cost";
cost.textContent = ` (${money(remaining * CREDIT_COST)})`;
cost.style.marginLeft = "6px";
cost.style.opacity = "0.7";
cost.style.fontSize = "0.9em";
cost.style.fontWeight = "normal";
span.appendChild(cost);
});
}
// ---------------- MAIN LOOP ----------------
function tick() {
injectRowCosts();
injectTableHeaderStats();
injectTopCreditsCardCost();
}
tick();
setInterval(tick, 2000);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment