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

@ekmanss/5eplay

v20260718.1.0

Published

Typed 5EPlay CS2 live-match discovery, match-detail snapshots, and MQTT updates without a browser.

Readme

@ekmanss/5eplay

Typed 5EPlay CS2 match details and live updates for Node.js 22+. The collector uses 5EPlay's JSON endpoints and MQTT-over-WebSocket feed directly; it does not launch a browser, execute page JavaScript, scrape rendered DOM, or require a logged-in account.

Install

pnpm add @ekmanss/5eplay

Complete match snapshot

import { getFiveEPlayMatch } from '@ekmanss/5eplay';

const result = await getFiveEPlayMatch(
  'https://event.5eplay.com/csgo/matches/csgo_mc_2395709',
);

console.log(result.data.match);
console.log(result.data.maps);
console.log(result.data.current);

The default snapshot includes every public match-data section used by the page:

  • match, tournament, teams, ranks, odds, best-of, stage, and series score;
  • complete map veto and every picked/decider map, including temporarily omitted upcoming maps;
  • per-map scores, halves, round-result codes, live timer/bomb state, and player equipment;
  • completed-map Data Overview metrics and the 5-by-5 Player Comparison kill matrix;
  • complete historical logs and the current map's available log history;
  • pre-match team/player/map analysis, recent matches, and head-to-head history;
  • public player and big-event community rating cards.

Chat messages, login state, cookies, and account-specific actions are deliberately excluded.

getFiveEPlayMatch() accepts either the canonical URL or a csgo_mc_<id> identifier. It returns { data, diagnostics }. Independent HTTP sections are fetched concurrently; a normal capture does not open the realtime credential endpoint.

Currently live matches

Use the list API for frequent checks that only need to know whether a CS2 match has started:

import { getFiveEPlayLiveMatches } from '@ekmanss/5eplay';

const result = await getFiveEPlayLiveMatches();

if (result.data.hasLiveMatches) {
  for (const match of result.data.matches) {
    console.log(match.id, match.url, match.teams, match.currentMap);
  }
}

This method normally makes one small public list request and never fetches match details, analysis, logs, community ratings, Markdown, or realtime credentials. The source list also contains upcoming matches, so the collector strictly keeps series with live state (including the interval between two maps, when currentMap is null). If the first 20 source rows are all live, it continues paging until every live match is collected.

For serialized five-second polling without overlapping requests:

import { setTimeout as delay } from 'node:timers/promises';
import { getFiveEPlayLiveMatches } from '@ekmanss/5eplay';

while (true) {
  const { data } = await getFiveEPlayLiveMatches({ timeoutMs: 5_000 });
  console.log(data.hasLiveMatches, data.matches.map((match) => match.url));
  await delay(5_000);
}

Generate a formatted Markdown report

From this repository, pass a match URL/ID and either an exact .md filename or a directory:

pnpm 5eplay:md -- \
  'https://event.5eplay.com/csgo/matches/csgo_mc_2395709' \
  './outputs/5eplay-report.md'
pnpm 5eplay:md -- 'csgo_mc_2395709' './outputs'

The directory form writes ./outputs/csgo_mc_2395709.md. Parent directories are created automatically, and the completed report atomically replaces the destination file. The report contains match/map details, analysis, complete event logs, and sanitized request diagnostics. Community ratings are intentionally omitted and are not requested by the Markdown writer.

The human-readable report is deliberately more compact than the typed snapshot:

  • the overview keeps only match status/identity/version/format, capture time, and source URL;
  • completed and live maps show scores, clear half/round results, player tables, duels, highlights, milestones, and readable logs; upcoming maps use one short placeholder;
  • head-to-head and recent matches show only time, canonical match link, teams/opponent, score, and result;
  • player power is reduced to Rating plus firepower, entry, opening, utility, sniping, clutch, and trading scores;
  • transport versions, coordinates, raw round codes, provider JSON, odds, logos, and community ratings stay out of the Markdown report.

These presentation choices do not remove fields from getFiveEPlayMatch() or realtime snapshots.

Installed packages expose the same command as 5eplay-match-md and a programmatic API:

import { writeFiveEPlayMatchMarkdown } from '@ekmanss/5eplay';

const written = await writeFiveEPlayMatchMarkdown(
  'csgo_mc_2395709',
  '/absolute/path/to/report.md',
);

console.log(written.outputPath, written.bytes);

Use renderFiveEPlayMatchMarkdown(result) instead when the match has already been fetched and the caller wants the Markdown string without writing it.

Realtime session

import { createFiveEPlayMatchSession } from '@ekmanss/5eplay';

await using session = await createFiveEPlayMatchSession('csgo_mc_2395709');

for await (const update of session) {
  if (update.type === 'state') {
    console.log(update.snapshot.current?.teams);
  } else if (update.type === 'log') {
    console.log(update.event.kind, update.event.kill);
  }
}

The first yielded item is the complete HTTP snapshot. Later state updates contain the latest scoreboard snapshot and log updates contain one typed event. session.snapshot() returns the latest merged state at any time. The session uses one authorized MQTT connection for match state and one for event logs, sends keepalives, suppresses already-seen log updateVersion replays, and reconnects with a bounded backoff after an unexpected disconnect. Distinct log versions remain lossless even when their payloads match. Provider restart/replay frames that regress a started map are withheld until an HTTP resync confirms the rollback or MQTT catches up.

Always close a session, either with await using, await session.close(), or a finally block.

Options

const result = await getFiveEPlayMatch(match, {
  timeoutMs: 15_000,
  signal: abortController.signal,
  includeAnalysis: true,
  includeLogs: true,
  includeCommunityRatings: true,
  onProgress: (event) => console.error(event.stage, event.message),
});

The three include* flags default to true. Disable optional sections when only a compact live scoreboard is required.

Errors

Failures throw FiveEPlayError with stable code, operation, stage, and retryable fields. Realtime credentials are kept inside the MQTT connection and never appear in data, diagnostics, progress events, or errors.

Documentation

Disclaimer

This is an unofficial project and is not affiliated with or endorsed by 5EPlay. Consumers are responsible for complying with applicable terms and using reasonable request rates.

License

MIT © 2026 ekmanss