Wszystkie endpointy odczytu zwracają JSON i są dostępne bez klucza,
bez logowania i bez rejestracji. Adres bazowy to ta sama domena, na której
czytasz tę stronę.
Endpointy odczytu wysyłają nagłówek Access-Control-Allow-Origin: *,
więc możesz z nich korzystać przez fetch() bezpośrednio
z przeglądarki, z dowolnej domeny. Endpointy zapisu (dodawanie i usuwanie
serwera z listy) tego nagłówka nie mają — celowo.
Zanim na tym zbudujesz
To projekt hobbystyczny, nie usługa komercyjna. Nie ma żadnego SLA:
serwis może zniknąć, zmienić kształt odpowiedzi albo przestać działać bez
zapowiedzi i bez okresu przejściowego. Dane pochodzą z publicznego API FiveM
i są tak dobre jak ono. Jeśli budujesz coś, na czym Ci zależy — trzymaj
własny cache i przewiduj, że tego API pewnego dnia nie będzie.
Dashboard
GET/api/stats
Aktualny stan wszystkich śledzonych serwerów plus suma zbiorcza.
Dane pochodzą z pamięci podręcznej odświeżanej co POLL_INTERVAL_MS
(domyślnie 20 s), więc odpytywanie częściej niż co 20 s nic nie wnosi.
Przykładowe żądanie
curl https://stats.bykens.eu/api/stats
Przykładowa odpowiedź (skrócona do jednego serwera)
{
"servers": [
{
"code": "okz5dj",
"label": "Intouch.gg",
"hostname": "INTOUCH",
"banner": "https://cdn-intouch.realmgaming.eu/baner.png",
"players": 121,
"max": 230,
"queue": 2,
"upvotes": 0,
"framework": "ESX",
"resourceCount": 412,
"updatedAt": "2026-09-14T11:29:10.380Z",
"trend": { "players": "flat", "queue": "flat" },
"peakToday": { "players": 121, "queue": 2 },
"uptime": {
"day": { "percent": 100, "checks": 288 },
"week": { "percent": 99.4, "checks": 2016 }
},
"health": {
"grade": "A",
"powody": [],
"decyduje": "uptime",
"uptime": { "znany": true, "powod": null, "percent": 99.4, "checks": 2016, "hours": 168, "band": "ponad-99" },
"wskaznik": { "znany": true, "powod": null, "status": "brak-wzorca", "rodzinyPotwierdzone": [], "rodzinyObserwowane": [], "observations": 41 }
}
}
],
"totals": { "players": 246, "max": 931, "queue": 2 },
"generatedAt": "2026-09-14T11:29:21.793Z"
}
Pola warte uwagi
| Pole | Znaczenie |
| trend | up / down / flat — kierunek zmian z ostatnich ~2,5 min, z martwą strefą, żeby nie migał przy szumie |
| uptime.*.percent | Procent udanych odczytów w oknie. null znaczy „za mało danych", co jest czymś innym niż 0 |
| framework | Rozpoznany framework (ESX, QBCore, Qbox, vRP) albo null, gdy żaden marker nie pasuje. Te same reguły co na liście serwerów |
| resourceCount | Liczba resource'ów zgłoszona przez serwer. null, gdy serwer nie udostępnia ich listy |
| error | Obecne tylko gdy serwer nie odpowiada. Wtedy brak players, trend i peakToday |
| health.grade | Ocena zdrowia: A / B / C albo null. A — uptime 7 dni powyżej 99% i żadna rodzina obserwacji licznika nie jest potwierdzona. B — uptime od 95% do 99% i to samo o obserwacjach. C — uptime poniżej 95% albo jakakolwiek rodzina potwierdzona |
| health.powody | Puste przy ocenie. Gdy grade jest null, wymienia czego brakuje: uptime-brak-odczytow, uptime-za-krotkie-okno (okno krótsze niż doba), wskaznik-bez-rozstrzygniecia. Litera zgadnięta z połowy przesłanek wyglądałaby jak policzona, więc jej nie ma |
| health.decyduje | Co dało tę literę: uptime, wskaznik albo oba. null, gdy oceny nie ma |
| health.uptime / health.wskaznik | Uzasadnienie, zawsze obecne — także wtedy, gdy litery nie ma. Obie liczby, długość okna uptime w godzinach (hours), status wskaźnika i lista potwierdzonych rodzin |
| health.wskaznik.rodzinyObserwowane | Rodziny widziane w oknie, także te jeszcze niepotwierdzone. Do oceny nie wchodzą — litera stoi wyłącznie na rodzinyPotwierdzone. Są po to, żeby dało się napisać „widzimy coś, ale to się jeszcze nie utrzymuje" zamiast milczeć tak samo jak przy pustym oknie. Pusta lista, gdy znany jest false |
Czego ocena nie mówi: czy serwer jest dobry, uczciwy albo wart grania. uptime to nasza widoczność serwera — przerwa po naszej stronie wygląda tak samo jak awaria serwera. wskaznik opisuje nasze pomiary licznika graczy, nie zachowanie administracji.
Limity: brak rate limitu. Dane odświeżane co ~20 s.
GET/api/kronika
Trwała oś czasu zdarzeń: awaria, powrót, rekord dnia, prawie pełny.
Okno 90 dni, najnowsze pierwsze. To samo, co pokazuje strona
Historia.
Parametry
| Parametr | Znaczenie |
| code | Kod cfx.re jednego serwera. Bez parametru — wszystkie |
| type | online, offline, full, record-players, record-queue |
| limit | Ile wpisów na stronę (domyślnie 50, najwyżej 500) |
| offset | Ile pominąć, licząc od najnowszego |
{
"wpisy": [
{ "id": 812, "at": "2026-09-18T09:14:02.118Z", "type": "offline", "code": "lerb6bv", "label": "Intouch.gg", "value": null }
],
"razem": 137,
"offset": 0,
"limit": 50,
"przeglad": {
"serwery": [{ "code": "lerb6bv", "label": "Intouch.gg", "ile": 41 }],
"typy": [{ "type": "offline", "ile": 22 }],
"razem": 137,
"najstarszy": "2026-06-21T18:02:11.004Z",
"oknoDni": 90,
"sufit": 10000
}
}
Różnica wobec /api/events: tamto oddaje ostatnie ~20 zdarzeń z pamięci procesu i pustoszeje przy restarcie usługi — to jest pasek „co się właśnie dzieje”. Kronika idzie z dysku i restart przeżywa.
Limity: brak rate limitu. Okno 90 dni i sufit 10 000 wpisów; starsze odpadają przy zapisie.
GET/api/history
Historia sumy wszystkich serwerów — próbka co HISTORY_INTERVAL_MS
(domyślnie 5 min), maksymalnie 288 próbek, czyli pełne 24 h.
Z parametrem ?code= zwraca historię jednego serwera
(samą tablicę, bez intervalMs).
Przykładowe żądania
curl https://stats.bykens.eu/api/history
curl https://stats.bykens.eu/api/history?code=okz5dj
Przykładowa odpowiedź (bez parametru)
{
"totals": [
{ "timestamp": "2026-09-14T11:29:10.381Z", "players": 246, "max": 931, "queue": 2 }
],
"intervalMs": 300000
}
| Parametr | Znaczenie |
| code | Kod serwera z /api/stats. Nieznany kod → 404 z {"error": "Nieznany kod serwera"} |
Limity: brak rate limitu. Historia obejmuje maksymalnie ostatnie 24 h i nie przetrwa dłużej — starsze próbki są nadpisywane.
GET/api/hourly
Heatmapa godzin szczytu: 168 komórek (7 dni tygodnia × 24 godziny) ze
średnią liczbą graczy i kolejki. Narasta przez cały czas życia serwisu,
więc im dłużej chodzi, tym wiarygodniejsza. Komórki bez próbek zwracają
null, a nie zero — to celowe rozróżnienie „brak danych"
od „zero graczy".
Przykładowe żądanie
curl https://stats.bykens.eu/api/hourly
Przykładowa odpowiedź (2 z 168 komórek)
{
"cells": [
{ "day": 0, "hour": 0, "players": null, "queue": null, "samples": 0 },
{ "day": 1, "hour": 13, "players": 246, "queue": 2, "samples": 12 }
],
"days": 1,
"since": "2026-09-14",
"intervalMs": 300000
}
| Pole | Znaczenie |
| day | Dzień tygodnia, 0 = niedziela (jak w JavaScriptowym getDay()) |
| samples | Liczba próbek uśrednionych w tej komórce. Przy 1 próbce liczba jest praktycznie bez wartości |
| days | Z ilu różnych dni w ogóle zebrano dane |
Limity: brak rate limitu.
GET/api/events
Ostatnie ~20 zdarzeń (serwer padł, wrócił, zapełnił się, pobił rekord),
najnowsze pierwsze. Żyją wyłącznie w pamięci — restart usługi czyści
listę i tak ma być: to podgląd ostatnich minut, nie dziennik zdarzeń.
Przykładowe żądanie
curl https://stats.bykens.eu/api/events
Przykładowa odpowiedź
{
"events": [
{ "id": 7, "at": "2026-09-14T11:31:02.118Z", "type": "record",
"code": "okz5dj", "label": "Intouch.gg", "value": 231 }
]
}
Limity: brak rate limitu. Zaraz po restarcie usługi lista bywa pusta ({"events": []}) — to nie błąd.
Lista serwerów
GET/api/lookup/servers
Wszystkie serwery dodane przez odwiedzających, z kompletem danych
wyciągniętych z API FiveM. Czyta wyłącznie z pamięci podręcznej —
Twoje żądanie nigdy nie wywoła zapytania do cfx.
Przykładowe żądanie
curl https://stats.bykens.eu/api/lookup/servers
Przykładowa odpowiedź (skrócona)
{
"servers": [
{
"code": "yokb5k",
"hostname": "Realm Roleplay | WL-OFF",
"projectName": "RealmRP", "projectDesc": "Polski serwer roleplay",
"players": 50, "max": 500, "queue": 0, "peakPlayers": 297,
"framework": null, "resourceCount": 324,
"locale": "pl-PL", "tags": ["roleplay", "wl-off"],
"gameName": null, "whitelist": false, "whitelistInfo": null,
"oneSync": "on", "gameBuild": "3570", "scriptHook": false,
"pureLevel": null,
"discord": "https://dc.realmrp.pl", "store": "https://sklep.realmrp.pl",
"playerNames": { "total": 226, "anonymized": true },
"endpoints": ["https://30123-spillway.example.eu/"],
"endpointsHidden": false, "private": false,
"online": true, "error": null,
"joinUrl": "https://cfx.re/join/yokb5k"
}
],
"count": 1,
"limit": 300,
"batchMax": 10,
"intervalMs": 60000,
"clientRefreshMs": 15000
}
| Pole | Znaczenie |
| online | false = serwer nie odpowiada, ale wpis zostaje z ostatnimi znanymi danymi. null = jeszcze nie sprawdzony |
| endpointsHidden | true gdy serwer ukrywa swój bezpośredni adres |
| counters |
Pełny opis dwóch liczników z odpowiedzi cfx — zawsze obecny, także gdy się zgadzają
(state: brak-pola, nieprawidlowa-wartosc,
zgodne, rozbieznosc). „Sprawdzone i zgodne" to inna informacja
niż „nie sprawdzono", a reported: 0 to pomiar, nie brak pomiaru.
direction mówi, w którą stronę: zawyzanie (serwer zgłasza
więcej — zwykle gracze na ekranie ładowania) albo zanizanie.
percent jest liczony względem liczby cfx (percentOf);
przy clients = 0 jest null, bo mianownik jest zerem
|
| selfReported | Pole zgodnościowe dla starszej strony: null
albo trzy liczby, obecne tylko przy rozbieżności. Nowy kod czyta counters |
| health |
Ocena zdrowia — ta sama, co w /api/stats, na karcie serwera
i na odznace: jeden moduł, jedne progi. grade to
A / B / C albo null
z listą powody, a uptime i wskaznik
niosą uzasadnienie także wtedy, gdy litery nie ma. Pełny opis reguły —
przy /api/stats wyżej
|
| activityReport |
Raport wskaźnika licznika graczy. Zawsze obecny dla serwera online — także wtedy,
gdy nic się nie zapaliło, bo „sprawdziliśmy i nic" to inna odpowiedź niż „nie było
czego sprawdzić".
status: brak-danych / za-malo-danych /
nieaktualne / swiezosc-nieznana / brak-wzorca /
obserwacje.
level: brak / informacja (jedna rodzina
obserwacji) / wzorzec (dwie różne, potwierdzone rodziny przy pełnej
jakości danych).
families: malaZmiennosc (sygnały lowCv
i stall — dwa opisy tego samego zjawiska, liczą się jako jedna
przesłanka) i rozjazdLicznikow (countersDiffer).
familyDependence: obecne tylko przy co najmniej dwóch rodzinach
potwierdzonych na pełnej jakości własnych danych — pary tych rodzin
z zadeklarowaną zależnością: nieznana (niezmierzona, dziś jedyny stan),
zalezne (występują razem częściej niż przypadkiem — para nie daje
wzorzec) albo niezalezne-w-probie, z podstawą w
basis.
quality: liczba różnych obserwacji źródłowych, rozpiętość okna,
największa luka, świeżość (swieze / nieaktualne /
nieznana) i sourceRepeats — ile naszych odczytów oddało
tę samą obserwację.
dataQuality: jakość danych w wersji zwięzłej —
basis, grade (pelna / ograniczona /
niewystarczajaca), limits (wszystkie powody obniżenia oceny,
nie pierwszy), coveragePercent, largestGapMinutes,
sourceAgeSeconds. Ten sam opis ma każdy sygnał w signals,
z własnym basis: lowCv i stall stoją na oknie
obserwacji (okno-obserwacji), a countersDiffer na
pojedynczym odczycie (pojedynczy-odczyt) — dwie liczby z jednej
odpowiedzi okna nie potrzebują. Pełna wersja jest w /api/serwer.
Pole niczego nie bramkuje: o tym, co się zapala, decydują te same warunki co bez niego.
To opis pomiarów licznika, nie ocena serwera. Liczone wyłącznie z liczb na
poziomie serwera, bez żadnych danych o pojedynczych graczach. Bufor obserwacji żyje
w pamięci, więc po restarcie usługi status to brak-danych.
Progi są ustawieniami początkowymi i wymagają walidacji
|
| activityPattern | Pole zgodnościowe dla starszej strony:
null poza poziomem wzorzec. Nowy kod czyta
activityReport |
| projectName | Nazwa, którą serwer nadaje sobie sam (sv_projectName). null, gdy pokrywa się z hostname |
| projectDesc | Opis własnymi słowami serwera, obcięty do 400 znaków |
| peakPlayers | Rekord graczy zgłoszony przez sam serwer — cfx nie dokumentuje, z jakiego okna. null, gdy serwer go nie podał albo gdy jest niższy od bieżącej liczby graczy |
| gameName | null = GTA V (stan domyślny). "rdr3" = to serwer RedM, nie FiveM |
| whitelist | true/false z sv_appearAllowlisted, null gdy serwer nic nie podał |
| whitelistInfo | Instrukcja dołączenia (sv_allowlistInstructions), obcięta do 200 znaków |
| pureLevel | Poziom pure mode, gdy większy od zera. null = stan domyślny |
| playerNames | Sam fakt, czy serwer anonimizuje swoją listę graczy: anonymized to true, false albo null (nie da się rozstrzygnąć). Nicków ten endpoint nie zwraca i zwracać nie będzie |
| extraVars | Surowy zrzut zmiennych serwera, których nie mapujemy jawnie |
| clientRefreshMs | Jak często warto odpytywać. Backend odświeża dane co intervalMs, ale rozkłada zapytania po kolei |
| batchMax | Ile kodów wolno wrzucić w jednym zgłoszeniu do /api/lookup/add-many |
Limity: brak rate limitu na odczyt. Lista mieści maksymalnie 300 serwerów. Przy pełnej liście odpowiedź waży około 0,6 MB.
GET/api/serwer?server=KOD
Jeden serwer, pełne rozliczenie wskaźnika licznika graczy — to,
co pokazuje strona /serwer?server=KOD, otwierana kliknięciem w nazwę
serwera na dashboardzie albo na liście. Jedyne miejsce, w którym
obie ścieżki wskaźnika spotykają się w jednej odpowiedzi
(activityReport z bieżących odczytów i patternReport
z dobowych rollupów), i jedyne, które oddaje pomiary bez progów.
Dlaczego osobno od /api/lookup/servers: ten endpoint
oddaje współczynnik zmienności i długość zastoju także wtedy, gdy nie
sięgają progu. W hurtowej odpowiedzi listy ta sama liczba jechałaby dla
trzystu serwerów przy każdym odświeżeniu każdej otwartej karty. Tutaj
pojawia się wyłącznie wtedy, gdy ktoś świadomie otworzył stronę jednego
serwera.
Przykładowe żądanie
curl "https://stats.bykens.eu/api/serwer?server=okz5dj"
Przykładowa odpowiedź (skrócona)
{
"code": "okz5dj", "pinned": true, "online": true,
"hostname": "INTOUCH", "players": 235, "max": 249, "queue": 2,
"lastSeen": "2026-09-15T22:39:09.694985519Z",
"observedAtMs": 1789511949694,
"checkedAt": "2026-09-15T22:42:57.069Z",
"counters": { "state": "zgodne", "reported": 246, "counted": 235,
"diff": 11, "direction": "zawyzanie", "percent": 5,
"percentOf": "counted", "countedZero": false },
"countersThresholds": { "minPercent": 25, "minPlayers": 10 },
"activityReport": { "status": "brak-wzorca", "level": "brak",
"families": [], "confirmedFamilies": [], "signals": [],
"quality": { "observations": 26, "spanMinutes": 118, "grade": "pelna" },
"dataQuality": { "basis": "okno-obserwacji",
"coverage": { "percent": 100, "bucketMinutes": 10,
"bucketsWithObservation": 11, "bucketsTotal": 11,
"spanMinutes": 118, "observations": 26,
"minObservations": 12, "minSpanMinutes": 90 },
"largestGap": { "minutes": 7, "maxAllowedMinutes": 29, "includesNow": false },
"age": { "sourceObservationSeconds": 212, "sinceLastReadingSeconds": 14,
"staleAfterMinutes": 15, "freshness": "swieze" },
"sourceRepeats": 7, "grade": "pelna", "limits": [] } },
"measurements": {
"window": { "observations": 26, "spanMinutes": 118, "maxGapMinutes": 7,
"sufficient": true, "minObservations": 12, "minSpanMinutes": 90,
"maxGapShare": 0.25, "bufferWindowHours": 6, "samplesMax": 180,
"staleAfterMinutes": 15 },
"variation": { "computable": true, "reason": null, "meets": false,
"cvPercent": 4.7, "threshold": 2, "baseThreshold": 2, "mean": 231,
"minMeanPlayers": 20, "observations": 26, "minutes": 118,
"capacityBand": "z-zapasem", "capacitySharePercent": 46,
"capacityToleranceSlots": 25, "strictness": 1 },
"stall": { "computable": true, "reason": null, "meets": false,
"players": 235, "minutes": 5, "typicalMinutes": 9, "changes": 12,
"requiredMinutes": 60, "minMinutes": 60, "factor": 6,
"baseMinMinutes": 60, "baseFactor": 6,
"minChanges": 3, "minPlayers": 20, "atCapacity": false,
"capacityBand": "z-zapasem", "capacitySharePercent": 47,
"capacityToleranceSlots": 25, "strictness": 1 },
"families": {
"malaZmiennosc": { "met": false, "confirmed": false, "forMinutes": null,
"observations": 0, "missingForMinutes": 118,
"releaseInMinutes": null,
"wasConfirmed": true, "timesConfirmed": 1,
"sinceReleasedMinutes": 98, "confirmMinutes": 45,
"confirmMinObservations": 6, "releaseMinutes": 20 },
"rozjazdLicznikow": { "met": false, "confirmed": false, "...": "jak wyżej" }
}
},
"availability": { "hourlyProfile": false, "hourlyProfileReason": "tylko-przypiete" },
"patternReport": { "status": "obserwacje", "level": "informacja", "...": "jak w /api/trends" },
"daily": {
"days": [
{ "date": "2026-09-05", "coveragePercent": 100, "avgPlayers": 100,
"peakPlayers": 110, "hasProfile": true, "hoursCovered": 24,
"hoursExpected": 24, "maxGapHours": 0, "ratio": 1.1,
"used": true, "limited": false, "reason": null },
{ "date": "2026-09-08", "coveragePercent": 42, "avgPlayers": 100,
"peakPlayers": 110, "hasProfile": true, "hoursCovered": 24,
"hoursExpected": 24, "maxGapHours": 0, "ratio": null,
"used": false, "limited": false, "reason": "pokrycie-doby" }
],
"config": { "windowDays": 14, "minDays": 10, "minCoveragePercent": 90,
"minHoursOf24": 22, "maxGapHours": 2, "ratioMax": 1.5,
"minSharePercent": 80, "minMeanPlayers": 20 }
},
"generatedAt": "2026-09-16T00:42:57.201Z"
}
| Pole | Znaczenie |
| online | true / false / null — ostatnie
to serwer jeszcze nie sprawdzony, a nie serwer niedostępny. Trzy różne stany,
bo to trzy różne odpowiedzi |
| activityReport.dataQuality |
Jakość danych w pełnej wersji (lista dostaje zwięzłą). Ten sam kształt przy
raporcie i przy każdym sygnale; basis mówi, na czym stoi dany wynik.
coverage.percent: odsetek pełnych 10-minutowych kubełków z co
najmniej jedną obserwacją źródłową, od pierwszej obserwacji do teraz. Kubełek, w którym
wypada „teraz", nie wchodzi do rachunku; okno krótsze niż kubełek ma null.
Przerwa dłuższa niż 15 min kasuje bufor, więc pokrycie spada poniżej 100% tylko przez
dziury 10–15 min — dłuższe zaczynają okno od nowa i widać je po
observations i spanMinutes.
largestGap: największa luka, dozwolone maksimum (¼ okna)
i includesNow — czy to luka od ostatniej obserwacji do teraz.
age: wiek obserwacji źródłowej i czas od naszego ostatniego odczytu,
liczone w chwili odpowiedzi. Dla sygnału countersDiffer
coverage i largestGap są null — nie dotyczą.
limits: za-malo-obserwacji, okno-za-krotkie,
luka-ponad-cwierc-okna, swiezosc-nieznana,
nieaktualne. Pokrycie jest wystawiane, nie bramkowane
|
| measurements |
Pomiary BEZ progów. activityReport.signals mówi „zapalić czy nie";
to pole mówi ile dokładnie wyszło i ile brakowało do progu. Dla serwera
niedostępnego jest null — wskaźnika wtedy nie liczymy w ogóle.
computable: czy tej liczby wolno użyć. false
oznacza, że liczba jest policzona, ale nie znaczy nic — powód w reason:
brak-obserwacji, okno-niewystarczajace,
ponizej-pulapu-graczy, komplet-na-serwerze (stała liczba
przy komplecie to skutek limitu, nie własność licznika — dotyczy obu pomiarów,
a komplet to limit minus max(2 sloty, 5% limitu), bo sloty trzymają też gracze
na ekranie ładowania), za-malo-zmian.
capacityBand: położenie względem limitu slotów —
komplet, blisko-limitu (powyżej 90%, progi zaostrzone
strictness-krotnie: CV 2% → 1%, zastój 60 → 120 min i 6× → 12×),
z-zapasem albo null (limit nieznany, progi bazowe).
Dla variation liczone dla całego okna, dla stall — dla
wartości, na której licznik stoi.
meets: czy próg jest przekroczony. Przy computable: false
jest zawsze false.
Progi jadą razem z liczbami (threshold,
minMinutes, factor, requiredMinutes — to progi
obowiązujące przy danym położeniu; bazowe w baseThreshold,
baseMinMinutes, baseFactor), żeby
nikt nie trzymał własnej kopii — ta rozjeżdża się przy pierwszej zmianie
|
| measurements.families |
Stan maszyny potwierdzania dla obu rodzin ścieżki listy — i jedyna
historia, jaką ten wskaźnik ma. met to „warunek jest spełniony
teraz", confirmed to „trwa nieprzerwanie dość długo, żeby się
liczyć". confirmed: true przy met: false znaczy, że
rodzina była aktywna przed chwilą i właśnie się wygasza —
releaseInMinutes mówi, ile zostało.
Po zgaśnięciu wszystkie pola powyżej wracają do wartości „nic się nie
działo", więc rodzina wygasła wyglądałaby identycznie jak taka, która nigdy się
nie zapaliła. Odróżniają je trzy pola: wasConfirmed,
timesConfirmed i sinceReleasedMinutes (ile minut temu
zgasła). releaseInMinutes i sinceReleasedMinutes to
dwie różne rzeczy i nigdy nie są niepuste naraz: pierwsze odlicza do
zgaśnięcia, drugie liczy od niego.
Dalej wstecz nie widzimy i nie jest to dziennik zdarzeń: bufor żyje
w pamięci, więc licznik timesConfirmed zeruje i restart
usługi, i przerwa w odczytach dłuższa niż próg świeżości
|
| availability |
Czego dla tego serwera nie zmierzymy — i że to się nie zmieni.
hourlyProfile: false (z powodem tylko-przypiete) znaczy,
że profilu godzinowego dla niego nie zbieramy: miara
profileShape nie policzy się nigdy, a nie „jeszcze nie",
i wszystkie jego doby mają trwale limited: true.
Dziś ta wartość równa się pinned i to jest celowa nadmiarowość:
reguła „przypięty ⇒ jest profil" ma siedzieć w jednym miejscu. Gdyby profil
kiedyś objął całą listę, pinned zostałoby bez zmian, a klient
wnioskujący z niego zacząłby kłamać; tutaj zmienia się jedna linijka.
Dotyczy to też serwera odpiętego: rollupy są trwałe, więc zachowuje
stare doby z profilem, choć nowych już nie zbieramy
|
| daily.days |
Doba po dobie z okna czternastu dni, od najstarszej. used mówi, czy
weszła do rachunku; reason jest niepusty dokładnie wtedy, gdy
nie weszła: pokrycie-doby, za-malo-graczy,
brak-szczytu, brak-godzin, pokrycie-godzin,
dziura-w-dobie. limited: true to doba, która weszła, ale
bez profilu godzinowego — i to ta etykieta blokuje potem podniesienie poziomu.
Powód pochodzi z tej samej listy warunków, z której korzysta sam wskaźnik
|
| daily.config | Progi ścieżki dobowej, podane wprost. minDays: 10
to inna liczba niż czternaście dni raportu /api/trends: wskaźnik
potrzebuje dziesięciu dób z czternastu i nie wymaga ciągłości |
| countersThresholds | Progi rozjazdu liczników — oba muszą być
przekroczone naraz. Sam procent zapalałby małe serwery, sama liczba duże |
| Kody odpowiedzi | 400 — brak parametru albo to nie jest kod
cfx. 404 — poprawny kod, ale tego serwera nie ma na liście |
Limity: brak rate limitu. Czyta wyłącznie z pamięci podręcznej —
Twoje żądanie nigdy nie wywoła zapytania do cfx i nie przesuwa stanu wskaźnika.
Profil godzinowy zbieramy tylko dla serwerów przypiętych, więc dla pozycji
dołożonej z listy wszystkie doby mają limited: true, a miara
profileShape nie policzy się nigdy — to ograniczenie kosztu zapisu,
nie brak danych, na które trzeba poczekać.
Trendy
GET/api/trends
Porównanie tydzień do tygodnia dla każdego śledzonego serwera: średnia
graczy, średnia kolejka i szczyty z ostatnich siedmiu pełnych dni
wobec siedmiu poprzednich. Liczone z dziennych rollupów — zbioru
całkowicie osobnego od /api/history (24 h)
i /api/hourly (siatka 7×24 bez daty).
Dzisiejszy dzień nie wchodzi do żadnego okna — jest niepełny. Jeśli
w oknie czternastu dni brakuje choć jednego, ten serwer dostaje
ready: false i żadnych pól porównania: nie ma
current, previous ani change.
To celowe — liczba wyliczona z dziur wygląda tak samo jak prawdziwa.
Przykładowe żądanie
curl https://stats.bykens.eu/api/trends
Przykładowa odpowiedź (skrócona)
{
"ready": true,
"daysNeeded": 14,
"weekDays": 7,
"windows": {
"current": { "from": "2026-09-07", "to": "2026-09-13" },
"previous": { "from": "2026-08-31", "to": "2026-09-06" }
},
"minSamplesPerDay": 144,
"expectedSamplesPerDay": 288,
"flatPercent": 5,
"servers": [
{
"code": "okz5dj", "label": "Intouch.gg",
"ready": true, "daysCollected": 31, "daysMissing": 0, "waitDays": 0,
"current": { "days": 7, "avgPlayers": 198.4, "avgQueue": 12.7, "peakPlayers": 250, "peakQueue": 61 },
"previous": { "days": 7, "avgPlayers": 181.2, "avgQueue": 10.3, "peakPlayers": 248, "peakQueue": 54 },
"change": {
"players": { "comparable": true, "from": 181.2, "to": 198.4, "percent": 9, "direction": "up" },
"queue": { "comparable": true, "from": 10.3, "to": 12.7, "percent": 23, "direction": "up" }
}
},
{
"code": "jjj4kl", "label": "Onbeat",
"ready": false, "daysCollected": 11, "daysMissing": 3, "waitDays": 3,
"pattern": null,
"patternReport": {
"status": "obserwacje",
"level": "informacja",
"families": ["ksztaltDoby"],
"confirmedFamilies": [],
"quality": { "days": 11, "limitedDays": 0, "daysWithProfile": 11, "minDays": 10, "grade": "pelna" },
"signals": [
{ "id": "lowPeakToAverage", "family": "ksztaltDoby", "experimental": true, "confirmed": false,
"data": { "days": 11, "lowDays": 11, "limitedDays": 0, "typicalRatio": 1.02,
"highestRatio": 1.05, "threshold": 1.5, "from": "2026-09-03", "to": "2026-09-13" } },
{ "id": "profileShape", "family": "ksztaltDoby", "experimental": true, "confirmed": false,
"data": { "days": 11, "hours": 24, "profileAmplitude": 0.06, "profileAgreement": 0.31 } }
]
}
}
],
"generatedAt": "2026-09-14T16:20:03.918Z"
}
| Pole | Znaczenie |
| ready | Na poziomie serwera: czy w oknie czternastu dni jest komplet. Na poziomie całej odpowiedzi: czy choć jeden serwer ma komplet — nowy serwer nie blokuje raportu dla pozostałych |
| waitDays | Za ile dni okno będzie pełne. Brakujący dzień wypada z okna dopiero, gdy przesunie się poza czternasty, więc to nie zawsze jest po prostu daysMissing |
| daysCollected | Ile pełnych dni mamy w ogóle (okno rollupów to 90 dni), niezależnie od okna porównania |
| minSamplesPerDay | Od ilu odczytów dzień liczy się jako pełny. Dzień poniżej progu jest traktowany jak brak dnia, a nie jak dzień z niższą średnią |
| change.*.comparable | false, gdy poprzednia średnia była bliska zeru — wtedy percent jest null, bo skok z 0,2 na 0,6 to formalnie „+200%", a w praktyce dalej brak kolejki |
| change.*.direction | up / down / flat. flat poniżej flatPercent — percent jest wtedy dalej podany |
| avgPlayers / avgQueue | Średnia ze średnich dziennych, nie ze wszystkich próbek — krótszy dzień ma ważyć tyle samo, co pełny |
| patternReport |
Wskaźnik licznika graczy liczony z trwałych rollupów dziennych zamiast z bufora
obserwacji. Zawsze obecny, ze status jak w
activityReport (za-malo-danych /
brak-wzorca / obserwacje).
Dziś zawiera dwie miary, obie eksperymentalne — nie podnoszą
level ponad informacja i nie mają progów alarmowania:
lowPeakToAverage — niski stosunek szczytu doby do średniej tej
doby, w ≥ 80% z minimum 10 dób. Nazwa jest dosłowna, bo miara opisuje
amplitudę względem poziomu, a nie rytm dobowy: płynny, powtarzalny rytm
od 60 graczy w nocy do 140 wieczorem ma średnią 100 i stosunek 1,40, czyli poniżej
progu 1,5. Ta miara nie dowodzi braku rytmu dobowego ani manipulacji.
profileShape — profileAmplitude (rozpiętość medianowego
profilu godzinowego, 0 = płaska linia) i profileAgreement (powtarzalność
profilu między dobami, 1 = ten sam kształt co dzień). To dwie różne rzeczy niż
powyższa i często jej przeczą.
Do rachunku wchodzą wyłącznie doby o pokryciu ≥ 90%, pokryciu godzin ≥ 22 z 24
i największej ciągłej luce ≤ 2 h — samo pokrycie nie wystarcza, bo braki skupione
w jednej porze doby to pomiar czegoś innego. Doby zebrane przed wprowadzeniem profilu
godzinowego mają quality.grade: "ograniczona".
dataQuality (basis: "doby-rollupu", także przy każdej
mierze): coverage — ile dób weszło do rachunku z okna 14
(daysUsed, percent), najsłabsze pokrycie przyjętej doby;
largestGap.hours — najdłuższa luka w profilu godzinowym przyjętych dób;
age.daysSinceLastDay — ile dób temu była ostatnia przyjęta doba;
limits: za-malo-dob, doby-bez-profilu.
Profil godzinowy zbieramy tylko dla serwerów przypiętych — przy 300
pozycjach listy to ~19 MB w jednym pliku zapisywanym co pięć minut.
Progi (1,5; 10 dób; 80%) dobrano na trzech serwerach i jednej dobie —
są wstępne i nie określają częstości fałszywych alarmów.
Brak obserwacji nie potwierdza, że liczba graczy jest prawdziwa
|
| pattern | Pole zgodnościowe dla starszej strony. Dziś zawsze
null: wszystkie miary tej ścieżki są eksperymentalne i nie osiągają
poziomu wzorzec. Nowy kod czyta patternReport |
Limity: brak rate limitu. Treść zmienia się raz na dobę — odpytywanie częściej niż co kilka godzin nic nie wnosi.
Resource'y
GET/api/resources
Ranking najpopularniejszych resource'ów — na ilu ze śledzonych serwerów
występuje każda nazwa. Liczony na żywo z pamięci procesu (dashboard
plus lista serwerów, każdy serwer raz), z krótkim, kilkusekundowym
oknem pamięci podręcznej. Nic tu nie jest zapisywane na dysk, więc to
stan z tej chwili, a nie historia.
Przykładowe żądania
curl https://stats.bykens.eu/api/resources
curl "https://stats.bykens.eu/api/resources?limit=50&builtin=1"
Przykładowa odpowiedź (skrócona)
{
"top": [
{ "rank": 1, "name": "ox_lib", "servers": 4, "percent": 100, "builtin": false },
{ "rank": 2, "name": "oxmysql", "servers": 4, "percent": 100, "builtin": false },
{ "rank": 3, "name": "pma-voice", "servers": 4, "percent": 100, "builtin": false }
],
"serversTotal": 5,
"serversCounted": 4,
"resourcesTotal": 883,
"builtinTotal": 4,
"builtinIncluded": false,
"limit": 20,
"generatedAt": "2026-09-14T16:02:11.004Z"
}
| Parametr | Znaczenie |
| limit | Ile pozycji zwrócić. Domyślnie 20, maksymalnie 100 |
| builtin | 1 dokłada resource'y z paczki FiveM i txAdmina (hardcap, monitor, sessionmanager…). Domyślnie ich nie ma — stoją prawie wszędzie, więc bez nich ranking mówi o tym, co administratorzy faktycznie wybrali |
| Pole | Znaczenie |
| serversTotal | Ile serwerów w ogóle śledzimy (dashboard + lista, bez podwójnego liczenia) |
| serversCounted | Z ilu z nich udało się wziąć listę resource'ów. To jest mianownik percent — serwer, który nie odpowiada, nie jest serwerem z zerem resource'ów, więc wypada z obliczeń |
| percent | servers / serversCounted, zaokrąglone. Mówi na ilu serwerach, nie ilu graczy to widzi |
| builtinTotal | Ile rozpoznanych wbudowanych nazw jest w całym zbiorze — niezależnie od limit i od builtin |
Limity: brak rate limitu. Wynik przeliczany nie częściej niż raz na 10 s.
Zapis — bez CORS
Poniższe endpointy nie wysyłają nagłówka Access-Control-Allow-Origin,
więc nie wywołasz ich z przeglądarki z obcej domeny. Z curla
czy z własnego backendu — owszem. Obowiązuje rate limit liczony po
prawdziwym adresie IP żądania, a nie po nagłówku, który łatwo podrobić.
POST/api/lookup/add
Dodaje serwer do wspólnej listy. Przyjmuje sam kod cfx.re albo pełny link
(cfx.re/join/…, servers.fivem.net/servers/detail/…).
Serwer musi istnieć — nieistniejący kod nie trafia na listę.
Przykładowe żądanie
curl -X POST https://stats.bykens.eu/api/lookup/add \
-H 'Content-Type: application/json' \
-d '{"code":"okz5dj"}'
Przykładowa odpowiedź
{ "ok": true, "code": "okz5dj", "added": true, "server": { … } }
| Odpowiedź | Kiedy |
| 200 alreadyOnList | Serwer już jest na liście — traktowane jak sukces |
| 400 bad_code | Kod nie ma formatu cfx.re (6–7 znaków alfanumerycznych) |
| 404 not_found | Serwer o tym kodzie nie istnieje albo nie odpowiada |
| 409 list_full | Lista osiągnęła 300 pozycji |
| 429 rate_limit | Przekroczony limit prób |
Limity: maksymalnie 5 prób na 10 minut z jednego adresu IP. Liczone są wszystkie żądania, także te ze złym kodem. Licznik jest osobny od licznika usuwania.
POST/api/lookup/add-many
Dodaje kilka serwerów jednym żądaniem. Pole codes to jeden kawałek
tekstu — kod albo link na linię, albo oddzielone przecinkami; oba warianty
działają zamiennie. Każda pozycja przechodzi dokładnie tę samą ścieżkę co
przy /api/lookup/add: format kodu, deduplikacja, sufit długości listy
i wymóg istnienia serwera.
Przykładowe żądanie
curl -X POST https://stats.bykens.eu/api/lookup/add-many \
-H 'Content-Type: application/json' \
-d '{"codes":"okz5dj\njjj4kl, yokb5k"}'
Przykładowa odpowiedź
{
"ok": true,
"results": [
{ "input": "okz5dj", "code": "okz5dj", "status": "added", "server": { … } },
{ "input": "jjj4kl", "code": "jjj4kl", "status": "already", "server": null },
{ "input": "abc!!!", "code": null, "status": "bad_code", "server": null }
],
"added": ["okz5dj"],
"summary": { "added": 1, "already": 1, "bad_code": 1,
"not_found": 0, "list_full": 0, "duplicate_in_batch": 0 },
"count": 42,
"limit": 300
}
| status pozycji | Znaczenie |
| added | Dopisany do listy; server zawiera komplet danych z odpytania weryfikującego |
| already | Ten kod już był na liście |
| duplicate_in_batch | Ten sam kod wystąpił w zgłoszeniu więcej niż raz |
| not_found | Serwer o tym kodzie nie istnieje albo nie odpowiada; powód w polu error |
| bad_code | To nie jest kod cfx.re ani link; code jest wtedy null, a input trzyma wklejony tekst |
| list_full | Lista zapełniła się w trakcie tego zgłoszenia |
| Odpowiedź | Kiedy |
| 200 | Zgłoszenie rozpatrzone — także wtedy, gdy żadna pozycja się nie dodała. O losie każdego kodu mówi jego status |
| 400 empty | Puste zgłoszenie |
| 400 batch_too_big | Więcej niż 10 pozycji — zgłoszenie odrzucane w całości, nie przycinane |
| 400 batch_too_long | Sam tekst zgłoszenia dłuższy niż 2000 znaków |
| 429 rate_limit | Przekroczony limit prób |
Limity: najwyżej 10 kodów w jednym zgłoszeniu. Rate limit jest wspólny z /api/lookup/add (5 żądań na 10 minut z jednego IP) i liczy ŻĄDANIA, nie kody — jedna paczka to jedno trafienie.
DELETE/api/lookup/remove
Usuwa serwer z listy. Bez logowania — usunąć może każdy, tak samo jak
każdy może dodać. Kod można podać w ciele żądania albo jako
?code=.
Przykładowe żądanie
curl -X DELETE https://stats.bykens.eu/api/lookup/remove \
-H 'Content-Type: application/json' \
-d '{"code":"okz5dj"}'
Przykładowa odpowiedź
{ "ok": true, "code": "okz5dj", "removed": true }
Limity: maksymalnie 5 prób na 10 minut z jednego adresu IP, na liczniku osobnym od dodawania. Usunięcie serwera, którego nie ma na liście, zwraca 200 z alreadyGone — stan jest przecież taki, jakiego chciałeś.
Kanał zdarzeń (RSS)
GET/feed.xml
Ten sam ticker co /api/events, tyle że w formacie
Atom — do wrzucenia w dowolny czytnik RSS. Strona główna ma
<link rel="alternate" type="application/atom+xml">,
więc czytniki znajdą kanał same po podaniu samego adresu serwisu.
To nie jest archiwum
Zdarzenia żyją wyłącznie w pamięci procesu i restart usługi je kasuje —
dokładnie tak samo jak pasek zdarzeń na stronie głównej. Kanał pokazuje
ostatnie kilkadziesiąt minut, a po restarcie bywa pusty. Pusty kanał to
poprawny kanał, nie awaria.
Przykładowe żądanie
curl https://stats.bykens.eu/feed.xml
Przykładowa odpowiedź (skrócona do jednego wpisu)
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Statystyki serwerów FiveM — zdarzenia</title>
<id>https://stats.bykens.eu/feed.xml</id>
<link rel="self" type="application/atom+xml" href="https://stats.bykens.eu/feed.xml"/>
<link rel="alternate" type="text/html" href="https://stats.bykens.eu/"/>
<updated>2026-09-14T16:59:06.800Z</updated>
<author><name>Statystyki serwerów FiveM</name></author>
<entry>
<title>Rekord kolejki: Intouch.gg (51)</title>
<link rel="alternate" type="text/html" href="https://stats.bykens.eu/"/>
<id>https://stats.bykens.eu/feed.xml#okz5dj-record-queue-2026-09-14T16:40:00.000Z</id>
<updated>2026-09-14T16:40:00.000Z</updated>
<published>2026-09-14T16:40:00.000Z</published>
<category term="record-queue"/>
<content type="text">Nowy dzisiejszy rekord kolejki na Intouch.gg: 51.</content>
</entry>
</feed>
Rodzaje zdarzeń (category term)
| term | Znaczenie |
| online | Serwer znowu odpowiada |
| offline | Serwer przestał odpowiadać |
| full | Przekroczony próg zapełnienia (z histerezą, żeby nie migało) |
| record-players | Nowy dzisiejszy rekord graczy |
| record-queue | Nowy dzisiejszy rekord kolejki |
| Pole | Uwaga |
| entry/id | Składane z kodu serwera, rodzaju zdarzenia i znacznika czasu — nie z licznika w pamięci. Licznik po restarcie zaczyna od jedynki, więc to samo id oznaczałoby raz jedno zdarzenie, raz zupełnie inne, a czytnik po id rozpoznaje, co już widział |
| entry/link | Prowadzi na stronę główną. Zdarzenia nie mają własnych podstron i udawanie, że mają, dałoby martwy link |
| id i link | Składane z adresu, pod którym pobrano kanał — ta sama usługa odpowiada na localhost i na domenie |
Limity: brak rate limitu. Bufor mieści 20 ostatnich zdarzeń, bez cache po drodze.
Monitoring
GET/health
Dla zewnętrznych monitoringów (UptimeRobot i podobne). Bez logowania,
z CORS-em, bez cache. Odpowiada na pytanie „czy ta usługa działa",
a nie „czy serwery FiveM są online".
Przykładowe żądanie
curl -i https://stats.bykens.eu/health
Przykładowa odpowiedź
{
"status": "ok",
"uptimeSeconds": 9,
"lastSuccessfulPollAt": "2026-09-14T14:14:07.393Z",
"staleAfterSeconds": 60,
"serversTracked": 3,
"calibrationSampleSize": 0
}
| Kod / status | Znaczenie |
| 200 ok | Pętla odpytywania działa — ostatni udany odczyt jest świeższy niż staleAfterSeconds |
| 200 starting | Usługa właśnie wstała i nie zdążyła jeszcze nic pobrać. To rozruch, nie awaria |
| 503 stale | Od staleAfterSeconds nie udało się pobrać danych z żadnego serwera — coś utknęło |
| calibrationSampleSize | Ile serwerów próby kalibracyjnej dzieli dziś budżet odpytywania z resztą. 0 poza przebiegiem zbierającym. Serwery próby nie są liczone w serversTracked i nie pojawiają się w żadnym innym endpoincie |
Co NIE jest błędem: pojedynczy serwer FiveM offline. Znacznik ostatniego udanego odczytu stawiamy, gdy odpowie choć jeden serwer — inaczej /health zamieniłby się w alarm o cudzej awarii. Próg to trzykrotność POLL_INTERVAL_MS (przy domyślnych 20 s → 60 s).
Odznaka do README
GET/badge.svg
Obrazek SVG z aktualną liczbą graczy — do wklejenia w README na GitHubie,
na stronę serwera albo gdziekolwiek działa <img>. Generowany
u nas, nie przez shields.io, więc nie zależy od obcej usługi.
Wysyła Cache-Control: no-cache, żeby nie pokazywać liczby sprzed
godzin, i Access-Control-Allow-Origin: *, żeby dało się go osadzić wszędzie.
Do wklejenia w Markdown




W HTML-u
<img src="https://stats.bykens.eu/badge.svg" alt="Gracze online" />
| Parametr | Znaczenie |
| type | total (domyślnie, gracze + kolejka), players albo queue. Nieznana wartość cicho wraca do total — odznaka w cudzym README ma się narysować zawsze, a nie wywrócić na literówce |
| server | Kod jednego ze śledzonych serwerów zamiast sumy. Nieznany kod daje odznakę z napisem „nieznany kod serwera", a nie błąd HTTP — po drugiej stronie jest <img>, więc 500 pokazałoby tylko ikonę zepsutego obrazka |
Limity: brak rate limitu. Odznaka zawsze zwraca HTTP 200 — także gdy serwer jest offline (napis „offline") albo nie ma jeszcze danych („brak danych").
GET/badge-uptime.svg?server=KOD
Dostępność serwera z ostatnich 24 h. Ta sama szata co
/badge.svg, ale parametr server jest tu
obowiązkowy — uptime liczymy per serwer i nie ma czegoś takiego jak
„uptime sumy".
Do wklejenia w Markdown

| Co widać | Kiedy |
| 99,6% na turkusie | Od 99% w górę |
| 97,3% na bursztynie | Od 95% do 99% — w skali doby 99% to już kwadrans niedostępności, więc próg jest celowo surowy |
| 42,1% na czerwieni | Poniżej 95% |
| brak danych na szaro | Za mało odczytów, żeby cokolwiek powiedzieć. To nie to samo co 0% — zero byłoby oskarżeniem serwera o awarię, której nie zmierzyliśmy |
| BŁĄD: podaj ?server=kod | Brak parametru |
| BŁĄD: nieznany kod serwera | Kod spoza śledzonej trójki |
Uwaga: odznaka działa także dla serwera, który właśnie nie odpowiada — wtedy ta liczba jest najbardziej potrzebna, więc nie zastępujemy jej napisem „offline".
GET/badge-ocena.svg?server=KOD
Ocena zdrowia serwera — ta sama litera, którą liczy /api/stats
i karta serwera. Odznaka nie pokazuje samej litery: obok niej stoi
powód, bo ocena bez podstawy jest wyrokiem, a nie pomiarem.
Parametr server obowiązkowy.
Do wklejenia w Markdown

| Co widać | Kiedy |
| A · 99,6% na turkusie | Uptime 7 dni powyżej 99% i żadna rodzina obserwacji licznika nie jest potwierdzona |
| B · 97,3% na bursztynie | Uptime od 95% do 99%, obserwacje jak wyżej |
| C · 90,1% na czerwieni | Uptime poniżej 95% |
| C · wzorzec licznika na czerwieni | Uptime w porządku, ale utrzymuje się obserwacja licznika |
| brak oceny na szaro | Któregoś z dwóch pomiarów nie da się policzyć — na przykład uptime ma jeszcze mniej niż dobę obserwacji. Szary, nigdy czerwony: brak pomiaru nie jest zarzutem wobec serwera |
Pełny rachunek — obie liczby, reguła i powody braku litery — jest na karcie serwera: /serwer?server=KOD.
GET/badge-framework.svg?server=KOD
Rozpoznany framework serwera — ESX, QBCore,
Qbox, vRP, rg_core. Te same reguły
wykrywania co na liście serwerów i w /api/stats, bo jest to
jedna kopia w fivem-parse.js. Parametr server
obowiązkowy.
Do wklejenia w Markdown

| Co widać | Kiedy |
| rg_core na turkusie | Rozpoznano framework |
| nieznany na szaro | Serwer odpowiedział, ale żaden ze znanych markerów nie pasuje. Nigdy pusta prawa część — odznaka bez wartości wygląda na zepsutą, a nie na „nie wiemy" |
| offline na czerwieni | Serwer nie odpowiada. Po błędzie nie mamy już poprzedniego odczytu, a „nieznany" sugerowałoby, że serwer odpowiedział i nic nie rozpoznaliśmy |
Limity: brak rate limitu. Jak wszystkie odznaki — zawsze HTTP 200, no-cache i CORS *.
Widget do osadzenia
GET/widget?server=KOD
Nie API, tylko gotowa strona HTML do wstawienia w <iframe>:
jedna karta, przezroczyste tło, bez nagłówka i sortowania. Bez parametru
pokazuje sumę wszystkich śledzonych serwerów. Odświeża się sama co 15 s.
Do wklejenia na własną stronę
<iframe
src="https://stats.bykens.eu/widget?server=okz5dj"
width="330" height="160" style="border:0"
title="Statystyki serwera FiveM" loading="lazy"></iframe>
| Parametr | Znaczenie |
| server | Kod serwera. Pominięty → suma wszystkich. Nieznany → karta „brak danych", nie błąd HTTP |
Limity: karta ma stałą wysokość 157 px, więc height="160" nigdy nie wywoła paska przewijania.