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

fingerprint-platform-sdk

v0.1.5

Published

Browser SDK for the self-hosted Fingerprint Platform — collects device signals, encrypts the payload (X25519+AES-GCM), and ships it to the collector.

Readme

fingerprint-platform-sdk

Browser SDK for the self-hosted Fingerprint Platform. Collects 50+ device signals (canvas/webgl/audio hashes, fonts, timezone, hardware, behavioral aggregates, lie-detection), encrypts the payload with X25519 + AES-256-GCM, and ships it to your collector.

The collector pairs each event with server-side signals it observes directly from the request (real IP, JA4 TLS fingerprint, header order, HTTP/2 frame fingerprint) and returns a suspectScore 0–100 plus a list of risk flags.

Install

npm install fingerprint-platform-sdk
# or
pnpm add fingerprint-platform-sdk
# or
yarn add fingerprint-platform-sdk

Use it (ESM / bundlers)

import { init } from 'fingerprint-platform-sdk';

const fp = init({
  collectorUrl: 'https://fp.your-domain.com',
  // The api_key issued for your tenant when the project was provisioned.
  // Sent on every ingest as the `X-Project-Key` header. NOT the
  // human-readable project id — that's only used in the dashboard URL.
  // Without an api_key, every request returns 401 unknown_project.
  projectKey: 'Id6MOAy8K3pQpwAMc9yqQjuxmupb2Wvo4GpOBw2C6hw',
  // optional: pin a known server pubkey to skip the /v1/pk round-trip
  // serverPublicKeyB64: '...',
});

// On a meaningful action (login, signup, checkout, …)
const result = await fp.identify({
  event: 'login',
  linkedId: 'user-12345',
});

console.log(result.eventId); // "1700000000000.abc12X"
console.log(result.visitorId); // "cD6f7B607A518A37aB38" (mixed-case alphanumeric,
//                                16–64 chars — sync mode is default; pass
//                                { sync: false } for fire-and-forget)

Use it (script tag — no bundler)

<script src="https://unpkg.com/fingerprint-platform-sdk/dist/fp.js" async></script>
<script>
  window.addEventListener('load', async () => {
    window.FP.init({
      collectorUrl: 'https://fp.your-domain.com',
      projectKey: 'YOUR_API_KEY', // see «projectKey» in the table below
    });
    const r = await window.FP.identify({ event: 'pageview' });
    console.log(r);
  });
</script>

Auto-init via global config

<script>
  window.__FP_CONFIG__ = { collectorUrl: 'https://fp.your-domain.com' };
</script>
<script src="https://unpkg.com/fingerprint-platform-sdk/dist/fp.js" async></script>

init is called automatically as soon as the SDK loads.

API

init(config: FpConfig): FpSdk

| Field | Required | Description | | -------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | collectorUrl | ✅ | Origin where the platform's collector is reachable, e.g. https://fp.your-domain.com. The SDK appends /v1/pk and the (path-randomised) ingest endpoint. | | projectKey | ✅* | The api_key issued for your tenant — sent on every ingest as the X-Project-Key header. This is the random opaque string the platform gave you when the project was provisioned (not the human-readable project id used in dashboard URLs). Omit only if your collector deployment exposes a permissive default project; otherwise every request returns 401 unknown_project. | | serverPublicKeyB64 | | Pre-shared public key (base64). Skips the bootstrap /v1/pk round-trip. Useful when you control deploys end-to-end. | | sdkVersion | | Defaults to the package version. Override for A/B-testing custom builds. |

identify(opts?: IdentifyOptions): Promise<IngestResponse>

| Field | Type | Description | | -------------- | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | event | 'pageview' \| 'login' \| 'signup' \| 'action' \| 'heartbeat' | Defaults to 'pageview'. | | linkedId | string | Optional. Integrator-supplied identifier for the user — typically your authenticated user id, an order number, or a session token. Lets the platform tie a device fingerprint (visitorId) back to your account model. The userId parameter is a deprecated alias kept for pre-0.1.4 callers. | | sync | boolean | Default true. The collector blocks the response until scoring finishes (~50–150 ms). Pass false for passive page-view tracking — see «Sync vs async» below. | | preferBeacon | boolean | When true, prefers navigator.sendBeacon (fire-and-forget, fast). Implies sync: false. Default false. |

Sync vs async

fp.identify() defaults to synchronous scoring: the HTTP response body carries the real visitorId and suspectScore once the scoring worker has finished. This is the right default for click-driven flows (login submit, checkout) where the integrator wants to act on the verdict inline.

For passive page-views or analytics where you don't need the verdict on the wire, opt out:

fp.identify({ event: 'pageview', sync: false });
// → returns { visitorId: 'pending', suspectScore: -1 } immediately;
//   real verdict is delivered via your webhook or pulled later via
//   GET /v1/result/<eventId>.

If the scoring worker doesn't publish a result within SYNC_TIMEOUT_MS (default 2s on the collector), sync calls fall back to the same pending response — the request is never lost, you just don't see the verdict on this RPC.

Returns the IngestResponse:

interface IngestResponse {
  v: string;
  eventId: string; // 6-char id, returned immediately
  result: 'ok' | 'retry' | 'reject';
  visitorId: string; // 16–64 char alphanumeric device id, or "pending" while scoring is async
  userId?: string; // echoed
  suspectScore: number; // 0–100, or -1 while pending
  external: {
    flags?: string[];
    linkedVisitors?: string[];
  };
}

What gets sent

The SDK collects, then encrypts, the following before posting:

  • Hardware: User-Agent, Client Hints, screen, hardware concurrency, device memory.
  • Locale: timezone, language, languages list.
  • Rendering hashes: canvas, WebGL, audio (each rendered 3× and the majority hash kept for stability).
  • Fonts & plugins.
  • Permissions map (notifications/geolocation/camera/…).
  • WebRTC local IP (for VPN detection on the server).
  • Behavioral aggregates: mouse velocity, keyboard hold/gap timings, scroll inertia.
  • Lie detection: navigator.webdriver, Function.prototype.toString integrity, iframe / worker comparisons.

The full schema lives in @fp/shared-types.

What gets received from the request

Outside what the SDK sends, the collector also reads (browser cannot fake):

  • Real source IP (or X-Forwarded-For behind nginx / Caddy).
  • TLS JA4 fingerprint when the request goes through the platform's TLS edge.
  • HTTP/2 SETTINGS frame order (Akamai-style).
  • HTTP header order — distinguishes browsers from python-requests / axios / Go net/http.

Bundle size

| Format | Size | | ----------------------------------------------- | ------------------------ | | dist/fp.js (IIFE, terser) | ~60 KB / ~22 KB gzipped | | dist/fp.obf.js (IIFE + javascript-obfuscator) | ~300 KB / ~80 KB gzipped | | dist/index.mjs (ESM, for bundler consumers) | ~60 KB / ~22 KB gzipped |

Building from source (for platform maintainers)

This package is published from the Fingerprint Platform monorepo. Two CI-controlled knobs harden the production bundle:

| Env var | Effect | | ------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | SDK_DOMAIN_LOCK="host1,host2" | Bakes a hostname allow-list into fp.obf.js. Loaded from any other origin → SDK self-redirects to about:blank. | | SDK_HARDEN=true | Enables selfDefending, debugProtection (DevTools-detection debugger loop), and disableConsoleOutput. |

SDK_DOMAIN_LOCK="fp.example.com" SDK_HARDEN=true \
  pnpm --filter fingerprint-platform-sdk build

To publish:

cd apps/sdk-browser
pnpm version patch          # bump (or minor / major)
pnpm publish --dry-run      # inspect tarball — verifies no .tsbuildinfo /
                            # .d.ts.map / source files leak
pnpm publish --access public

Use pnpm publish (not npm publish) — the workspace devDependencies are written as workspace:* in package.json. pnpm rewrites those to real published versions on publish; npm would publish the literal workspace:* and the package would be uninstallable.

prepublishOnly regenerates dist/ (ESM + CJS + IIFE + types) before each publish; nothing leaks the workspace's @fp/* internals — vite bundles them inline (see vite.config.tsexternal: []).

License

MIT — see LICENSE.