Skip to content
everloot
Get the addon

Drop rates to a spreadsheet

Page through corroborated drop rates and save them as CSV.

Prerequisites#

  • Node 18 or newer, or Python 3 with only its standard library. Nothing to install.
  • A spreadsheet that opens CSV files: Excel, Google Sheets, LibreOffice or Numbers.
  • No account. Without a key, this endpoint allows 30 requests an hour for each IP address and up to 500 rows a page. Limits and keys explains the free key that raises both.

Steps#

  1. Read one page

    A page of GET /api/rollups/drops has the rates, the credit line and a next link. A rate is public once three installs looted its source. Trimmed, with placeholder values:

    One page
    {
      "rates": [
        { "sourceNpcId": 100, "itemId": 900, "kills": 40, "drops": 4, "rate": 0.1, "reporters": 3, "public": true }
      ],
      "measuredZeros": [],
      "offset": 0,
      "limit": 500,
      "total": 1,
      "totalRates": 1,
      "next": null,
      "attribution": { "credit": "Data from Everloot (https://everloot.app), CC BY-SA 4.0.", "…": "…" }
    }

    kills counts loot windows players opened on the source, not kills counted by the game. A rate has either sourceNpcId or sourceObjectId. rate is a fraction from 0 to 1.

  2. Follow next until it is null

    Ask for 500 rows at a time. While next holds an address, fetch it. When it is null, you have everything. The scripts do that, then write the CSV and a second file with the credit line.

    drops
    // Every corroborated drop rate, saved as drops.csv. Run: node drops.mjs
    import { writeFile } from "node:fs/promises";
    
    const die = (message) => {
      console.error(message);
      process.exit(1);
    };
    const BASE = "https://everloot.app";
    let url = `${BASE}/api/rollups/drops?limit=500`;
    const rates = [];
    let credit = "";
    
    while (url) {
      const res = await fetch(url);
      const page = await res.json();
      if (res.status === 429) die(`Rate limited. Try again in ${res.headers.get("retry-after")} seconds.`);
      if (!res.ok) die(`${res.status}: ${page.error ?? "request failed"}`);
      if (page.unreachable) die("Storage could not be read; the empty list is not a zero. Try again later.");
      rates.push(...page.rates);
      credit = page.attribution.credit;
      url = page.next ? new URL(page.next, BASE).href : null; // null on the last page
    }
    
    const header = ["source_type", "source_id", "item_id", "kills", "drops", "rate", "reporters"];
    const lines = rates.map((r) => [
      r.sourceNpcId ? "npc" : "object",
      r.sourceNpcId ?? r.sourceObjectId,
      r.itemId, r.kills, r.drops, r.rate, r.reporters,
    ].join(","));
    
    await writeFile("drops.csv", [header.join(","), ...lines].join("\n") + "\n");
    await writeFile("drops-credit.txt", credit + "\n");
    console.log(`Wrote ${rates.length} drop rates to drops.csv`);
    console.log(credit);

    The same endpoint also lists measuredZeros: sources players looted with nothing in their windows. The scripts leave them out. If the storage cannot be read, the answer says so, and the scripts stop instead of writing an empty file that looks like a result.

  3. Run it

    Run
    node drops.mjs

    Today it prints this, and drops.csv holds only the header row:

    Output
    Wrote 0 drop rates to drops.csv
    Data from Everloot (https://everloot.app), CC BY-SA 4.0.

    Once rates exist, each one is a row. Placeholder rows:

    drops.csv
    source_type,source_id,item_id,kills,drops,rate,reporters
    npc,100,900,40,4,0.1,3
    npc,101,901,41,5,0.12195121951219512,3
  4. Open it in a spreadsheet

    Open drops.csv in Excel, LibreOffice or Numbers, or in Google Sheets with File, Import, Upload. Format the rate column as a percentage. Then sort by kills to see the best-measured rates first.

  5. Add the credit line

    The data is CC BY-SA 4.0 and has to be credited. Open drops-credit.txt and paste its line under the table, or into the sheet's header. It is the CREDIT_LINE from @everloot/protocol, and the endpoint sends it in attribution.credit and in the X-Everloot-Credit header. If you publish the sheet or anything built from it, keep the line with it. Licence and credit has the full terms.

Check your work#

  • The script prints how many rates it wrote and the credit line. The row count in the spreadsheet is that number plus the header row.
  • Every rate is between 0 and 1,.
  • drops-credit.txt holds one line starting with "Data from Everloot".
  • A 429 stops the script with Rate limited. Try again in N seconds. N is the Retry-After header. Wait that long, or use a free key.
  • A file with only the header row is a real answer today. It means no source has three installs behind it yet, not that nothing drops.

You can also ask for a smaller page with ?offset=0&limit=100. A limit above your page size is capped, and next still leads on.

Next steps#