Valheim
You are viewing a potentially older version of this package. View Latest Version
Install

Details

Date Uploaded
3 weeks ago
Downloads
697
Size
27KB
Dependency string
Proudlock_Technology-GsValheimStatsClient-0.2.11
ADDatHost Valheim hosting
30% off!

GsValheimStatsClient

A client companion that posts your personal Valheim stats to an HTTP endpoint - by default the self-hosted gs dashboard, but it'll post to any URL you point it at, so you can ingest your stats however you like.

Pairs with the server-side GsValheimStatsEmitter. Both POST to the same endpoint; the dashboard merges them.

Ingesting the data into your own dashboard? See the Data format & self-hosting wiki for the complete payload schema, key conventions, and merge rules.


What it tracks

Read from your own game (the things only the client knows), accumulated and persisted across sessions:

  • Profile counters - Valheim's own PlayerProfile stats: kills, deaths, builds, crafts, jumps, distances (walked / run / sailed / air), trees chopped, items picked up, ...
  • Skills - every weapon/utility skill level
  • Per-creature kills - what you're killing and how much
  • Crafts - which items you've crafted (+ counts)
  • Materials gathered - Wood, Stone, ores, ...
  • Weapons - per weapon category: total damage, kills, hardest single hit, biggest total swing (cleave/AoE)
  • Specific weapons - same, per actual item (Bronze Sword vs Iron Sword)
  • Boss damage + DPS - your damage to each boss and your active engagement time (DPS = damage / fightSec), incl. fire/poison damage-over-time credited to whoever applied it
  • Trophies - collected trophies
  • Deaths - cause (incl. felled-by-your-own-tree, Deathsquito), biome, life length, kills before dying
  • Multiplayer-aware - whichever client owns a creature records the damage every player deals to it, so combat totals are exact across a group
  • Boss self-damage - damage a boss takes from the world (lava / its own fire / falls), with no player to blame

Setup

  1. Install via r2modman / Thunderstore (depends on denikson-BepInExPack_Valheim).

  2. Launch the game once to generate the config, then edit BepInEx/config/net.cproudlock.gsvalheimstatsclient.cfg:

    [General]
    World = vhserver3          # must match the server's world name
    EmitIntervalSeconds = 120  # how often it POSTs
    
    [Ingest]
    Url = https://gs.proudtech.net/api/valheim/ingest
    Token = <bearer token from the dashboard owner>
    
  3. Restart Valheim. It POSTs every EmitIntervalSeconds (and on death).

Stats are filed under World, so set it to whatever you want to group your runs by (typically the server's -world name).


Ingesting the stats yourself

The mod just does an authenticated POST of a JSON snapshot. You don't need the gs dashboard - point Url at anything that speaks HTTP.

Request:

  • POST <Url>
  • Authorization: Bearer <Token> (omitted if Token is blank)
  • Content-Type: application/json

Payload (source: "client"):

{
  "schemaVersion": 1,
  "game": "valheim",
  "source": "client",
  "reporter": "Erebus",
  "world": "vhserver3",
  "emittedAtUtc": "2026-06-09T18:00:00Z",
  "snapshotIdLocal": "5e2f...",
  "players": [{
    "name": "Erebus",
    "platformId": "-1285113746",
    "kills": 312, "bossKills": 1, "deaths": 4,
    "longestLifeSec": 7200, "bestKillsBeforeDeath": 150,
    "stats":   { "vh_EnemyKills": 312, "vh_Builds": 540, "vh_DistanceSail": 4200 },
    "skills":  [{ "skill": "Knives", "level": 42 }],
    "creatureKills": [{ "creature": "$enemy_greydwarf", "kills": 140 }],
    "crafts":  [{ "item": "$item_club", "count": 3 }],
    "materials": [{ "material": "Wood", "amount": 3400 }],
    "weapons": [{ "weapon": "Knives", "damageDealt": 493, "kills": 29, "hardestHit": 79, "biggestSwing": 121 }],
    "weaponItems": [{ "item": "$item_knife_bronze", "damageDealt": 400, "kills": 25, "hardestHit": 79 }],
    "boss":    [{ "boss": "Eikthyr", "damageDealt": 1450, "fightSec": 95 }],
    "pickups": [{ "item": "$item_trophy_boar", "count": 11 }]
  }, {
    "name": "Pridetoes",
    "weapons": [{ "weapon": "Bows", "damageDealt": 220, "kills": 3, "hardestHit": 60, "biggestSwing": 60 }],
    "boss":    [{ "boss": "Eikthyr", "damageDealt": 700, "fightSec": 95 }]
  }],
  "deathEvents": [{
    "playerName": "Erebus", "killer": "tree", "biome": "BlackForest",
    "posX": 120, "posY": 30, "posZ": -44, "lifeSec": 1800, "killsThisLife": 40,
    "tsUtc": "2026-06-09T17:30:00Z"
  }],
  "bossSelfDamage": [{ "boss": "Fader", "damage": 210 }]
}

Notes:

  • All counters are cumulative running totals (idempotent - re-posting the same snapshot is safe). snapshotIdLocal lets a receiver dedupe.
  • Creature / craft / item keys are Valheim localization tokens ($enemy_*, $item_*); stats keys are vh_<PlayerStatType>.
  • reporter is who captured this payload. Valheim simulates each creature on the nearest client, so in multiplayer a client also records the combat it witnesses for other players on creatures it owns - those appear as extra, combat-only entries in players[] (just weapons/weaponItems/boss). Source-separate weapon/boss rows by reporter and sum across reporters: each hit is seen by exactly one owner, so it's an exact total with no double-count. Fire/poison damage-over-time is credited to whoever applied it.
  • bossSelfDamage is per-boss damage taken with no player attacker (lava, the boss's own fire, fall) - a curiosity stat, not attributed to anyone.

Minimal receiver (Node):

import express from 'express';
const app = express();
app.use(express.json({ limit: '1mb' }));
app.post('/api/valheim/ingest', (req, res) => {
  if (req.get('authorization') !== 'Bearer my-secret') return res.sendStatus(401);
  for (const p of req.body.players ?? [])
    console.log(`${p.name}: ${p.kills} kills, ${p.deaths} deaths`);
  res.json({ status: 'ok' });
});
app.listen(3001);

Then set Url = http://<host>:3001/api/valheim/ingest and Token = my-secret.

Quick test with curl:

curl -X POST http://localhost:3001/api/valheim/ingest \
  -H 'Authorization: Bearer my-secret' -H 'Content-Type: application/json' \
  -d '{"game":"valheim","source":"client","world":"test","players":[{"name":"You","kills":1}]}'

Privacy: the mod sends your stats to whatever Url you configure. Only install with a Url/Token you trust.

Thunderstore development is made possible with ads. Please consider making an exception to your adblock.