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

unshared-frontend-sdk

v2.0.2

Published

Browser SDK for Unshared Labs — routes fingerprint events through the customer's own backend

Readme

unshared-frontend-sdk

Browser SDK for Unshared Labs — collects a device fingerprint and sends it through your own backend. Your API key never touches the browser.


Install

npm install unshared-frontend-sdk

Or via CDN (no build step) — see CDN / UMD usage below for the complete example.


Quick Start

import { UnsharedLabsBrowser } from 'unshared-frontend-sdk';

// Same-origin (frontend served by the same backend): omit baseUrl
const client = new UnsharedLabsBrowser({});

// Cross-origin (separate domains): set baseUrl via env var
// const client = new UnsharedLabsBrowser({ baseUrl: process.env.BACKEND_URL });

// On page load — fire and forget
const fingerprint = await client.collect();
client.submitFingerprintEvent(fingerprint, { userId: currentUser?.id });

That's it. The SDK handles retries, timeouts, and errors silently.

Using this SDK alongside the Node unsharedBoundToUser middleware (Tier 1)? The middleware also auto-injects an inline fingerprint script into your HTML. That is expected — the two submitters share a client-side dedup guard (window.__unshared) and emit one event per (user, route). You do not need to turn injection off. See Fingerprint Collection: what loads what, who submits when.


Configuration

new UnsharedLabsBrowser({
  baseUrl:    process.env.BACKEND_URL, // optional — omit for same-origin
  maxRetries: 3,                       // optional, default: 3
  timeout:    30_000,                  // optional, default: 30s per attempt
});

| Option | Type | Default | Description | |--------|------|---------|-------------| | baseUrl | string | "" (same-origin) | Base URL of your backend. Omit if your frontend and backend share the same domain. | | maxRetries | number | 3 | How many times to retry on failure | | timeout | number | 30000 | Per-attempt timeout in milliseconds |


Methods

collect()

Collect a browser fingerprint. Returns a FingerprintWireFormat object ready to pass to submitFingerprintEvent.

const fingerprint = await client.collect();

submitFingerprintEvent(fingerprint, opts?)

Send the fingerprint to your backend's /unshared/submit-fingerprint-event route. Fire-and-forget — you don't need to await this unless you want delivery confirmation.

// Fire and forget (recommended)
client.submitFingerprintEvent(fingerprint, {
  userId:    currentUser?.id,  // optional
  eventType: 'page_view',      // optional
});

// Awaited (if you need delivery confirmation)
const result = await client.submitFingerprintEvent(fingerprint);
if (!result.success) {
  console.warn('Delivery failed:', result.error?.message);
}

Options:

| Option | Type | Description | |--------|------|-------------| | userId | string | ID of the logged-in user | | eventType | string | Event label (e.g. "page_view", "login") |


Backend requirement

The SDK sends fingerprints to {baseUrl}/unshared/submit-fingerprint-event. Your backend must handle this route. If you're using unshared-clientjs-sdk, the createUnsharedMiddleware sets this up automatically:

// On your Express backend
import express from 'express';
import { UnsharedLabsClient } from 'unshared-clientjs-sdk';
import { createUnsharedMiddleware } from 'unshared-clientjs-sdk/middleware';

const app = express();
const unshared = new UnsharedLabsClient({ apiKey: process.env.UNSHARED_API_KEY });

app.use(express.json());
app.use(createUnsharedMiddleware(unshared));

Error handling

All methods follow a never-throw contract. Errors are always returned as a result object — the SDK will not throw or reject under any circumstances.

const result = await client.submitFingerprintEvent(fingerprint);

// result.success === false means delivery failed
// result.error.code === 'DELIVERY_FAILED'

Retries happen automatically on network errors, timeouts, and server errors (5xx). Client errors (4xx) are not retried.


CDN / UMD usage

The UMD bundle exposes a window.UnsharedLabsBrowser namespace object. Destructure the class from it first:

<script src="https://unpkg.com/[email protected]/dist/index.umd.js"></script>
<script>
  const { UnsharedLabsBrowser } = window.UnsharedLabsBrowser;

  // Omit baseUrl for same-origin. Set it for cross-origin: { baseUrl: 'https://api.example.com' }
  const client = new UnsharedLabsBrowser({});

  client.collect().then(fp => {
    client.submitFingerprintEvent(fp);
  });
</script>