Type “cs2 ranks in order” into Google and you get a dozen pages with the same static list and a banner ad above the fold. None of them tell you where you actually stand right now, how far you are from the next tier, or whether your last ten matches are trending up or down. This tutorial fixes that by walking through a small Python tool that stores the full CS2 rank ladder (both Premier CS Rating and the classic Competitive skill groups), pulls your Steam profile data, and logs your progress over time in a local database you control.
By the end you will have a working command-line tracker, a SQLite history file, and a clear mental model of how CS2’s two separate ranking systems relate to each other. The project takes about 45 to 60 minutes if you already have Python installed, longer if this is your first time setting up a virtual environment.
What You’ll Build: A CS2 Rank Order Lookup and Progress Tracker
Counter-Strike 2 runs two parallel ranking systems. Premier mode assigns a numeric CS Rating and groups players into seven color bands, from Grey at the bottom to Gold at the top. Competitive and Wingman modes still use the 18 named skill groups inherited from CS:GO, running from Silver I through Global Elite, and those ranks are tracked separately per map. A lot of players don’t realize both systems run at once, which is why “cs2 ranks in order” searches often mix the two lists together.
The tool you’ll build does three things: it displays both ladders in the correct order with their rating thresholds, it checks your Steam profile through the official Steam Web API to confirm the account is reachable, and it logs the CS Rating you enter after each session so you can see your climb (or your tilt) over time. Valve does not expose a public endpoint that returns live Premier rating, so the tracker works with manual entry plus Steam profile verification rather than pretending to scrape data that isn’t officially available.
Prerequisites
Gather these before you start:
- Python 3.11 or newer (3.12 is fine too) installed and on your PATH
- pip 23.x or newer
- A free Steam Web API key from the Steam API key registration page
- Your SteamID64 (a 17-digit number, not your custom URL name)
- A public or “friends only with game details” Steam profile (fully private profiles return empty data)
- requests 2.32 or newer, installed via pip
- Basic comfort with a terminal, no prior API experience required
If you don’t know your SteamID64 off the top of your head, open your Steam profile in a browser, and a site like SteamID.io will convert your custom URL into the 64-bit number the Steam Web API expects. Trying to pass your display name or your /id/ vanity URL straight into the API is one of the most common mistakes in this whole project, so get that number written down now.
Step 0: Find Your SteamID64 Without Guessing
Steam actually uses three different ID formats, and only one of them works with the Web API calls in this project. SteamID (the old STEAM_0:1:xxxx format), SteamID3 (the bracketed [U:1:xxxx] version), and SteamID64 (a plain 17-digit number starting with 7656) all refer to the same account, but the Steam Web API only accepts the 64-bit form. If your profile uses a custom URL like steamcommunity.com/id/yourhandle, that handle is not your SteamID64 either, it’s just a vanity string that Steam resolves internally.
The fastest way to get the right number is to open your own profile page, right-click anywhere on it, and view the page source, then search for “steamid”. You’ll see the 17-digit value sitting right next to your account’s internal data. Third-party converter sites work too, but paste your result into the steam_api.py script from Step 7 before you trust it. If the script returns your correct display name, the ID is right. If it throws a RuntimeError, you copied the wrong format.
Step 1: Learn the Two CS2 Rank Ladders in Order
Before writing any code, you need the reference data straight. Competitive and Wingman matchmaking use the same 18-rank skill group list, run from lowest to highest below.
| Order | Competitive / Wingman Rank |
|---|---|
| 1 | Silver I |
| 2 | Silver II |
| 3 | Silver III |
| 4 | Silver IV |
| 5 | Silver Elite |
| 6 | Silver Elite Master |
| 7 | Gold Nova I |
| 8 | Gold Nova II |
| 9 | Gold Nova III |
| 10 | Gold Nova Master |
| 11 | Master Guardian I |
| 12 | Master Guardian II |
| 13 | Master Guardian Elite |
| 14 | Distinguished Master Guardian |
| 15 | Legendary Eagle |
| 16 | Legendary Eagle Master |
| 17 | Supreme Master First Class |
| 18 | Global Elite |
A detail that trips people up: Competitive rank is tracked per map, not globally. You can sit at Legendary Eagle on Mirage and Gold Nova III on Inferno at the same time, because the hidden rating behind each map’s queue is separate. If your friend claims a single “Competitive rank” for the whole game, they’re simplifying, and your tracker should account for that when you log results.
Step 2: Map the Premier CS Rating Bands
Premier mode skips named ranks entirely and shows a raw CS Rating number, color-coded into seven bands. The widely used community breakdown runs in 5,000-point increments, topping out at Gold for anything at 30,000 or above.
| Order | Premier Color Band | CS Rating Range |
|---|---|---|
| 1 | Grey | 0 – 4,999 |
| 2 | Light Blue | 5,000 – 9,999 |
| 3 | Blue | 10,000 – 14,999 |
| 4 | Purple | 15,000 – 19,999 |
| 5 | Pink | 20,000 – 24,999 |
| 6 | Red | 25,000 – 29,999 |
| 7 | Gold | 30,000+ |
Treat the color names as community shorthand, not an official Valve label. The game itself just shows your number. New accounts also need to clear placement matches before Premier displays any rating at all, which is why distribution charts sometimes exclude fresh accounts and sometimes don’t, producing the mismatched percentages you’ll see across different tracking sites.
Step 3: Check Current Distribution Data (And Why It Varies)
Third-party sites like Leetify publish rank distribution snapshots pulled from the accounts they track, and the numbers shift depending on sample size, region, and whether placement accounts are counted. One 2026 snapshot from Leetify’s Premier rank distribution data library put the Blue band around a quarter of tracked players, with Gold representing a tiny fraction at the very top. Treat any specific percentage you read as an estimate from that tracker’s sample, not a Valve-published statistic.
| Premier Band | Approximate Share (third-party estimate) |
|---|---|
| Grey | ~21% |
| Light Blue | ~24% |
| Blue | ~26% |
| Purple | ~19% |
| Pink | ~8% |
| Red | ~2% |
| Gold | <1% |
Our tracker will store your own rating history locally instead of relying on any single tracker’s population snapshot, so your percentile comparisons stay consistent over time even if third-party sample sizes shift month to month.
Step 4: Set Up Your Project Folder and Virtual Environment
Create a clean folder and isolate dependencies so this project doesn’t fight with other Python work on your machine.
mkdir cs2-rank-order
cd cs2-rank-order
python3 -m venv venv
source venv/bin/activate # on Windows: venv\Scripts\activate
pip install --upgrade pip
Next, add a requirements file so the environment is reproducible on another machine or in a scheduled job later.
# requirements.txt
requests==2.32.3
python-dotenv==1.0.1
pip install -r requirements.txt
Step 5: Get Your Steam Web API Key and Store It Safely
Register a key at the Steam API key page using any domain name (localhost works for personal projects). Steam issues the key instantly and ties it to your account. Never commit this key to a public repository. Create a .env file instead and load it with python-dotenv.
# .env
STEAM_API_KEY=your_key_here
STEAM_ID64=765611980xxxxxxxx
Add .env to your .gitignore immediately, before you run your first git commit, not after. API keys that leak into public repositories get scraped and abused within hours, and automated secret-scanning bots actively watch for this exact pattern of leaked Steam and gaming API keys.
A Short Note on Securing Your Steam Credentials
Because this is a security-conscious tutorial, it’s worth being explicit about what this project does and doesn’t touch. The Steam Web API key you generated only grants read access to public profile data, it cannot log into your account, open a trade, or change your password. That’s a meaningfully smaller attack surface than the credentials phishing kits that impersonate rank-boosting or skin-trading tools and ask for your actual Steam username and password. Never paste your real Steam login into any third-party rank checker, including ones that look like official Valve pages. This tutorial’s script only ever sends your API key and SteamID64 to api.steampowered.com over HTTPS, nothing else.
It’s also good practice to rotate the key if you ever suspect it leaked, Steam lets you revoke and regenerate a Web API key from the same registration page at any time, and any script using the old key will start failing with a 403 immediately. Treat the key the same way you’d treat a database password: scoped, revocable, and never pasted into a chat window or a public gist.
Step 6: Build the Rank Ladder Data Module
This file holds both ladders as plain Python data structures, which keeps the lookup logic simple and testable.
# ranks.py
COMPETITIVE_RANKS = [
"Silver I", "Silver II", "Silver III", "Silver IV",
"Silver Elite", "Silver Elite Master",
"Gold Nova I", "Gold Nova II", "Gold Nova III", "Gold Nova Master",
"Master Guardian I", "Master Guardian II", "Master Guardian Elite",
"Distinguished Master Guardian",
"Legendary Eagle", "Legendary Eagle Master",
"Supreme Master First Class", "Global Elite",
]
PREMIER_BANDS = [
("Grey", 0, 4999),
("Light Blue", 5000, 9999),
("Blue", 10000, 14999),
("Purple", 15000, 19999),
("Pink", 20000, 24999),
("Red", 25000, 29999),
("Gold", 30000, None),
]
def band_for_rating(rating: int) -> str:
for name, low, high in PREMIER_BANDS:
if high is None and rating >= low:
return name
if high is not None and low <= rating <= high:
return name
raise ValueError(f"Rating {rating} is out of the known Premier range")
def progress_to_next_band(rating: int) -> dict:
for i, (name, low, high) in enumerate(PREMIER_BANDS):
if high is not None and low <= rating <= high:
next_name = PREMIER_BANDS[i + 1][0]
points_needed = (high + 1) - rating
return {"current": name, "next": next_name, "points_needed": points_needed}
return {"current": "Gold", "next": None, "points_needed": 0}
Running this module standalone with a few sample ratings is a fast way to confirm the band boundaries before you wire in live data. Feed it 14,999 and 15,000 back to back and check the output flips from Blue to Purple exactly where it should.
Test the Band Logic Before You Trust It
Boundary math is exactly the kind of thing that looks obviously correct and is quietly off by one. Before this logic ever touches your real rating history, write a handful of tests that check the edges of every band, not just the middle values. Install pytest and add a small test file next to ranks.py.
# test_ranks.py
from ranks import band_for_rating, progress_to_next_band
def test_band_boundaries():
assert band_for_rating(0) == "Grey"
assert band_for_rating(4999) == "Grey"
assert band_for_rating(5000) == "Light Blue"
assert band_for_rating(14999) == "Blue"
assert band_for_rating(15000) == "Purple"
assert band_for_rating(30000) == "Gold"
assert band_for_rating(55000) == "Gold"
def test_progress_calculation():
result = progress_to_next_band(13450)
assert result["current"] == "Blue"
assert result["next"] == "Purple"
assert result["points_needed"] == 1550
pip install pytest
pytest test_ranks.py -v
Five minutes spent on this file saves you from a tracker that silently miscounts your climb for weeks before anyone notices the off-by-one error at a band boundary.
Step 7: Verify Your Steam Profile Through the Official API
Before logging any rating, confirm the Steam Web API can actually see your profile. The ISteamUser/GetPlayerSummaries endpoint, documented on the Steam Web API overview page, returns basic profile data and a visibility flag.
# steam_api.py
import os
import requests
from dotenv import load_dotenv
load_dotenv()
API_KEY = os.environ["STEAM_API_KEY"]
STEAM_ID = os.environ["STEAM_ID64"]
BASE_URL = "https://api.steampowered.com"
def get_player_summary(steam_id: str = STEAM_ID) -> dict:
url = f"{BASE_URL}/ISteamUser/GetPlayerSummaries/v2/"
params = {"key": API_KEY, "steamids": steam_id}
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
players = response.json()["response"]["players"]
if not players:
raise RuntimeError("Steam returned no player data. Check the SteamID64 and profile visibility.")
return players[0]
if __name__ == "__main__":
player = get_player_summary()
visibility = player.get("communityvisibilitystate")
print(f"Name: {player.get('personaname')}")
print(f"Visibility state: {visibility} (3 = public, 1 = private)")
Run python steam_api.py. A visibility state of 3 means your profile is public and the rest of the project will work cleanly. A value of 1 means the profile is private, and you'll need to switch "Game details" to public in your Steam privacy settings before continuing.
Step 8: Build the SQLite History Table
Since Valve doesn't expose live Premier rating through a public endpoint, you'll enter your current rating manually after each session (copied straight from the in-game Premier screen) and let the tool log it with a timestamp.
# db.py
import sqlite3
DB_PATH = "rank_history.db"
def init_db():
conn = sqlite3.connect(DB_PATH)
conn.execute("""
CREATE TABLE IF NOT EXISTS rating_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
logged_at TEXT NOT NULL,
rating INTEGER NOT NULL,
band TEXT NOT NULL
)
""")
conn.commit()
conn.close()
def log_rating(rating: int, band: str):
conn = sqlite3.connect(DB_PATH)
conn.execute(
"INSERT INTO rating_log (logged_at, rating, band) VALUES (datetime('now'), ?, ?)",
(rating, band),
)
conn.commit()
conn.close()
def recent_history(limit: int = 10):
conn = sqlite3.connect(DB_PATH)
rows = conn.execute(
"SELECT logged_at, rating, band FROM rating_log ORDER BY id DESC LIMIT ?",
(limit,),
).fetchall()
conn.close()
return rows
SQLite needs no server and ships with Python's standard library, which keeps this project to a single file you can back up or move between machines without touching a database admin console.
Step 9: Tie It Together With a CLI Entry Point
Now wire ranks.py, steam_api.py, and db.py into one command you run after each session.
# tracker.py
import argparse
from ranks import band_for_rating, progress_to_next_band
from db import init_db, log_rating, recent_history
from steam_api import get_player_summary
def main():
parser = argparse.ArgumentParser(description="CS2 rank order progress tracker")
parser.add_argument("--rating", type=int, required=True, help="Current Premier CS Rating")
parser.add_argument("--history", action="store_true", help="Show the last 10 logged entries")
args = parser.parse_args()
init_db()
if args.history:
for logged_at, rating, band in recent_history():
print(f"{logged_at} | {rating:>6} | {band}")
return
player = get_player_summary()
band = band_for_rating(args.rating)
progress = progress_to_next_band(args.rating)
log_rating(args.rating, band)
print(f"Steam account: {player.get('personaname')}")
print(f"Current rating: {args.rating} ({band})")
if progress["next"]:
print(f"Points to {progress['next']}: {progress['points_needed']}")
else:
print("You're in the top Premier band.")
if __name__ == "__main__":
main()
Step 10: Run It and Read the Output
With your .env file in place, log your first session:
python tracker.py --rating 13450
Expected output:
Steam account: yourhandle
Current rating: 13450 (Blue)
Points to Purple: 1550
Check your running history anytime with python tracker.py --history, which prints the timestamp, rating, and band for your last ten logged sessions straight from SQLite.
Step 11: Automate Logging With a Scheduled Task
Manual entry still beats no data at all, but you can at least automate the reminder. A cron entry on macOS or Linux can prompt you to log after your typical play window.
# crontab -e
# Reminder to log rating every night at 11pm
0 23 * * * /usr/bin/osascript -e 'display notification "Log your CS2 rating" with title "CS2 Tracker"'
On Windows, Task Scheduler can trigger the same kind of notification through a scheduled PowerShell script. Either way, the goal is consistency: a rating logged every session beats a perfect tracker you only open once a month.
Step 12: Extend the Tool With Competitive Map Ranks
Since Competitive rank is tracked per map, extend the rating_log table with a nullable map_name and comp_rank column, then add a second CLI flag, --map and --comp-rank, that logs entries from COMPETITIVE_RANKS instead of a Premier number. This lets one tool track both ladders side by side, which is exactly the gap that static "cs2 ranks in order" list pages can't fill, since they show you the ladder but never your place on it.
A Full Walkthrough From a Clean Machine
Here's what the whole build looks like end to end on a fresh laptop, to show how the pieces from every step above fit together in practice. Start from an empty folder.
$ mkdir cs2-rank-order && cd cs2-rank-order
$ python3 -m venv venv
$ source venv/bin/activate
$ pip install requests python-dotenv pytest
$ touch ranks.py steam_api.py db.py tracker.py .env .gitignore
$ echo "venv/" >> .gitignore
$ echo ".env" >> .gitignore
After pasting in the code from Steps 6 through 9 and filling in your real API key and SteamID64 in .env, the first real run looks like this.
$ pytest test_ranks.py -v
test_ranks.py::test_band_boundaries PASSED
test_ranks.py::test_progress_calculation PASSED
$ python tracker.py --rating 9800
Steam account: yourhandle
Current rating: 9800 (Light Blue)
Points to Blue: 200
$ python tracker.py --rating 10200
Steam account: yourhandle
Current rating: 10200 (Blue)
Points to Purple: 4800
$ python tracker.py --history
2026-10-08 19:02:11 | 10200 | Blue
2026-10-08 18:14:03 | 9800 | Light Blue
Two sessions in, the history already shows a band change from Light Blue to Blue, logged with a timestamp down to the second. That's the whole payoff of this project: a thirty-minute build turns a static "cs2 ranks in order" reference page into a personal log you can query, graph, or extend for as long as you keep playing.
Common Pitfalls When Building a CS2 Rank Tracker
- Passing the wrong SteamID format. The API needs the 17-digit SteamID64, not your vanity URL or SteamID3 bracket notation.
- Assuming Premier rating is publicly queryable. No official Valve endpoint returns it, so plan for manual entry or a third-party data source from the start.
- Leaving the Steam profile private.
GetPlayerSummariesreturns almost nothing useful if "Game details" is set to private. - Hardcoding the API key in source. Use environment variables and gitignore the file before your first commit, not after.
- Ignoring placement accounts. A fresh Premier account with no completed placements has no rating yet, and your band lookup should handle that case instead of crashing.
- Treating Competitive rank as global. It's per map. Logging one number for "Competitive rank" overall will quietly produce wrong history.
- Skipping rate-limit handling. The Steam Web API throttles aggressive polling, so add a short delay between calls if you expand this to multiple accounts.
Troubleshooting Guide
- 401 Unauthorized from the Steam API: your key is missing or mistyped in
.env. Reload the file and confirmos.environ["STEAM_API_KEY"]prints a value. - Empty
playerslist in the JSON response: the SteamID64 is wrong, or the account was banned, deleted, or set to fully private. - ModuleNotFoundError: No module named 'requests': the virtual environment isn't active. Run
source venv/bin/activateagain before installing or running anything. - sqlite3.OperationalError: database is locked: two processes wrote to
rank_history.dbat once. Avoid running the cron reminder and a manual log command in the same second. - ValueError: Rating out of known Premier range: you typed a negative number, or a rating above 30,000 triggered an edge case. The Gold band has no upper bound, so check your
band_for_ratinglogic handleshigh is None. - Script runs locally but the cron job does nothing: cron often uses a minimal PATH. Use absolute paths to the Python binary and script file inside the crontab entry.
- SSL certificate errors on a work or school network: upgrade
certifiwithpip install --upgrade certifi, since outdated certificate bundles are a common cause on locked-down networks. - The number you logged doesn't match the in-game screen: Premier rating updates immediately after a match ends, so log it right after your last game, not hours later from memory.
Staying Current When Valve Changes the Rank System
Valve has adjusted CS2's ranking systems before, and will again. As of this writing there's no verified official patch note describing a change to the seven Premier bands or the 18 Competitive skill groups beyond what's documented here, but rank guides age badly if you treat them as permanent. Before you lean on the PREMIER_BANDS thresholds in this tutorial for anything important, like a tournament seeding decision or a coaching benchmark, check the official CS2 news feed on Steam for the most recent patch notes rather than trusting a cached blog post.
If Valve does shift a threshold, the fix in this codebase is contained to one file. Update the tuples inside PREMIER_BANDS in ranks.py, rerun the pytest suite from earlier to confirm the boundary tests still pass with the new numbers, and your historical SQLite entries stay untouched since they store the raw rating alongside the band name you logged at the time. That's the practical advantage of building your own small tool over depending entirely on someone else's dashboard: when the source data changes, you control exactly how the update rolls out.
Advanced Tips for Extending the Tracker
Once the basic loop works, a few upgrades add real value without much extra code. Wire a Discord webhook into tracker.py so the tool posts an automatic message whenever band_for_rating returns a different band than your last logged entry, turning a silent log into an actual rank-up alert. If you record match demos, a parsing library can pull per-round data directly from .dem files instead of manual entry, closing the biggest gap in this build. And if you'd rather not keep a machine running around the clock, a scheduled cloud job can run the same script on a timer and push results to a private repository instead of a local SQLite file.
The Complete Project in One Place
Your finished folder should contain five files: requirements.txt, .env, ranks.py, steam_api.py, db.py, and tracker.py, plus the rank_history.db file that SQLite creates automatically on first run. That's the entire working project: no external server, no paid API tier, and no dependency beyond requests and python-dotenv. You can zip the folder (minus .env and the venv directory) and hand it to a teammate, and it will run the same way on their machine after a fresh pip install -r requirements.txt.
Why Premier CS Rating and Competitive Rank Stay Separate
Valve built Premier as a numeric system specifically so players could see fine-grained movement after every match instead of waiting for a rank-up screen that might only appear every few weeks. Competitive mode kept its named skill groups because a huge base of long-time players still associates terms like Global Elite with two decades of Counter-Strike history, and ripping that out would have been its own controversy. The two systems measure different queues, and third-party guides that map one directly onto the other (claiming, for instance, that a specific CS Rating equals Legendary Eagle) are making an approximation, not citing an official Valve conversion table. Build your own tracker, and you sidestep that whole debate by logging exactly what the game shows you, in the order it actually ranks you.
How This Compares to Third-Party CS2 Rank Trackers
Sites like Leetify, csstats.gg, and similar trackers pull data from large pools of players and give you percentile comparisons against thousands of other accounts, something a single-user script can't replicate. If you want to know whether your 13,450 rating puts you ahead of 60% of the player base or 80%, those sites are the right tool, and nothing in this tutorial competes with that scale.
What this project gives you instead is full ownership of your own history, with no account creation, no third-party server storing your match data, and no risk of a tracker shutting down and taking your rating history with it. The two approaches aren't really competing, pair a population-wide tracker for context with your own local log for the ground truth of your personal climb, and you get the best of both. Several players who build tools like this one eventually export their SQLite history into a spreadsheet or a Grafana dashboard once they have a few months of data logged, which is a natural next step once the basic loop in this tutorial is running reliably.
Frequently Asked Questions
What are all the CS2 ranks in order from lowest to highest?
Competitive and Wingman use 18 skill groups in order: Silver I through Silver IV, Silver Elite, Silver Elite Master, Gold Nova I through III, Gold Nova Master, Master Guardian I and II, Master Guardian Elite, Distinguished Master Guardian, Legendary Eagle, Legendary Eagle Master, Supreme Master First Class, and Global Elite. Premier mode instead uses seven CS Rating bands: Grey, Light Blue, Blue, Purple, Pink, Red, and Gold.
Is Premier rating the same as Competitive rank?
No. They're two separate matchmaking systems that run in parallel. Premier shows one numeric rating, while Competitive ranks are tracked per map using the classic named skill groups.
Can I check my CS2 Premier rating directly through the Steam Web API?
Not through any official public endpoint as of this writing. The Steam Web API can confirm your profile and basic Steam data, but live Premier rating isn't exposed, which is why this tutorial logs your rating manually rather than claiming to fetch it automatically.
Why does my Competitive rank look different on different maps?
Because Competitive rank is calculated per map rather than as one global number. A player can hold a high rank on a map they play constantly and a much lower rank on one they rarely queue.
How often does Premier CS Rating update?
It updates immediately after each completed match, which is why logging your number right after a session, rather than from memory later, keeps your tracker's history accurate.
What happens if my Steam profile is set to private?
The GetPlayerSummaries endpoint will return a visibility state of 1 and little else. Switch "Game details" to public in your Steam privacy settings so the API call in this tutorial returns usable data.
Is there an official Valve API for full CS2 match history?
Not a general-purpose public one. Most community trackers combine Steam profile data with demo parsing or their own collected datasets rather than a single official match-history endpoint.
How accurate are third-party CS2 rank distribution percentages?
They're estimates based on whatever sample of accounts each tracking site collects, not Valve-published statistics, and different sites report noticeably different percentages for the same bands because of that.




