A live, self-hosted map for a Palworld dedicated server — player positions, collectibles, bosses, and world state, almost all read straight from the server's own save files and the game's own assets. A small handful of values that aren't stored anywhere in the game's own data are cross-checked against public wikis instead — see below for exactly which ones.
| Layer | What it tracks | Live per-player state? |
|---|---|---|
| Players | Live position, level, HP, hunger, online/offline (via RCON), last-online time | — |
| Effigies (Relics) | 407 collectible statues, grouped by tier | ✅ per-player collected |
| Alpha Bosses | 90 field-boss spawns, name/species/element | ✅ per-player defeated |
| Bounty | 33 named human NPC bosses (bandit/raider/syndicate leaders) | ✅ per-player defeated |
| Challenge Towers | The 9 "GYM" boss-rush towers | ✅ per-player defeated |
| Oil Rigs | The 3 raid-zone POIs | world-shared (no per-player state exists) |
| Watchtowers / Waypoints | 22 climbable watchtowers + 152 fast-travel points | ✅ per-player unlocked |
| Journals | 64 lore pickups (Castaway's Journal + NPC Diaries) | ✅ per-player read |
| Schematics | 106 blueprint pickups | ✅ per-player collected |
| NPCs | 104 named NPCs (General/Wandering Merchant/Pal Dealer/Black Market/Dog Coin), with a shop-inventory modal (items or capturable Pals, live price/pool where the game exposes one) | — |
| Quests | 87 quests with a map location (28 Main, 59 Sub), split into Active/Not Started | ✅ per-player, shown only once a player is selected |
| Guild Bases | Player-built bases, grouped by guild | live, world-shared |
| Dungeons | Open-world dungeon entrances — only the ones currently spawned/enterable are shown, with a live active / total count and a despawn ETA. Click one for a full contents modal: every Boss/Mid-Boss/Normal/Monster/Fish/Human-Enemy tier, each marked Guaranteed or Random pool (N possible), boss escorts folded into a "w/ Escorts" flag instead of cluttering the grid, real portraits for every enemy including the human factions |
live, world-shared |
| Pal Spawns | Wild-Pal field spawn locations as opt-in highlighted map regions (not a heatmap) — strictly regular wild Pals, never Alpha Bosses/dungeon spawns/human NPCs. Defaults to nothing shown; pick a species and its actual spawn radius lights up, along with a spinning rainbow ring calling out that species' Alpha Boss (if it has one) and any currently-active dungeon it can be found in | ✅ per-player Mimog Effigy capture progress (✓/N-of-5) |
The sidebar groups everything above into five collapsible categories —
Points of Interest, Collectibles, Combat, Quests (only shows content once a
player is picked, since quest progress is inherently per-player), and Pal
Spawns (the one category that stays empty until you actively pick a
species, for the reason above) — and remembers which sections/checkboxes
you had expanded/checked, plus your View As pick, across a page refresh
(localStorage, client-side only — nothing server-side is saved per
visitor).
Selecting a player from View As... filters every checklist to what that
player has actually collected/defeated/unlocked, and pans the map to their
current position — here's Cat, zoomed to her own position, with her own
per-player checkmarks (and Mimog Effigy capture progress) applied across
every relevant section:
Clicking a Dungeon opens its full contents — which tiers are a guaranteed single enemy versus a genuine weighted pool, and a boss's escorts folded into a "w/ Escorts" flag instead of cluttering the grid with duplicate cards:
Pal Spawns is opt-in on purpose — nothing shows until you pick a species (checking everything at once would just highlight the whole map). Selecting one lights up its real spawn radius, plus a spinning rainbow ring calling out that species' Alpha Boss and any dungeon that's currently spawned with it inside:
backend/remote.pypullsLevel.savand every player's.savfrom the dedicated server host over SSH (sudo-scopedrsync/SFTP), on a 30-second refresh loop. This project runs against AMP, but nothing about it actually depends on AMP — seedeploy/README.md/deploy/bare-metal.mdfor pointing it at a barePalServerinstall instead.backend/parse.pydecodes the save files usingdeafdudecomputers/PalworldSaveTools(the PyPIpalworld-save-toolspackage doesn't support the 1.0 release's save format) and extracts everything live: player state, per-player collection/defeat/unlock flags, guild bases, which dungeon entrances currently have a spawned instance, and — as of Pal Spawns — each species' lifetime capture count (PalCaptureCount), which is what actually determines Mimog Effigy progress.extractor/PalExtractis a one-off C# console app (CUE4Parse) that reads the static data (positions, names, icons, element types, map textures, and — for Dungeon Contents/Pal Spawns — full enemy rosters joined from the game's own spawner/loot tables) directly out of the game's own.uasset/World Partition files. This runs once per game patch on a Windows box with the game installed, not at request time — its output is baked into the Docker image asdata/*_static.json+frontend/assets/.backend/server.pyis a Flask app that serves the static + live data as JSON (/api/players,/api/relics,/api/dungeons,/api/dungeon_contents,/api/pal_spawn_locations, etc.).frontend/index.htmlis a single-page Leaflet (CRS.Simple) map, rendered against the game's own map texture, polling those endpoints — no build step, no framework.
Nothing here is guessed: every mechanic (effigy collection flags, boss kill-tracking keys, dungeon active-state, coordinate transforms, etc.) was reverse-engineered directly from a real save file or the game's own data tables, with dead ends recorded so they don't get re-attempted. A short list of values simply don't exist anywhere in the game's own files, and for those we cross-check public wikis instead:
- Elemental type-effectiveness chart — baked into UI Blueprint logic
(
WBP_MainMenu_Pal_ElementMatchup), not aDataTable, so it can't be extracted. Sourced from the publicly documented chart, cross-checked against game8.co and dexerto.com for agreement, then sanity-checked against a real Pal's known matchups. - Challenge Tower HUD coordinates and recommended levels — no data-mined "recommended level" or reliable overworld position exists for towers in the game's own tables. Sourced from real in-game HUD coordinates read off the map, independently cross-checked against palworld.fandom.com's Tower page for agreement.
- Wandering Merchant / Pal Dealer positions, and real quest display
names — these NPCs are wild-spawns with no placement data anywhere in
the game's own files (confirmed dead end after an exhaustive search), and
QuestTitleMsgIddoesn't resolve through any shipped DataTable or StringTable either. Both are sourced from palpedia.ru, a data-mined community Palworld database, spot-checked against real in-game reports before trusting it for the rest.
The full investigation log — including how each of these was verified, and
a wiki-sourced typo that was caught and corrected along the way — lives in
NOTES.md.
| Backend | Python 3.13, Flask |
| Save parsing | palsav-flex / palooz (Oodle decompression) |
| Frontend | Leaflet.js, vanilla JS, no build step |
| Extractor | C#, .NET, CUE4Parse |
| Deployment | Docker/Portainer (git-repository stack), or bare Linux (systemd) |
This project reads almost all of its data directly from the game itself rather than scraping a wiki (see "How it works" above for the handful of wiki-sourced exceptions), which wouldn't be possible without these open-source projects:
- deafdudecomputers/PalworldSaveTools
— save file decoding (
palsav-flex,palooz), including Oodle/PlMdecompression for the 1.0 game release. Does all the heavy lifting behind every "live" layer on the map. - FabianFG/CUE4Parse +
CUE4Parse-Conversion
— reads Unreal Engine assets (
.uasset/World Partition/DataTables) directly, poweringextractor/PalExtract's extraction of every static position, name, icon, and map texture. - SixLabors.ImageSharp — image resizing for the extracted icon set (a CUE4Parse-Conversion dependency, used directly for downscaling Journal icons).
- PalworldModding/UsefulFiles — actively-maintained CUE4Parse mapping files for the current game version.
- palworldlol/palworld-coord
— the in-game-HUD-coordinate conversion formula used to validate several
extracted positions (see
NOTES.md). - Leaflet — the map renderer this whole frontend is built on.
This is the Windows dev-box flow (uses the Bitvise SSH Client for the
save-file pull — see backend/remote.py). For Linux, including a bare
LXC/VM with no Docker, use deploy/bare-metal.md
instead — the
setup differs enough (OpenSSH key provisioning, an env var with no default
outside a container, a Python import gotcha in how you invoke server.py)
that it's not just a pip install away.
cd backend
python -m venv ../.venv
../.venv/Scripts/pip install -r requirements.txt
cp secrets.py.example secrets.py
# edit secrets.py and fill in RCON_PASSWORD / AMP_HOST / AMP_USER /
# AMP_SAVE_ROOT / AMP_WORLD_GUID (or set them as env vars instead --
# those take priority if both are set)
python server.py
Then open http://localhost:5151.
Whichever platform you're on, always run server.py directly as a
script (python server.py / python backend/server.py), never as a
module (python -m backend.server) or via a WSGI target
(backend.server:app). The config loader (backend/config.py) resolves
backend/secrets.py via a plain import secrets — that only finds this
project's file if backend/ is the directory Python was launched from
(true for python server.py/python backend/server.py, false for -m
invocation). Get it wrong and Python silently imports its own standard
library secrets module instead, which has no RCON_PASSWORD attribute —
producing a "not set" error that looks like a missing-config problem, not
an import-shadowing one.
Two supported paths:
- Docker/Portainer — see
deploy/README.md(required env vars, SSH key provisioning, and gotchas from the first real deploy). - Bare Linux LXC/VM, no Docker — see
deploy/bare-metal.md(same config, plus the container-only defaults and import gotchas above that don't apply once there's no container around it).
backend/ Flask app, save-file parsing, live refresh loop
frontend/ Leaflet map (index.html + assets/)
extractor/PalExtract One-off CUE4Parse extractor for static game data
data/ Static extracted JSON (+ gitignored live-refreshed data)
deploy/ Docker/Portainer + bare-metal deployment docs and config
docs/ README screenshots
NOTES.md Full reverse-engineering investigation log






