How to show live FiveM server status on your website

Player count, online state and the connected player list, pulled from your own server and rendered on your site. The two ways to do it, the caching you need, and why the obvious approach breaks in production.

Last updated

A player count on your homepage does one job: it proves the server is alive. A community site without one is asking a visitor to take your word for it, and a visitor who has been burned by a dead server before will not.

There are two ways to get that number, they fail differently, and the one that looks simpler is the one that breaks.

The two sources

Through Cfx.re, keyed by your join code. Cfx.re runs the infrastructure that backs the server browser, and it exposes per-server data addressed by the six-character code in cfx.re/join/xxxxxx. You ask a fixed Cfx.re host for one server, and you get back a hostname, a player list and a slot count.

Directly from your own server. An FXServer answers three JSON endpoints on its own port: /info.json for configuration including sv_maxclients, /players.json for the connected player list, and /dynamic.json for the current and maximum counts. No third party involved.

The direct route looks better on paper. It has no dependency on anyone else and it is always current. In practice it has three problems that the Cfx.re route does not.

Why the direct route usually loses

It exposes your server's address. To query http://your.host:30120/dynamic.json from a browser, that address has to be in your page. You have just published the thing the join code existed to hide.

It is plain HTTP. Your site is on HTTPS. A browser will refuse to make an insecure request from a secure page, so the call has to happen on your server rather than in the visitor's browser, which means you need a backend. If you were planning a static site, you no longer have one.

sv_requestParanoia can switch it off. This is the one that catches people. It is a server convar that restricts who may call those endpoints, and it is not unusual for it to be set, either deliberately or by a framework's default config. When it is, your widget gets nothing and the cause is invisible from the outside.

Use the direct route when the request is already server-side, you control the convar, and you specifically want data Cfx.re does not carry. Otherwise use the join code.

The shape of a working lookup

Whichever source you use, the same four things decide whether it works in production.

Ask once, not once per visitor. The single most common mistake. A page that fetches on every request turns a hundred concurrent readers into a hundred upstream calls, and you will be rate-limited for it. Cache the answer for thirty to sixty seconds. A player count that is a minute stale is indistinguishable from a live one to a human being, and the difference to your upstream is a hundredfold.

Time out fast, and have an answer ready. An upstream that hangs must not hang your page with it. Eight seconds is a generous ceiling from a datacenter. Past that, render the last known value or an honest "status unavailable", never a spinner that spins forever.

Treat a stale record as offline. This one is subtle. A server that has stopped is not removed from the list immediately, it just stops being updated. If you render whatever the API last said, a server that died an hour ago still shows nine players online, which is worse than showing nothing. Check the last-seen timestamp and treat anything older than about ten minutes as offline.

Distinguish empty from offline. Zero players on a running server and a server that is not running are different facts and your visitors read them completely differently. "0/64 online" says quiet evening. "Offline" says do not bother downloading this. Do not render the first when you mean the second.

Rendering it so it means something

The number is not the point. What a visitor does next is the point.

  • Put it next to the join button, not in a stats strip at the bottom. The count exists to make the button feel worth pressing.
  • Show the slot count too. "24 players" is ambiguous. "24/64" says there is room, and "62/64" says hurry.
  • Consider the player list. FiveM will give you connected player names. On a roleplay server that is unusually persuasive, because a visitor recognizes names from clips, and it is also a privacy decision your community should make deliberately rather than by default.
  • Do not animate a count that is cached. A number ticking up every second while the underlying value refreshes once a minute is theatre, and people notice.

Doing it without a backend

If your site is static, you have three options, in order of how well they age.

A small serverless function. One endpoint on your own domain that does the lookup, caches it, and returns JSON. Your page calls that. Every static host worth using offers this, and it keeps your join code and your caching policy in one place you control.

A third-party status widget. Fastest to ship, and you are now rendering someone else's iframe on your homepage, with their uptime and their tracking. Fine for a stopgap.

Build-time only. Fetch at deploy and bake the number in. This is worse than nothing. A hardcoded "47 players online" that never changes is actively dishonest, and visitors who return twice will notice.

If it says offline and the server is not

Work through it in this order.

  1. Check the code, not the server. Strip whitespace, strip any cfx.re/join/ prefix, confirm the case. Most failures are here.
  2. Confirm the server registered with Cfx.re. If it does not appear in the server browser at all, no lookup keyed by a join code can find it.
  3. If you are querying directly, check sv_requestParanoia. It is the most likely single cause of a direct lookup returning nothing while everything else looks healthy.
  4. Check where the request came from. A lookup that works from your laptop and fails from your deployed site is a datacenter-versus-residential difference, not a code difference.
  5. Check your own cache. If you cached an offline result for an hour, you will keep seeing it for an hour.

On this template

RPWebsite ships this as configuration. Set your join code and the status, the player count, the player list and the join button all read from it, with the caching and the staleness check already in place. There is a FiveM server resource included for the case where you want the direct route, and switching between them is a config value rather than a rewrite.

from $99

One-time · full source code

Get it now