NickHub Back to the tracker

Under the hood

How a WoW run ends up on a website

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.

  1. In the gameThe addon

    Listens to the game and logs what happens.

  2. On the PCThe saved file

    The one place an addon is allowed to write.

  3. On the PCThe uploader

    Spots changes and sends them to the site.

  4. On CloudflareThe Worker

    Checks the password and stores the run.

  5. In your browserThe dashboard

    Turns raw data into charts and records.

The addon keeps the diary

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:

LoggedDetails
Level-upsTime, /played, zone and gold
KillsMob, type, level, XP and zone, including pet kills
QuestsTitle, XP, money and how long the quest was held
DeathsWho or what did it, where, and at what level
TravelEach zone change, plus pet deaths and session times

Working out which kills are yours

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.

Matching XP to the right kill

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.

Everything else the game doesn't hand over

The workaround at the center of it all

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.

The uploader is the courier

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:

The Worker is the doorman

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.

The dashboard does the math

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.

Testing a game that wasn't out yet

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.

Good to know

Is this Advanced Combat Logging or a Blizzard API?

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.

Does it play the game or automate anything?

No. It only watches and writes things down. The one action it takes is a UI reload, and only when you ask for one.

Is it live to the second?

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.

Are the numbers perfect?

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.

The stack

PartBuilt with
AddonLua, WoW's addon API
UploaderPython standard library
BackendCloudflare Workers and KV
DashboardPlain HTML, CSS and JavaScript, Chart.js

All of it is open to read: view the code on GitHub.