Scraping it

yaml
scrape_configs:
  - job_name: vintagestory
    static_configs:
      - targets: ["127.0.0.1:9464"]

GET /metrics returns the exposition text; every other path returns 404.

A ready-to-run Prometheus and Grafana pair lives in contrib/grafana; Prometheus alerting rules calibrated to these thresholds live in contrib/alerts.

For panel authors #

The exposition text is the contract: game panels can read /metrics directly instead of going through Prometheus, which is how the first panel integration was built. Three things to know. Each server instance runs its own Pulse on its own port, so a shared machine has one endpoint per instance. The loopback bind covers a panel running on the same host; scraping from another machine goes through a reverse proxy or a deliberate Bind change, as below. Any polling cadence works, the endpoint is cheap to hit; existing metric families keep their names and shapes, and anything breaking would be called out loudly in the changelog first.

A word on the bind address #

The default binds loopback, which means only something running on the same host can scrape it. That default is deliberate. A Vintage Story server is usually a public host, and the metrics endpoint has no authentication of any kind, so widening Bind to 0.0.0.0 publishes your player count and tick health to whoever asks. Anyone who can reach the port can also occupy its (small, fixed) number of connection slots and blind your own scraper behind them, so a Bind beyond loopback wants a firewall rule limiting the port to the scraper. Changing Bind is a choice you should make on purpose, not a default you inherit.

If you need to scrape from elsewhere, the safest options leave Bind on loopback: tunnel to it, or put a reverse proxy in front of it that only your scraper can reach. If you widen Bind instead, add the firewall rule above.

Bind is a plain socket address, not a URL prefix. 0.0.0.0 binds every IPv4 interface, and localhost binds the IPv4 loopback directly, so both localhost and 127.0.0.1 reach it, whichever one a client's own name resolution tries first. All of this behaves the same on Windows, Linux and macOS, and none of it needs administrator rights or a netsh URL reservation on Windows. Binding 0.0.0.0 there can still prompt Windows Firewall to ask whether to allow access, or be blocked outright by a service's default inbound rules; loopback never asks, since nothing outside the machine is trying to reach it.

If the port is already taken, Pulse logs an error and carries on without the endpoint. The game server keeps running; you get no metrics until you fix the config.

Source: README.md