// ==UserScript==
// @name Grok ratelimit indicator
// @namespace https://6942020.xyz/
// @version 1.2
// @description Shows ratelimit information on Grok
// @author WadeGrimridge
// @match https://grok.com/*
// @license MIT
// @grant none
// ==/UserScript==
(function () {
"use strict";
let rateInfoElement = null;
const modelRateLimits = {
"grok-latest": null,
"grok-3": {
DEFAULT: null,
REASONING: null,
DEEPSEARCH: null,
},
};
const modelDisplayNames = {
"grok-latest": "Grok 2",
"grok-3": {
DEFAULT: "Grok 3",
REASONING: "Think",
DEEPSEARCH: "DeepSearch",
DEEPERSEARCH: "DeeperSearch",
},
};
function formatTime(seconds) {
if (seconds >= 3600) {
const hours = Math.floor(seconds / 3600);
const remainingMinutes = Math.floor((seconds % 3600) / 60);
return remainingMinutes > 0
? `${hours}h ${remainingMinutes}m`
: `${hours}h`;
}
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
return remainingSeconds > 0
? `${minutes}m ${remainingSeconds}s`
: `${minutes}m`;
}
async function fetchRateLimit(
modelName,
requestKind = "DEFAULT",
attempt = 1
) {
try {
const response = await fetch("/rest/rate-limits", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ requestKind, modelName }),
});
if (response.status !== 200 && attempt <= 10) {
await new Promise((resolve) => setTimeout(resolve, 1000));
return fetchRateLimit(modelName, requestKind, attempt + 1);
}
const data = await response.json();
if (!isValidRateData(data)) return;
updateRateInfo(data, modelName, requestKind);
} catch (error) {
console.error(`[grok-ratelimit] Rate limit fetch failed:`, error);
if (attempt <= 10) return;
if (rateInfoElement) {
rateInfoElement.textContent = "Couldn't fetch ratelimit info";
}
}
}
function isValidRateData(data) {
return (
data &&
typeof data.remainingQueries === "number" &&
typeof data.totalQueries === "number"
);
}
function updateRateInfo(data, modelName, requestKind = "DEFAULT") {
if (!rateInfoElement) return;
if (modelName === "grok-3") {
modelRateLimits[modelName][requestKind] = data;
} else {
modelRateLimits[modelName] = data;
}
const lines = [];
for (const kind of ["DEFAULT", "REASONING", "DEEPSEARCH", "DEEPERSEARCH"]) {
const modelData = modelRateLimits["grok-3"][kind];
if (!modelData) continue;
const timeStr = formatTime(modelData.windowSizeSeconds);
const displayName = modelDisplayNames["grok-3"][kind];
lines.push(
`${displayName}: ${modelData.remainingQueries}/${modelData.totalQueries} (${timeStr})`
);
}
const grok2Data = modelRateLimits["grok-latest"];
if (grok2Data) {
const timeStr = formatTime(grok2Data.windowSizeSeconds);
lines.push(
`${modelDisplayNames["grok-latest"]}: ${grok2Data.remainingQueries}/${grok2Data.totalQueries} (${timeStr})`
);
}
rateInfoElement.textContent = lines.join(" | ");
}
const originalFetch = window.fetch;
window.fetch = async function (...args) {
const [resource, options] = args;
const url =
resource instanceof Request ? resource.url : resource.toString();
if (!url.includes("/rest/rate-limits")) {
return originalFetch.apply(this, args);
}
const requestBody = JSON.parse(options.body);
const modelName = requestBody.modelName;
const requestKind = requestBody.requestKind;
const response = await originalFetch.apply(this, args);
const clone = response.clone();
clone.json().then((data) => {
if (!isValidRateData(data)) return;
updateRateInfo(data, modelName, requestKind);
});
return response;
};
function createRateInfoElement() {
const targetDiv = document.querySelector(
'main div:has(> a[aria-label="Home page"])'
);
if (targetDiv && !rateInfoElement) {
const headerDiv = targetDiv.parentElement;
headerDiv.classList.remove(
"@[80rem]/nav:h-0",
"@[80rem]/nav:top-8",
"@[80rem]/nav:from-transparent",
"@[80rem]/nav:via-transparent"
);
rateInfoElement = document.createElement("div");
rateInfoElement.className = "ml-2 text-sm break-words";
rateInfoElement.style.maxWidth = "calc(100vw - 240px)";
rateInfoElement.textContent = "Fetching ratelimit info...";
targetDiv.appendChild(rateInfoElement);
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
(async () => {
await fetchRateLimit("grok-3", "DEFAULT");
await sleep(100);
await fetchRateLimit("grok-3", "REASONING");
await sleep(100);
await fetchRateLimit("grok-3", "DEEPSEARCH");
await sleep(100);
await fetchRateLimit("grok-3", "DEEPERSEARCH");
await sleep(100);
await fetchRateLimit("grok-latest");
})();
}
}
function waitForElement() {
const targetDiv = document.querySelector(
'main div:has(> a[aria-label="Home page"])'
);
if (targetDiv) {
createRateInfoElement();
} else {
requestAnimationFrame(waitForElement);
}
}
waitForElement();
})();