Lightweight Node.js server browser for Counter-Strike community servers. The app fetches server candidates from Steam, enriches them with live query metadata, and serves a browser UI for fast filtering and joining.
- Community admins who want a small, self-hosted server browser.
- Players looking for curated servers with cleaner live status than raw listings.
- Maintainers who want a practical Express app without framework bloat.
- Modular structure (
config,routes,services,utils). - Refresh orchestration with bounded concurrency (
WORKER_CONCURRENCY). - Stale-cache protection via freshness state and
/healthdegradation logic. - Graceful shutdown with optional wait for active refresh completion.
- Snapshot restore/persist support (optional file-based cache).
- Manual refresh endpoint with optional token protection.
- Ping (when available from live query).
- Player count source (
gamedig_livevssteam_fallback). - Server stability fields (
missedRefreshCount,stabilityState,lastSeenAt,lastRefreshAt). - Player-list normalization with explicit
playerListStatushandling.
- Clean default list focused on readability.
- Advanced view toggle for technical columns/metadata.
- Expandable per-server details for deeper diagnostics.
- Favorites (local storage).
- Auto-refresh controls and countdown.
- Improved connect/copy flows.
- Safer rendering/escaping patterns.
- Desktop-friendly country flag assets + favicon.
The default/collapsed main list is intentionally lightweight.
- Keep it clean and readable.
- Do not add technical/diagnostic/heuristic noise to the collapsed list.
- Experimental metadata and heuristics belong only in advanced view or expanded details.
This policy applies to future features as well.
- Node.js 18+ (recommended)
- Steam Web API key
npm installcp .env.example .envSet at least:
STEAM_API_KEY(required)
Commonly adjusted values:
TARGET_MAP,ALLOWED_COUNTRIES,MIN_SLOTS,MAX_SLOTSREFRESH_INTERVAL_MS,WORKER_CONCURRENCY,MAX_STALE_MSSNAPSHOT_CACHE_FILE,RESTORE_SNAPSHOT_ON_STARTUP,PERSIST_SNAPSHOT_ON_REFRESH
npm startDevelopment watch mode:
npm run devOpen:
- UI:
http://localhost:3000 - API snapshot:
http://localhost:3000/api/servers - Health:
http://localhost:3000/health
- Fetch candidate servers from Steam API.
- Filter by slot limits and dedupe by server address.
- GeoIP filter by allowed countries.
- Query live metadata with bounded concurrency (GameDig).
- Merge with previous cache to preserve recently-missed servers for a grace window.
- Compute freshness/stability metadata and expose current snapshot.
- Optionally persist snapshot to disk.
- Advanced view: opt-in technical visibility while keeping default list tidy.
- Expanded details: deeper per-server context (status fields, player-list details, metadata).
Use these surfaces for diagnostics, not the default collapsed list.
- Live server data can be incomplete or inconsistent between refreshes.
- Player list availability depends on per-server query behavior; some servers won’t return a list.
- Ping and metadata can fluctuate quickly.
- Some values are sourced from Steam fallback when live query data is unavailable.
A future implementation is possible, but should be treated as heuristic, not guaranteed truth.
Potential signals to combine:
- Tags/keywords (if available from upstream query data).
- Server name patterns.
- Map naming conventions (custom map patterns vs stock maps).
- Useful rules metadata when present.
Proposed output classes:
likely_cleanprobably_moddedunknown
Caveat:
- Skin/knife/plugin usage often cannot be determined with certainty from standard query data alone.
Critical placement rule if implemented:
- Show this classification only in advanced view or expanded details.
- Never show it in the default collapsed main list.