npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@writeshh/fotmob-api

v0.1.0

Published

Unofficial FotMob API client — match data, live scores and xG. TypeScript, zero dependencies.

Readme

fotmob-api

Unofficial FotMob client for Node 20+. TypeScript, zero dependencies, native fetch.

Usage guide with real response samples →

npm install @writeshh/fotmob-api
import { getMatchesByDate, getMatchDetails, search } from "@writeshh/fotmob-api";

const today = await getMatchesByDate(new Date());     // grouped by league
const match = await getMatchDetails(5795432);         // facts, lineups, stats, shotmap
const hits  = await search("arsenal");

| function | endpoint | | --- | --- | | getMatchesByDate(date) | matches?date=YYYYMMDD | | getMatchDetails(matchId) | matchDetails?matchId= | | getLeagueDataForMatch(matchId, leagueId) | leagueDataForMatch?matchId=&leagueId= — other fixtures in the round, no table | | getLeague(id, season?) | leagues?id=&season= | | getLeagueSeasons(id) | leagueseasondeepstats?id= | | getTable(leagueId) | tltable?leagueId= | | getFixtures(id) | fixtures?id= | | getTeam(id) | teams?id= | | getPlayer(id) | playerData?id= | | getAllLeagues() | allLeagues | | search(term) | search/suggest?term= | | getTransfers(page) | transfers?page= | | watchMatch(matchId) | polls matchDetails — see below |

Live matches

import { watchMatch } from "@writeshh/fotmob-api";

for await (const { match, changed, finished } of watchMatch(4123517)) {
  if (changed) console.log(match.header);   // score or events moved
  if (finished) console.log("full time");
}

Polls until full time, then returns. It paces itself off each response's cache max-age — FotMob drops that to 10s while a match is ongoing — so it never outruns the CDN. Transient network errors are retried (maxRetries, default 5) instead of ending the loop. Pass signal to stop early, intervalMs to override the pacing, untilFinished: true to keep polling past full time.

matchDetails cache TTL tracks match state: 10s ongoing, 900s upcoming, 3600s finished. Polling faster returns the same cached body.

Anything not wrapped: fotmob<T>(path, params, opts). Every call takes { signal, headers, baseUrl }. Failures throw FotmobError with url and status.

Base is https://www.fotmob.com/api/data/, which needs no auth header today — the apigw.fotmob.com host and its signed x-mas / x-fm-req header are not involved. If FotMob locks these paths down, requests start returning the SPA's HTML instead of JSON and FotmobError reports it.

npm test        # type-check + deterministic tests, no network
npm run test:live   # 15 tests against the real API
npm run test:all

src/client.test.ts runs against a local stand-in server, so it is offline and deterministic. src/live.test.ts hits FotMob and resolves its own match ids at runtime rather than pinning ones that age out.

Unofficial and unaffiliated. Data belongs to FotMob; keep request volume sane.

Note: fixtures returns ids as strings while matches returns them as numbers for the same entities. Coerce before comparing across the two.