Read your clan's DropTracker data from your own app — stats, collection logs, combat achievements, personal bests, loot and more. Everything here needs an API key, and keys are free.
Quickstart
Create a key. Group admins make one from their group settings; individual supporters can make one from account settings.
Copy it when it is shown — it is displayed once and cannot be retrieved again.
Every endpoint except /v2/health needs a key, sent as Authorization: Bearer dtk_…. There is no query-parameter form — a key in a URL ends up in server logs, browser history and Referer headers, so the header is the only way in.
A key sees exactly what its owner could see on the website and nothing more. A group key reads that group's members; a user key reads the accounts that user has claimed; a global key reads every group and every player. Global keys are issued by staff to third-party integrations — a site displaying clan information, for example — and are never self-serve. GET /v2/meta tells you which one you hold, as scope.
A global key is not a visibility override. Players who have hidden themselves, and players whose account owner is hidden, are invisible through this API to every scope — exactly as they are to a signed-out visitor on the website. “Everything” means everything the site itself would show.
Missing, malformed, unknown, revoked and expired keys all return the same 401. That is deliberate: the id inside a token must not become a way to find out which keys exist.
Rate limits
Limits belong to the key, not to any subscription. Every key starts on the same entry tier, including keys owned by premium groups. Higher tiers are granted by staff once a consumer's traffic has proven well-behaved — so build something that works first, then ask for more room.
Budget
What it caps
requests_per_min
How many calls you may make in a minute.
cost_units_per_min
How much actual work you may cause in a minute — see the cost model below.
requests_per_day
Sustained daily volume.
max_concurrency
How many requests you may have in flight at once.
Read your own limits from GET /v2/meta at runtime rather than hardcoding them; they change when a key is promoted. Every response also carries them as headers:
Going over any budget returns 429 with Retry-After and a limit field naming which one you hit.
How requests are priced
Not all requests are equal. One player's loot total is a single cached lookup; a hundred players' full collection logs is hundreds of thousands of rows. So instead of counting requests alone, we price them:
cost = number of players x sum of the cost of each requested section
The cost is charged before the query runs, so an over-budget request is refused rather than executed and billed afterwards. That is what stops one integration slowing the service down for everyone — including you.
Worked examples
One player, include=identity,loot → costs 1.
A 100-player page of identity,loot → costs 100.
A 100-player page of all → costs 39,500.
A whole 400-member roster, every section — four pages — costs 158,000, which fits inside one minute on the entry tier with room to spare. Measured end to end: about 10 seconds and 1.1 MB of compressed JSON.
The prices are measured, not estimated — one unit is roughly 0.05 ms of server work per player. That is why the spread is so wide: clog_slots genuinely costs 161x what loot does, and pricing them closer together would mean cheap requests subsidising expensive ones.
Endpoints
Base URL: https://api.droptracker.io/v2
GET/v2/groups
Every group
All groups, cursor-paginated, with each one's visible member count. Requires a global key — the scope issued to third-party integrations.
Parameter
Default
Notes
limit
25
Groups per page. Maximum 100.
cursor
—
The `next_cursor` from your previous response.
GET/v2/players
Every player
All visible players, cursor-paginated, carrying whichever sections you ask for. Requires a global key; a group key pages its own roster instead.
Parameter
Default
Notes
include
identity
Comma-separated section list, or `all`.
limit
25
Players per page. Maximum 100.
cursor
—
The `next_cursor` from your previous response.
GET/v2/healthno key required
Health
Liveness check. The only endpoint that does not need a key.
GET/v2/meta
About your key
Your key's id, label, tier, what it is scoped to, and the limits currently applied to it. Read your limits from here at runtime rather than hardcoding them — they change when a key is promoted.
GET/v2/sections
Section catalogue
Every section the running API offers and what each one costs. This is the authoritative version of the table on this page.
GET/v2/collection-log
Collection log structure
Every collection log slot — item id and name, grouped into tabs and pages — plus a flat items map of id to name. Read from the game cache and refreshed weekly after the game update, so a new boss's drops are known without anyone editing a file. Game data, not player data: any valid key may read it. Flat cost of 20; updated_at_unix moves only when the structure actually changed, so cache on it. The ids in clog_slots are the keys here.
One page of your group's members, each carrying the same sections. Requires a group-scoped key for that group.
Parameter
Default
Notes
include
identity
Comma-separated section list, or `all`.
limit
25
Players per page. Maximum 100.
cursor
—
The `next_cursor` from your previous response. Omit for the first page.
days
30
Window for the loot sections. Maximum 366.
top
10
Rows per player in the loot breakdowns. Maximum 50.
since
until − 24h
`drops` only: window start, unix seconds UTC. Clamped to at most 7 days before `until`.
until
now
`drops` only: window end, unix seconds UTC. Clamped to now.
max_drops
50
`drops` only: rows per player, newest first. Maximum 200.
npc
—
`drops` only: a boss name or Wise Old Man boss slug (`barrows_chests`). Restricts the feed, and the per-player cap, to that boss — the Boss-of-the-Week query.
?include= takes a comma-separated list, or all. Ask for a section that does not exist and you get a 400 naming it — rather than a response quietly missing the data you wanted. If one section fails while the others succeed, it comes back as {"error": "unavailable"} and the rest of the response is still served.
This table is documentation; GET /v2/sections is the authoritative list for whatever version is running.
Core
Section
Cost
Contains
identity
0
Name, account type, combat and total level, EHB, last sync. Always included — every response says who it is about. last_seen is when the player's DropTracker plugin was last seen (any submission, account sync or event poll), accurate to about 5 minutes, or null if never.
meta
0
Board standing — monthly and all-time rank, with the number of ranked players — plus group memberships. On a group request it also attaches the group's own stats. Free.
plugin_config
1
The player's DropTracker plugin settings as their client last sent them (plugin 6.0.16+): when, plugin and RuneLite versions, settings by section, which ones differ from the defaults, and client environment. null if the plugin has never sent them. Self-reported by the client. Global keys do not receive env.custom_api_endpoint. Not part of `all`, so ask for it by name.
Loot
Section
Cost
Contains
loot
1
Loot value this month and all time. Read from the same place as the leaderboard, so the two can never disagree.
loot_npcs
16
Top NPCs by loot value over the requested window.
loot_items
121
Top items by loot value over the requested window.
Progress
Section
Cost
Contains
stats
1
Experience in all 24 skills, plus the total.
combat_achievements
1
Combat achievement points, the tier they reach, and the next tier with the points still needed and progress towards it. Points refresh every time the player completes a task; tasks completed comes from account sync.
badges
1
Badges the player currently holds.
pets
3
Pets received, with the date each was recorded.
deaths
3
Recorded death count and the most recent one.
quests
4
Quest counts by state: not started, in progress, finished.
clog
8
Collection log progress: slots obtained out of the game's own total, and how many individual slots we hold rows for.
diaries
8
Achievement diary tasks completed, per area and tier.
points
8
Lifetime DropTracker points earned.
personal_bests
8
Best time per boss, split by team-size bracket.
clog_slots
161
Every recorded collection log slot with its quantity — around 1,500 rows per player, so price a page accordingly.
Feed
Section
Cost
Contains
drop_ids
0
Modifier: adds drop_id to every entry of drops — the stable identity you need for exactly-once processing. Free, emits nothing on its own, and does nothing without drops.
drops
50
Individual drops, newest first, inside a bounded window: since / until as unix seconds (default the last 24 hours, at most 7 days) and max_drops rows per player (default 50, at most 200). Every entry carries received_at as unix seconds UTC. Priced per 24 hours of window — a week costs 350. Not part of `all`; ask for it by name.
The shape of clog_slots
Most collection log slots have a quantity of 1, so repeating that for every slot would triple the response for no information. Slots come back as a sorted id array plus a sparse map of the quantities that are not 1:
"clog_slots": {
"items": [995, 1149, 11802, 22981],
"quantities": { "995": 40, "22981": 3 }
}
// 1149 and 11802 are absent from "quantities", so both are 1.
drops — the individual-drop feed
Every other section describes a player's state; drops is a stream of events, so it has its own window (since / until, unix seconds UTC, default the last 24 hours, at most 7 days) and its own price: 50 per player per 24 hours of window, rounded up, so a week costs 350. Rows per player are capped by max_drops, newest first, and the payload says when that cap bit. Every entry carries received_at as unix seconds UTC — when DropTracker accepted the submission, not when the drop happened in game. Add drop_ids when you need the stable drop_id for exactly-once processing.
"drops": {
"from": 1788264000, "to": 1788350400,
"count": 2, "truncated": false, "oldest": 1788300000,
"drops": [
{ "item_id": 4151, "item_name": "Abyssal whip",
"npc_id": 415, "npc_name": "Abyssal Sire",
"quantity": 1, "value_each": 2000000, "total_value": 2000000,
"received_at": 1788343200, "received_at_iso": "2026-09-02T10:00:00",
"drop_id": 203743875 } // only with include=drop_ids
]
}
// truncated: true means more drops than max_drops fell in the window;
// continue with until=<oldest>.
For a poller: ask for drops,drop_ids with since a few minutes before your last successful poll and dedupe on drop_id. The feed is not part of all — ask for it by name.
meta — standing, at no cost
include=meta adds where an entity sits on the boards. It is priced at zero because it is: two batched cache reads for the whole page, with no per-player work. On a player it adds ranks and memberships; on a group request it also attaches the group's own row, which describes the group rather than the page — so it reads the same on page 4 of a roster as on page 1.
On GET /v2/groups each row gains the monthly figures as stats. Two deliberate absences: there is no all-time group rank — monthly group standings are maintained, but deriving an all-time one means summing every group across all history — and all_time_gp is returned for a single group, not on the listing where it would be that work per row. Every figure comes from the same source as the website's leaderboards, so a rank here cannot disagree with a profile page.
Paging a roster
Group listings page by cursor, not by offset — a deep offset makes the database walk and throw away every row it skips, so page 50 would cost fifty pages of work. Pass the next_cursor from each response back as cursor. It is null on the last page.
The response names the section it did not recognise and lists the valid ones.
401
Missing, malformed, unknown, revoked or expired key.
All of those look identical on purpose, so a token cannot be used to probe which keys exist. Check the header format first.
403
A valid key, but not scoped to what you asked for.
Group keys may only read their own group.
404
No such player — or one outside your scope, or hidden.
These are deliberately indistinguishable; otherwise the API would let you enumerate other clans' rosters.
429
A rate-limit budget was exhausted.
`Retry-After` says how long to wait, and the `limit` field names which budget you hit.
503
The query exceeded the server's time limit.
Not a crash — the server gives up cleanly rather than holding the connection. Narrow `days` or ask for fewer sections.
Notes on the data
Loot totals come from the same source as the site's leaderboards, so the two can never disagree.
loot_npcs and loot_items are served from hourly rollups. They aggregate whole hours, so a drop from a few minutes ago may not appear immediately.
Collection log obtained and total come from the game's own counter, which knows about slots we hold no row for. tracked_items is our row count and will usually be lower — that is expected, not a discrepancy.
Timestamps are UTC, ISO-8601.
A collection log slot's first-seen date is when we recorded it, never when the player obtained it.