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

metacritic-ts

v1.3.0

Published

TypeScript library to extrapolate data from Metacritic.

Readme

metacritic-ts

Ask DeepWiki GitHub npm npm CI

A TypeScript library for interacting with the Metacritic website API. Easily search for games, movies and tv shows and retrieve their Metacritic ratings.

This library takes inspiration from another library of mine howlongtobeat-ts.

⚠️ Disclaimer: This library is not an official API and is not affiliated nor endorsed with Metacritic.com or Fandom Inc in any way. Please use this library responsibly and do not abuse or overload the Metacritic servers. Use at your own risk.

Features

  • Search for games, movies and tv shows on Metacritic
  • Retrieve rating data (critic and user scores) for games, movies and tv shows
  • Resilient networking: configurable timeouts, retries with backoff, 429 handling, an injectable fetch and AbortSignal support
  • Failures carry a machine-readable kind, so you can tell a Metacritic outage from a change that broke this library
  • Fully typed, with a discriminated-union result type and zero console noise

Installation

npm install metacritic-ts

Requires Node.js 18 or newer (the library uses the global fetch). Ships both ESM and CommonJS builds.

Usage

import { MetacriticService, RecordType } from 'metacritic-ts'

const metacritic = new MetacriticService()

// Search across all record types (games, movies, tv shows).
const results = await metacritic.search('The Last of Us')
if (results.success) {
  console.log(results.data) // MetacriticSearchEntry[]
} else {
  console.error(results.error)
}

// Restrict to a record type via the options object.
await metacritic.search('Breaking Bad', { recordType: RecordType.TVShow })

// Fetch the full critic/user score breakdown for the best match.
const detail = await metacritic.getDetail('The Last of Us Part II', RecordType.Game)
if (detail.success && detail.data) {
  console.log(detail.data.criticScore.score, detail.data.userScore.score)
}

Handling failures

Every failure carries an optional kind alongside error. Branch on kinderror is prose for humans and its wording may change between releases.

const detail = await metacritic.getDetail('The Last of Us Part II', RecordType.Game)
if (!detail.success) {
  switch (detail.kind) {
    case 'notFound':
      // Nothing is broken — Metacritic has no matching entry.
      break
    case 'transport':
    case 'timeout':
      // Could not reach Metacritic at all — a retry may well succeed.
      break
    case 'http':
      // Metacritic answered with an error status; `status` is set.
      console.error(`Metacritic returned ${detail.status}`)
      break
    case 'parse':
      // Metacritic answered, but the response could not be read: the site has
      // most likely changed shape. Please open an issue on this repo.
      break
    case 'aborted':
      // Your own AbortSignal fired.
      break
    case 'input':
      // The arguments were rejected — an empty key, or a record type with no
      // detail endpoint.
      break
  }
}

| kind | What happened | Where the fix lives | | ----------- | ---------------------------------------------------------- | ------------------- | | input | Arguments rejected | your call site | | transport | The round trip never completed — DNS, refused, reset, TLS | the network | | timeout | The per-request deadline elapsed | the network | | aborted | Your AbortSignal fired | your call site | | http | Metacritic answered with a non-2xx status (see status) | Metacritic | | parse | The response could not be understood | this library | | notFound | The search matched nothing, so there is no detail to fetch | nobody | | unknown | Could not be attributed to any of the above | — |

Note that search itself never reports notFound: a search matching nothing succeeds with an empty array, and searchOne succeeds with null. Only getDetail reports it, because it has no entry to look up.

Configuration

Pass an options object to the constructor (a bare number is still accepted as minSimilarity for backwards compatibility):

import { MetacriticService, consoleLogger } from 'metacritic-ts'

const metacritic = new MetacriticService({
  minSimilarity: 0.5, // min similarity threshold (0–1), clamped
  timeout: 30_000, // per-request timeout in ms
  retries: 2, // retry attempts on transient failures / 429 / 5xx
  logger: consoleLogger, // opt in to diagnostic logging (default: silent)
  // fetch: myCustomFetch,  // inject a custom fetch (proxy, undici agent, …)
})

// Cancel in-flight requests.
const controller = new AbortController()
const promise = metacritic.search('Halo', { signal: controller.signal })
controller.abort()

API

MetacriticService

  • constructor(options?: number | ScraperOptions)ScraperOptions extends the HTTP options (timeout, retries, retryDelay, fetch, userAgents, logger) with minSimilarity.
  • search(searchKey, options?): Promise<SearchResult>options is { recordType?, sortBySimilarity?, signal? }.
  • getDetail(searchKey, recordType, options?): Promise<DetailResult>options is { sortBySimilarity?, signal? }.

For getDetail, sortBySimilarity (default true) is important: with false, the first API result may not be the one you are looking for.

SearchResult / DetailResult

Discriminated unions:

type FailureKind = 'input' | 'transport' | 'timeout' | 'aborted' | 'http' | 'parse' | 'notFound' | 'unknown'
type Failure = { success: false; error: string; kind?: FailureKind; status?: number }

type SearchResult = { success: true; data: MetacriticSearchEntry[] } | Failure
type DetailResult = { success: true; data: MetacriticEntry | null } | Failure

error is always present. kind is always set by this library, and status is set whenever kind is 'http'. Both are typed as optional because they come from the shared @deadlock-too/scrape-kit Failure, where they were added without breaking older producers.

RecordType

TVShow, Movie, Game.

MetacriticSearchEntry

id, recordType, title, slug, must, criticScoreValue (the critic score as a number), similarity.

MetacriticEntry

id, recordType, title, slug, must, and criticScore / userScore, each a Score:

type Score = {
  score: number
  maxScore: number
  sentiment: string
  count: { positive: number; neutral: number; negative: number; total: number }
}

Development

git clone https://github.com/Deadlock-too/metacritic-ts.git
cd metacritic-ts
npm install

npm run build            # build with tsup
npm test                 # unit tests
npm run test:integration # live API tests (hit Metacritic)
npm run test:coverage    # unit tests with coverage
npm run lint             # eslint
npm run format           # prettier

Releases are managed with Changesets: run npm run changeset to record a change; the release workflow publishes to npm once the generated version PR is merged.

Issues, Questions & Discussions

If you found a bug, report it as soon as possible creating an issue, the code is not perfect for sure, and I will be happy to fix it. If you need any new feature, or want to discuss the current implementation/features, consider opening a discussion or even propose a change with a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.