
If somebody wants check your premier rating in widget(similar to FACEIT widget) here you go, easy setup, just download scriptable, and I’ll post full code down below.
// Variables used by Scriptable.
// These must be at the very top of the file. Do not edit.
// icon-color: deep-blue; icon-glyph: crosshairs;
/*
* CS2 PREMIER STATS WIDGET
* * Displays your Rating, Global Rank Tier, K/D, HLTV Rating, and Win Rate.
* Uses aggressive caching to prevent timeouts on the iOS Home Screen.
* * HOW TO USE:
* 1. Go to https://csstats.gg/ and find your profile.
* 2. Copy your STEAM ID (the numbers in the URL).
* 3. Add this script to a widget.
* 4. Long press the widget -> Edit Widget.
* 5. Paste your STEAM ID into the "Parameter" field.
* * Alternatively, enter your ID in the CONFIG section below.
*/
// — CONFIGURATION —
// Enter your Steam ID here if you don't want to use the Widget Parameter
const DEFAULT_STEAM_ID = "";
// — MAIN LOGIC —
const widgetParam = args.widgetParameter;
const steamID = widgetParam || DEFAULT_STEAM_ID;
if (!steamID || steamID === "") {
let w = createSetupWidget();
if (!config.runsInWidget) await w.presentSmall();
Script.setWidget(w);
Script.complete();
} else {
await runWidget(steamID);
}
async function runWidget(id) {
const url = "https://csstats.gg/player/" + id;
const fm = FileManager.local();
// Unique cache file per Steam ID allows multiple widgets for different players
const cachePath = fm.joinPath(fm.documentsDirectory(), `csstats_cache_${id}.json`);
// 1. Load Cache
let cachedData = null;
if (fm.fileExists(cachePath)) {
cachedData = JSON.parse(fm.readString(cachePath));
}
let finalData = cachedData;
try {
// 2. Fetch Fresh Data (Race against 13s timeout)
let freshData = await Promise.race([
getFreshStats(url),
new Promise((_, reject) => Timer.schedule(13000, false, () => reject("TIMEOUT")))
]);
// 3. Update Cache if successful
if (freshData && freshData.rating !== "0") {
finalData = freshData;
fm.writeString(cachePath, JSON.stringify(finalData));
}
} catch (e) {
// Fallback to cache on timeout/error
if (finalData) finalData.isCached = true;
}
// Fallback for very first run with no internet
if (!finalData) {
finalData = { rating: "0", kd: "—", hltv: "—", wr: "—", timestamp: new Date().getTime() };
}
let w = createStatsWidget(finalData, id);
if (!config.runsInWidget) await w.presentSmall();
Script.setWidget(w);
Script.complete();
}
// — SCRAPER —
async function getFreshStats(url) {
let wv = new WebView();
await wv.loadURL(url);
let jsonString = await wv.evaluateJavaScript(`
var maxAttempts = 22; // ~11 seconds
var interval = setInterval(function() {
maxAttempts–;
var text = document.body.innerText;
// Wait for essential keywords or timeout
if ((text.includes("Rating") && text.includes("K/D")) || maxAttempts <= 0) {
clearInterval(interval);
var ratingMatch = text.match(/([0-9]{1,3}[, ][0-9]{3})/);
var kdMatch = text.match(/K\\/?D(?:\\s*Ratio)?[\\s\\n]*([0-9]+\\.[0-9]+)/i);
var hltvMatch = text.match(/(?:Rating 2\\.0|HLTV Rating|Rating)[\\s\\n]*([0-9]+\\.[0-9]+)/i);
var wrMatch = text.match(/Win Rate[\\s\\n]*([0-9]+%)/i);
var result = {
success: true,
timestamp: new Date().getTime(),
rating: ratingMatch ? ratingMatch[1].replace(/[^0-9]/g, "") : "0",
kd: kdMatch ? kdMatch[1] : "—",
hltv: hltvMatch ? hltvMatch[1] : "—",
wr: wrMatch ? wrMatch[1] : "—"
};
completion(JSON.stringify(result));
}
}, 500);
`, true);
return JSON.parse(jsonString);
}
// — WIDGET UI —
function createStatsWidget(d, id) {
let num = parseInt(d.rating);
// Dynamic Theme
let theme = { m: "#5665e8", bg: "#0d0e17" }; // Blue <15k
if (num >= 30000) theme = { m: "#f7d93d", bg: "#1a160d" }; // Gold
else if (num >= 25000) theme = { m: "#eb4b4b", bg: "#1a0d0d" }; // Red
else if (num >= 20000) theme = { m: "#d32de6", bg: "#150b17" }; // Pink
else if (num >= 15000) theme = { m: "#9e4dd6", bg: "#110a17" }; // Purple
let w = new ListWidget();
w.backgroundColor = new Color(theme.bg);
w.setPadding(10, 8, 10, 8);
w.url = "https://csstats.gg/player/" + id;
// Header
let h = w.addStack();
h.centerAlignContent();
let tag = h.addStack();
tag.backgroundColor = new Color(theme.m, 0.2);
tag.setPadding(3, 6, 3, 6); tag.cornerRadius = 4;
let tagT = tag.addText("CS2 PREMIER");
tagT.font = Font.blackSystemFont(8); tagT.textColor = new Color(theme.m);
h.addSpacer();
// Status & Time
let date = new Date(d.timestamp || new Date().getTime());
let timeStr = date.getHours().toString().padStart(2, '0') + ":" + date.getMinutes().toString().padStart(2, '0');
let statusColor = d.isCached ? Color.orange() : new Color("#ade347");
if (d.rating === "0") statusColor = Color.red();
let liveDot = h.addText("●");
liveDot.font = Font.blackSystemFont(6);
liveDot.textColor = statusColor;
h.addSpacer(3);
let liveText = h.addText(timeStr);
liveText.font = Font.boldSystemFont(8);
liveText.textColor = Color.white();
liveText.opacity = 0.6;
w.addSpacer(10);
// Rating
let rStack = w.addStack();
rStack.centerAlignContent();
let rText = rStack.addText(num > 0 ? num.toLocaleString().replace(/,/g, ' ') : "LOADING…");
rText.font = Font.italicSystemFont(40); rText.textColor = Color.white();
rText.shadowColor = new Color(theme.m, 0.6); rText.shadowRadius = 4; rText.shadowOffset = new Point(0, 2);
rText.minimumScaleFactor = 0.8;
w.addSpacer(12);
// Stats Row
let sRow = w.addStack();
sRow.centerAlignContent();
sRow.spacing = 3;
let addStatPill = (label, value) => {
let s = sRow.addStack();
s.backgroundColor = new Color("#ffffff", 0.08);
s.setPadding(3, 4, 3, 4); s.cornerRadius = 5; s.centerAlignContent();
let l = s.addText(label);
l.font = Font.boldSystemFont(8); l.textColor = new Color("#ffffff", 0.5);
s.addSpacer(2);
let v = s.addText(value);
v.font = Font.boldSystemFont(9); v.textColor = Color.white();
v.lineLimit = 1; v.minimumScaleFactor = 0.7;
}
addStatPill("KD", d.kd);
addStatPill("HLTV", d.hltv);
addStatPill("WR", d.wr);
w.addSpacer(12);
// Progress Bar
let next = Math.ceil((num + 1) / 5000) * 5000;
if (num === 0) next = 5000;
let barBg = w.addStack();
barBg.size = new Size(0, 5); barBg.backgroundColor = new Color("#ffffff", 0.1); barBg.cornerRadius = 2.5;
let pct = (num % 5000) / 5000;
if (pct < 0) pct = 0;
let fill = barBg.addStack();
fill.size = new Size(135 * pct, 5);
fill.backgroundColor = new Color(theme.m); fill.cornerRadius = 2.5;
w.addSpacer(6);
// Footer
let fStack = w.addStack();
let foot = fStack.addText(`${next – num} TO NEXT RANK`);
foot.font = Font.heavySystemFont(7); foot.textColor = new Color("#ffffff", 0.4);
fStack.addSpacer();
let rankName = fStack.addText(`TIER ${Math.floor(next/1000)}K`);
rankName.font = Font.heavySystemFont(7); rankName.textColor = new Color(theme.m, 0.8);
return w;
}
function createSetupWidget() {
let w = new ListWidget();
w.backgroundColor = new Color("#1a1a1a");
let t = w.addText("⚠️ SETUP REQUIRED");
t.font = Font.boldSystemFont(12);
t.textColor = Color.red();
w.addSpacer(10);
let msg = w.addText("Long press widget > Edit Widget > Set 'Parameter' to your Steam ID.");
msg.font = Font.systemFont(10);
return w;
}