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-react-sdk

v2.3.0

Published

React SDK for Unshared Labs — provider + hooks over unshared-frontend-sdk with tag-manager-style publishable-key delivery

Readme

unshared-react-sdk

React SDK for Unshared Labs — account-sharing detection for React apps. A provider + hooks layer over unshared-frontend-sdk with automatic SPA route tracking and flagged-account handling.

Works the way Adobe Launch or BlueConic tags work: configure it with the publishable key we issue you and you're done — no backend integration required. (A proxy mode through your own backend is also supported.)

Pass publishableKey explicitly for direct mode or baseUrl explicitly for proxy mode. Omitting both defaults to same-origin proxy mode — unless you're consuming a client-specific build with a baked-in key (see "Packaged publishable key").


Install

npm install unshared-react-sdk

React 18+ is a peer dependency.

Not on npm yet? The current build is hosted at https://unshared-public.s3.amazonaws.com/react@18/ (index.mjs for bundlers, index.umd.js for script tags, index.d.ts for types) — see "Publishing React artifacts to S3" below.


Quick start (direct mode — recommended)

Wrap your app once, near the root, with the publishable key from your Unshared Labs dashboard:

import { UnsharedProvider } from 'unshared-react-sdk';

function Root() {
  const { user } = useAuth(); // your auth state

  return (
    <UnsharedProvider
      publishableKey="upk_your_key_here"
      user={user ? { userId: user.id, email: user.email } : null}
    >
      <App />
    </UnsharedProvider>
  );
}

That's everything:

  • A device fingerprint is collected once per tab and submitted when the user is identified.
  • SPA navigations (pushState, replaceState, popstate) are tracked automatically — Next.js, React Router, and custom routers all work without adapters.
  • Logout (usernull) clears all SDK state.
  • All failures are silent — the SDK never throws at runtime and never blocks your UI.

The publishable key is public by design: it can only submit events, never read data. Lock it to your domains by configuring allowed origins in your dashboard.


Identifying the user from deeper in the tree

If auth state isn't available where the provider mounts:

import { useUnshared } from 'unshared-react-sdk';

function LoginForm() {
  const { identify, logout } = useUnshared();

  async function onLoginSuccess(user) {
    identify({ userId: user.id, email: user.email });
  }

  async function onLogout() {
    logout();
  }
}

Reacting to flagged accounts

<UnsharedProvider
  publishableKey="upk_..."
  user={user}
  onFlagged={() => router.push('/account-suspended')}
>

onFlagged fires when any same-page fetch returns an account_flagged 403, or when an unshared:flagged CustomEvent is dispatched. The provider installs (and removes on unmount) a window.fetch interceptor to detect this.

Interstitial modal

Instead of (or alongside) onFlagged, the provider can render a server-driven interstitial modal — a JSON flow authored in the Unshared dashboard (e.g. email-OTP verification) fetched from the backend and rendered in a Shadow-DOM modal whose actions route back through the SDK's own verification calls.

<UnsharedProvider
  publishableKey="upk_..."
  user={user}
  enableInterstitial            // auto-show when flagged
  interstitialFlowType="email_verification"  // optional, this is the default
>

With enableInterstitial, the modal renders automatically on the same flagged signals as onFlagged (the 403 interceptor and the unshared:flagged event). To trigger it yourself instead, call useUnshared().showInterstitial(). The modal is removed on logout/unmount (client.destroy()).

This works in proxy mode as well: set baseUrl (instead of publishableKey) with the Node middleware mounted, and the modal is served and verified through your backend with the secret key — no publishable key in the frontend.


Props

| Prop | Type | Description | |------|------|-------------| | publishableKey | string | Direct mode. Publishable key (upk_…). Events go straight to the Unshared Labs platform. May only be omitted in client-specific builds with a baked-in key. | | apiUrl | string | Direct mode platform origin. Default https://api.unshared.ai. | | baseUrl | string | Proxy mode. Base URL of your backend running unshared-clientjs-sdk middleware. Use baseUrl="" for same-origin proxy mode. | | user | { userId, email, isPaidSubscriber? } \| null | The logged-in user. null while logged out; the transition to null clears SDK state. isPaidSubscriber: false means the SDK collects and submits nothing for this user — non-subscriber data is never received. | | onFlagged | () => void | Called when the platform flags the account. | | enableInterstitial | boolean | Direct mode: auto-render the interstitial modal when flagged (on the 403 interceptor or unshared:flagged event). Default false. | | interstitialFlowType | string | Flow type to fetch for the interstitial. Default email_verification. | | skipPaths | string[] | Path prefixes to never submit events for. | | includePathPrefix | string[] | If set, only these path prefixes submit events. | | sessionId | () => string \| undefined | Supply your own session ID (e.g. your auth/analytics session) instead of the SDK-generated UUID — it becomes the session_hash correlation key on every event. | | deviceId | () => string \| undefined | Supply your own device ID instead of the stable fingerprint hash. | | maxRetries | number | Delivery retries per request (default 3). | | timeout | number | Per-request timeout ms (default 30000). |

useUnshared()

Returns { client, identify, logout, showInterstitial }. client is the underlying UnsharedBrowser instance (null during SSR and before mount). showInterstitial(flowType?) fetches and renders the interstitial modal on demand (direct mode). Throws if called outside an <UnsharedProvider>.

In direct mode, client also carries the read/verification API — enough to build a fully frontend verify-wall:

const { client } = useUnshared();

const check = await client?.checkUser();
if (check?.data?.is_user_flagged) {
  await client.triggerEmailVerification();          // emails a 6-digit code
  // ...collect the code from the user...
  const result = await client.verify(enteredCode);  // → { verified: true }
}

triggerEmailVerification and verify are never retried by the SDK (each trigger sends a real email; verify attempts are budgeted server-side). Rate-limited responses include error.retryAfter seconds for countdown UIs.


Script tag / UMD (no bundler)

The published dist/index.umd.js is fully self-contained except for React itself — unshared-frontend-sdk (and its fingerprint engine) are bundled in. Load React 18's UMD first, then this package; the API lands on window.UnsharedReact:

<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unshared-public.s3.amazonaws.com/react@18/index.umd.js"></script>
<script>
  const { UnsharedProvider, useUnshared } = window.UnsharedReact;
  // Use exactly like the npm import, e.g. wrap your root render:
  // ReactDOM.createRoot(el).render(
  //   React.createElement(UnsharedProvider, { publishableKey: 'upk_...', user }, React.createElement(App))
  // );
</script>

React 19 ships no UMD builds — React 19 apps must use the npm path (which is unaffected; the package targets react >= 18 either way). Pages without React at all should use the plain browser SDK / /v2/sdk/{key}.js loader — or the standalone build below.

Standalone: true one-tag-and-done (niche — read the warnings)

dist/index.standalone.js (~200K min) bundles React, ReactDOM, and the SDK and auto-mounts an invisible provider from window.__unshared — no React on the page, no glue code.

When NOT to use it:

  • Never on a page that already runs React. The standalone's React renders an isolated, detached tree — it can't break the host's hooks/context (the trees never touch), but it also means useUnshared() from the host's own components cannot see this provider. React apps must use the npm/ESM path (peer-dependency React, single instance) or the UMD.
  • Pages with no React should usually prefer the browser tag loader (/v2/sdk/{key}.js) — it has no React dependency at all, is ~4× smaller, and does the same job. Reach for the standalone only when you specifically want the provider-style config surface (window.__unshared identity contract, identify/logout) on a React-less page.

React remains a peer dependency (react >= 18) for every module output (ESM/CJS/UMD) — the host app supplies the single React instance; only this opt-in standalone file carries its own copy.

<script>
  window.__unshared = {
    publishableKey: 'upk_...',                                // omit in client-keyed builds
    identity: () => window.Arc?.identity
      ? { userId: Arc.identity.uuid, email: Arc.identity.email, isPaidSubscriber: true }
      : null,
    onFlagged: () => location.assign('/account-suspended'),   // optional
    // sessionId, deviceId, skipPaths, includePathPrefix also accepted
  };
</script>
<script async src="https://unshared-public.s3.amazonaws.com/react@18/index.standalone.js"></script>

If auth resolves after the tag loads, call window.UnsharedReact.identify({ userId, email, isPaidSubscriber }) / window.UnsharedReact.logout().


SSR / Next.js

The provider is SSR-safe: the SDK is constructed in a mount effect and all browser APIs are touched client-side only. In the Next.js App Router, mount it in a "use client" layout component.


Proxy mode

If you prefer events to flow through your own backend (secret API key stays server-side, richer middleware features like verdict caching and email verification):

// Same-origin proxy mode:
<UnsharedProvider baseUrl="" user={user}>

// Cross-origin proxy mode:
<UnsharedProvider baseUrl="https://app.example.com" user={user}>

Your backend must run unshared-clientjs-sdk's createUnsharedMiddleware. See that package's docs.

Packaged publishable key

For client-specific builds, the React SDK can inherit a publishable key packaged into unshared-frontend-sdk:

  1. Explicit publishableKey prop.
  2. Build-time UNSHARED_PUBLISHABLE_API_KEY baked into unshared-frontend-sdk (client-specific builds only, e.g. the S3 flow).
  3. Otherwise no key — same-origin proxy mode. There is no hardcoded fallback; builds made without the env var (including every npm release) never carry a usable key.

Build distribution files in order (the React build bundles whatever browser dist it finds, so the browser build's env var determines whether a key is baked in):

UNSHARED_PUBLISHABLE_API_KEY=upk_test_or_client_key npm --prefix sdks/javascript/browser run build
npm --prefix sdks/javascript/frameworks/react run build

Passing baseUrl, including baseUrl="", keeps proxy mode and suppresses the packaged-key fallback.

Publishing React artifacts to S3

The canonical public distribution lives at s3://unshared-public/react@18/ (versioned per major):

https://unshared-public.s3.amazonaws.com/react@18/index.mjs           ← ESM (primary; bundlers / import maps)
https://unshared-public.s3.amazonaws.com/react@18/index.umd.js        ← UMD (script tag; page provides window.React)
https://unshared-public.s3.amazonaws.com/react@18/index.standalone.js ← one-tag: bundles React, auto-mounts from window.__unshared
https://unshared-public.s3.amazonaws.com/react@18/index.cjs           ← CommonJS
https://unshared-public.s3.amazonaws.com/react@18/index.d.ts          ← TypeScript types

Every file is self-contained except for React itself (unshared-frontend-sdk and the fingerprint engine are bundled at build time). The publish script uploads dist/index.mjs; pass the prefix as part of the bucket value to target the versioned path:

S3_BUCKET_NAME=unshared-public/react@18 npm --prefix sdks/javascript/frameworks/react run publish:s3

S3_BUCKET_NAME is intentionally deployment config rather than a hardcoded value in the script; the additional dist files (index.umd.js, index.cjs, index.d.ts) are uploaded alongside when a full set is wanted.

Before uploading, the script runs aws sts get-caller-identity. If credentials are missing or expired, it runs aws login and checks identity again. For SSO/profile setups, override the login command:

AWS_LOGIN_COMMAND="aws sso login --profile client-profile" \
S3_BUCKET_NAME=client-sdk-bucket \
npm --prefix sdks/javascript/frameworks/react run publish:s3

Force publishing is available for local or emergency use, but should not be used for normal releases:

FORCE_PUBLISH=1 \
S3_BUCKET_NAME=client-sdk-bucket \
npm --prefix sdks/javascript/frameworks/react run publish:s3

Only react remains an external dependency of the S3 artifacts — index.umd.js is the script-tag option (see "Script tag / UMD" above) and index.mjs suits bundlers or browser import maps that map react.


Releasing

unshared-frontend-sdk is a file: devDependency that gets bundled into every dist output (ESM/CJS/UMD) at build time — consumers only ever need React. No dependency rewriting is required at publish; release-js.yml (and the S3 publish script) build the browser package first so rollup can resolve it.