Skip to content

Instantly share code, notes, and snippets.

@SpaceSaver
Created August 30, 2025 17:48
Show Gist options
  • Save SpaceSaver/2be3bb2359040c7ac5fe9c6538864d42 to your computer and use it in GitHub Desktop.
Save SpaceSaver/2be3bb2359040c7ac5fe9c6538864d42 to your computer and use it in GitHub Desktop.
ChatGPT Model Selector
// ==UserScript==
// @name ChatGPT Model Override
// @namespace SpaceSaver Scripts
// @match https://chatgpt.com/*
// @grant none
// @version 2.0
// @author SpaceSaver UnderCover (/u/SpaceSaver2000-1)
// @description Adds a more advanced model selector to ChatGPT enabling you to save your GPT-4o credits for when you need them!
// @run-at document-start
// ==/UserScript==
(() => {
const HEADER_QUERY_STRING = "nav > .bottom-0";
let models = null;
const originalFetch = window.fetch;
async function fetchInterceptor(...args) {
if (!window.localStorage.getItem("selected-model")) {
window.localStorage.setItem("selected-model", "gpt-4o-mini");
}
//args[0] = new String(args[0][0])
if (typeof(args[0]) != "string") return originalFetch(...args);
console.log(args[0]);
if (args[0].endsWith("/backend-api/conversation") || args[0].endsWith("/backend-api/f/conversation") && args[1]?.body) {
const bodyJSON = JSON.parse(args[1].body);
bodyJSON.model = window.localStorage.getItem("selected-model");
args[1].body = JSON.stringify(bodyJSON);
/*} else if (args[0].split("?")[0].endsWith("/backend-api/models")) {
const res = await originalFetch(...args);
const textRes = await res.text();
res.text = async () => {return textRes};
res.json = async () => {return JSON.parse(textRes)};
models = JSON.parse(textRes).models;
setTimeout(() => loadMenu(), 30000);
return res;
*/
} else if (args[0].endsWith("/backend-api/conversation/init") && args[1]?.body) {
return
//If we do this it doesn't acknowledge that certain chats are disabled since 4o ratelimit has been reached 💀
/*
const res = await originalFetch(...args);
let textRes = await res.text();
textRes = JSON.parse(textRes);
if (textRes.blocked_features && textRes.blocked_features.filter(elem => {return elem.name == "send"}).length > 0) {
const newBlocked = [];
for (let x = 0; x < textRes.blocked_features.length; x++) {
if (textRes.blocked_features[x].name != "send") {
newBlocked.push(textRes.blocked_features[x]);
}
}
textRes.blocked_features = newBlocked;
}
console.log(textRes);
textRes = JSON.stringify(textRes);
res.text = async () => {return textRes};
res.json = async () => {return JSON.parse(textRes)};
*/
}
return await originalFetch(...args);
}
window.fetch = fetchInterceptor;
window.addEventListener("load",() => setTimeout( async () => {
console.log("Getting sh*t myself")
const headers = {};
try {
headers.Authorization = "Bearer " + document.documentElement.innerHTML.split('\\"accessToken\\",\\"')[1].split('\\"')[0]//window.__reactRouterContext.state.loaderData.root.clientBootstrap.session.accessToken;
} catch(e) {
console.log("Couldn't find token, probably logged out lol.")
}
models = (await ( await fetch("https://chatgpt.com/backend-api/models", {headers, credentials: "include"})).json()).models;
loadMenu();
}, 5000));
const loadMenu = () => {
const header = document.querySelector(HEADER_QUERY_STRING);
const selector = document.createElement("select");
for (const model of models) {
const opt = document.createElement("option");
opt.textContent = model.title;
opt.value = model.slug;
selector.appendChild(opt);
}
selector.style.backgroundColor = "var(--sidebar-surface-primary)";
selector.style.borderRadius = "15px";
selector.value = window.localStorage.getItem("selected-model");
selector.addEventListener("change", e => {
window.localStorage.setItem("selected-model", e.target.value);
});
header.insertBefore(selector, header.children[header.children.length - 1]);
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment