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

checkleakedcc

v2.0.0

Published

Official Node.js / TypeScript SDK for checkleaked.cc — data-breach search (Dehashed, Snusbase/experimental), hash cracking, GHunt, breach monitoring/tracking, and the full LeakRadar integration (email/domain/advanced/raw search, unlocked archive, notifica

Readme

checkleakedcc

Official Node.js / TypeScript SDK for checkleaked.cc — data‑breach search, hash cracking, Google‑account OSINT, breach monitoring, and the full LeakRadar integration (email / domain / advanced / raw search, the unlocked archive, notifications, and dark‑web indexing).

Fully typed, zero‑config, with automatic retries, typed errors, and helpers for the async unlock/export task flow.

npm i checkleakedcc

Requirements

Ships dual ESM + CommonJS with full type declarations, and has zero runtime dependencies.


Quick start

import CheckLeakedCC from 'checkleakedcc';

const api = new CheckLeakedCC('YOUR-API-KEY');

// Classic breach search
const res = await api.experimental('[email protected]', 'email');
console.log(res.found, res.results);

// Dehashed
const dh = await api.dehashed('[email protected]', 'email');

// LeakRadar domain intelligence
const report = await api.leakradar.domain.report('example.com');

// Breach monitoring
await api.tracking.add('example.com', 'domain');

CommonJS:

const CheckLeakedCC = require('checkleakedcc').default;
const api = new CheckLeakedCC('YOUR-API-KEY');

Configuration

Pass a string key, or an options object for full control:

const api = new CheckLeakedCC({
  apiKey: 'YOUR-API-KEY',
  timeout: 120000,        // ms, default 120000
  maxRetries: 2,          // retries on 429 / 5xx / transient network errors
  retryDelayMs: 500,      // base backoff
  baseUrl: 'https://api.checkleaked.cc/api',
  userAgent: 'my-app/1.0',
  throwOnErrorBody: true, // throw when the API replies `{ error: "..." }` on a 200 (default true)
});

Core search

| Method | Description | | --- | --- | | api.valid() | Validate the key, returns your plan. | | api.auth() | Lightweight auth check → { success: true }. | | api.experimental(entry, type, opts?) | Snusbase breach search. type: email, username, password, hash, name, lastip, domain, mass. | | api.dehashed(entry, type, opts?) | Dehashed search. type: email, username, password, hashed_password, name, address, phone, ip_address, vin, domain, or free (raw query). | | api.leakCheck(check, type?, opts?) | LeakCheck.io lookup. type defaults to auto. | | api.crackHash(hash) | Reverse a password hash → { hash, plain } (pro/plus). | | api.ghunt(email) | Google‑account OSINT (pro/plus). | | api.ip(ip?) | IP geolocation + ASN + WHOIS (public, free). Omit ip for your own. |

await api.dehashed('acme.com', 'domain', { page: 2, wildcard: true });
await api.experimental('john', 'username', { loadAll: true });
await api.leakCheck('+15551234567', 'phone');

Back‑compat: the v1 signatures api.experimental(entry, type) and api.dehashed(entry, type, page) still work — the third dehashed argument accepts either a page number or an options object.


Breach monitoring (api.tracking)

Two monitors share one interface. The account is identified by your key — you never pass a user id.

// Native monitor — types: 'login' | 'email' | 'domain'
await api.tracking.add('[email protected]', 'email');
await api.tracking.list();
await api.tracking.limits();                 // { limit, total }
await api.tracking.history('[email protected]', 'email');
await api.tracking.historyResult(historyId);
await api.tracking.remove(emailUniqueId);
await api.tracking.cleanEntries();

// LeakRadar monitor — types: 'domain' | 'raw'
await api.tracking.leakradar.add('example.com', 'domain');
await api.tracking.leakradar.list();
await api.tracking.leakradar.history('example.com', 'domain');

LeakRadar (api.leakradar)

The complete LeakRadar surface, grouped into scoped resources.

Email

await api.leakradar.email.search('[email protected]', { page: 1, page_size: 50, auto_unlock: false });
await api.leakradar.email.unlock('[email protected]', { max: 20 });
const task = await api.leakradar.email.unlockAsync('[email protected]', { max: 50 });
await api.leakradar.email.export('[email protected]', { format: 'csv' });
await api.leakradar.email.lockedExistsBulk(['[email protected]', '[email protected]'], true);

Domain

await api.leakradar.domain.summary('example.com', { light: true });
await api.leakradar.domain.employees('example.com', { page_size: 100 });
await api.leakradar.domain.customers('example.com');
await api.leakradar.domain.subdomains('example.com');
await api.leakradar.domain.urls('example.com');
await api.leakradar.domain.report('example.com');   // summary + every bucket in one call

Advanced search

Filter fields accept a single value or an array — scalars are auto‑wrapped.

await api.leakradar.advanced.search({ url_domain: 'example.com', password_strength: 'weak' }, { page_size: 100 });
await api.leakradar.advanced.unlock({ email_domain: 'example.com' }, { max: 100 });
const t = await api.leakradar.advanced.unlockAsync({ username: 'admin' }, { max: 500 });
await api.leakradar.advanced.export({ url_domain: 'example.com' }, 'csv');
await api.leakradar.advanced.exportUrls({ url_domain: 'example.com' });

Raw stealer‑log search, containers & files

await api.leakradar.raw.search({ q: 'example.com' }, { page_size: 25, auto_unlock: false });
await api.leakradar.raw.listParts({ container_id: 123, entry_path: 'path/file.txt' });
await api.leakradar.raw.getPart({ container_id: 123, entry_path: 'path/file.txt', seq: 0 });

await api.leakradar.container.tree({ container_id: 123, prefix: '' });
await api.leakradar.container.subfolders({ container_id: 123 });
await api.leakradar.container.fileInfo({ container_id: 123, entry_path: 'path/file.txt' });

await api.leakradar.rawFiles.list();
await api.leakradar.rawFiles.preview({ sha256_original: '…' });   // preview first to claim access
await api.leakradar.rawFiles.download({ sha256_original: '…', expires_in: 900 });

The unlocked archive & lists

await api.leakradar.unlocked.list({ page: 1, page_size: 100, status: 'new' });
await api.leakradar.unlocked.setStatus(leakId, 'in_progress');
await api.leakradar.unlocked.upsertComment(leakId, 'investigating');
await api.leakradar.unlocked.setList(leakId, listId);
await api.leakradar.unlocked.bulkStatus({ leak_ids: ['a', 'b'], target_status: 'fixed' });
await api.leakradar.unlocked.export({ format: 'csv' });

await api.leakradar.lists.create({ name: 'Q3 incident', color: '#ff0000' });
await api.leakradar.lists.list();
await api.leakradar.lists.clear(listId);      // async → poll lists.taskStatus(task_id)

Notifications & monitors

// Delivery channels
const method = await api.leakradar.notifications.methods.create({ type: 'email', value: '[email protected]' });

// Monitors
await api.leakradar.notifications.create({ type: 'domain', value: 'acme.com', method_id: method.id });
await api.leakradar.notifications.list();
await api.leakradar.notifications.setActive(id, false);
await api.leakradar.notifications.stats();

// Runs
await api.leakradar.notifications.runs.list({ page_size: 20 });
await api.leakradar.notifications.runs.items(runId);
await api.leakradar.notifications.runs.unlock(runId, { max: 50 });
await api.leakradar.notifications.runs.export(runId, { format: 'csv' });

// One‑call setup: ensure a method + create a domain monitor
await api.leakradar.monitor.quickAdd({ domain: 'acme.com', methodType: 'email' });

Dark web

await api.leakradar.darkWeb.search('acme', { page_size: 25, sort_by: 'published_at' });
await api.leakradar.darkWeb.getPost(postId);
await api.leakradar.darkWeb.sources();
await api.leakradar.darkWeb.stats();
await api.leakradar.darkWeb.digest('acme.com');   // last 7 days, or all monitored domains if omitted

Passwords, cross‑source, misc

await api.leakradar.password.range({ prefix: '5BAA6' });   // k‑anonymity, free
await api.leakradar.password.pwned('hunter2');             // → { pwned, count }

await api.leakradar.crossSourceCheck({ email: '[email protected]', domain: 'example.com' });
await api.leakradar.searchHistory({ page: 1, limit: 20 });
await api.leakradar.unlock({ leak_ids: ['id1', 'id2'] });
await api.leakradar.exports({ page: 1 });

Async tasks

unlockAsync (email / advanced / raw) returns { task_id }. Poll it:

const { task_id } = await api.leakradar.raw.unlockAsync({ q: 'example.com' }, 50);

// Server long‑poll (~25s), or client loop until done:
const done = await api.leakradar.tasks.pollUntilDone(task_id, { timeoutMs: 120000 });

Error handling

Every failure throws a typed error you can narrow with instanceof:

import {
  CheckLeakedError,
  CheckLeakedAuthError,
  CheckLeakedValidationError,
  CheckLeakedRateLimitError,
  CheckLeakedServerError,
  CheckLeakedNetworkError,
} from 'checkleakedcc';

try {
  await api.crackHash('…');
} catch (e) {
  if (e instanceof CheckLeakedAuthError) console.error('bad key or insufficient plan');
  else if (e instanceof CheckLeakedRateLimitError) console.error('slow down', e.retryAfterMs);
  else if (e instanceof CheckLeakedError) console.error(e.message, (e as any).status, (e as any).body);
}

429 and 5xx responses are retried automatically (honoring Retry-After). CheckLeaked endpoints that reply HTTP 200 with { error: "..." } are surfaced as thrown errors by default — set throwOnErrorBody: false to receive the raw body instead.


Response types

Every method is fully typed. The public response types (e.g. DehashedResult, EmailSearchResponse, LeakDetails) carry index signatures so they stay forward‑compatible as the API grows. For the exhaustive, sample‑derived nested shapes (generated from live responses with quicktype), reach for the schemas namespace:

import { schemas, type DomainSummaryResponse } from 'checkleakedcc';

type Whois = schemas.Whois;
type Leak = schemas.UnlockedLeaksItem;

Rate limits

The bot API allows 2 requests/second per key (and per IP). Space out bulk workloads accordingly; the SDK does not throttle for you.

License

MIT