Under the hood
World of Warcraft doesn't let addons go online. NickHub still puts every kill, quest and death on a public site, without a server to look after. Here's the trick.
Listens to the game and logs what happens.
The one place an addon is allowed to write.
Spots changes and sends them to the site.
Checks the password and stores the run.
Turns raw data into charts and records.
WoW announces almost everything that happens through events: you gained XP, a quest was turned in, something died. NickHub Tracker is about 430 lines of Lua, the language WoW addons are written in. It subscribes to 17 of those events and writes down the ones that matter for a leveling run:
| Logged | Details |
|---|---|
| Level-ups | Time, /played, zone and gold |
| Kills | Mob, type, level, XP and zone, including pet kills |
| Quests | Title, XP, money and how long the quest was held |
| Deaths | Who or what did it, where, and at what level |
| Travel | Each zone change, plus pet deaths and session times |
The combat log says when something dies, but not who gets credit. So the addon tags any NPC that you or your pet hurts. If a tagged mob dies later, that's a kill.
-- anything I (or my pet) do to an NPC marks it as "mine"
if isMine(srcFlags) and npcKey(dstGUID) and (DAMAGE[sub] or sub:find("^SPELL_AURA_APPLIED")) then
if not tagged[dstGUID] then tagged[dstGUID] = { name = dstName, t = GetTime() } end
end
From the addon. Every creature has a unique ID, so two wolves with the same name never get mixed up.
The game doesn't include XP in the death event. It arrives separately as a chat message, the same "dies, you gain 50 experience" line you see in game, and it can land just before or just after the death. The addon reads that message and pairs it with the matching mob name within a three-second window, whichever arrives first. The message pattern comes from the game's own text, so it isn't tied to English.
Addons run in a locked-down sandbox with no internet access and no general file access. Their only way to keep anything is a saved variables file, and WoW only writes that to disk on logout or a UI reload.
That one rule shapes the whole design. Typing /nh sync forces a UI reload, about three seconds, which makes WoW save the file. If you're in combat, the addon waits until the fight ends, then asks. With /nh auto on, it offers a one-click Sync button after every level-up.
So the addon never touches the internet. It leaves a note in a file, and something outside the game picks it up.
A small Python script, under 300 lines with no extra packages, runs on the PC while you play. Being outside the game, it isn't bound by WoW's rules. Every few seconds it does the following:
Most websites need a computer running all day waiting for visitors. A Cloudflare Worker flips that. It's a small piece of code, about 70 lines of JavaScript here, that Cloudflare runs on its global network only when a request arrives. There's no server to maintain, and it starts in about a millisecond.
if (url.pathname === "/api/ingest") {
if (request.method !== "POST") return json({ error: "POST only" }, 405);
return ingest(request, env);
}
if (url.pathname === "/api/data") return data(env);
return env.ASSETS.fetch(request);
The Worker's whole routing logic: an upload, a request for stats, or the website itself.
data.The Worker hands over raw data, and your browser does the rest. Records like fastest level and nemesis, the zone journey and the charts are all worked out on the page when it loads, with Chart.js drawing the graphs. The colors follow the character too: hunters get WoW's hunter green.
How do you test a tracker for a run that hasn't happened? A simulator. A test harness fakes WoW's API and runs the real addon through a full 1โ60 run, firing kills, quests, deaths and level-ups along the way, then feeds the result through the real uploader's parser. The demo data on the site comes from that run: thousands of kills, all simulated, until the first real sync replaces them.
Neither. It doesn't use the WoWCombatLog.txt file that Warcraft Logs reads, or Blizzard's web API. It listens to the in-game event stream that addons like Details! and DBM use, from inside the client.
No. It only watches and writes things down. The one action it takes is a UI reload, and only when you ask for one.
Not quite. Nothing leaves the game until a sync or logout, so the site updates moments after each sync, not after each kill. Nothing is lost in between.
Very close, with known edges. A mob you hit that another player tagged can occasionally count as a kill, and mobs only get a type and level if they were seen by target, mouseover or nameplate.
| Part | Built with |
|---|---|
| Addon | Lua, WoW's addon API |
| Uploader | Python standard library |
| Backend | Cloudflare Workers and KV |
| Dashboard | Plain HTML, CSS and JavaScript, Chart.js |
All of it is open to read: view the code on GitHub.