npm package: @stevandric/identity-js
Description: Visitor fingerprinting, identification & analytics — drop-in script or npm package
Author: Stevan Andric
Latest version: 0.2.12
Deprecated: This package has moved to @identityjs/tracker

# identity-js

Visitor intelligence platform with browser fingerprinting, behavioral analytics, and real-time insights.

**Dashboard & Docs: [www.identity-js.com](https://www.identity-js.com)**

- **40+ fingerprint signals** — canvas, WebGL, audio, fonts, speech voices, math quirks, screen, CPU, timezone
- **11 behavioral trackers** — dead clicks, phantom clicks, rage clicks, form abandonment, frustration scoring, reading behavior, input hesitation, error tracking, text copy, session replay
- **Persistent visitor ID** — survives cookie clears via fingerprint reconciliation
- **Bot detection** — 0-100 score with reasons, no ML required
- **Custom events** — `IdentityJS.track('signup', { plan: 'pro' })`
- **SPA support** — automatic page journey via pushState/popstate
- **Cookie-free** — no cookies, no consent banners
- **Zero runtime dependencies** — 29 KB gzipped
- **Fully managed** — no servers to set up, everything runs on identity-js.com

---

## Quick start

### npm

```bash
npm install @stevandric/identity-js
```

```js
import IdentityJS from '@stevandric/identity-js';

const visitor = await IdentityJS.init({
  apiKey: 'pk_live_YOUR_KEY',
});

console.log(visitor.visitorId); // e.g. "a3f2b1c4d5e6-k9m2"
```

### Script tag (CDN)

```html
<script src="https://cdn.jsdelivr.net/npm/@stevandric/identity-js/dist/identity.min.js"></script>
<script>
  IdentityJS.init({
    apiKey: 'pk_live_YOUR_KEY',
  });
</script>
```

Get your API key at [www.identity-js.com/dashboard](https://www.identity-js.com/dashboard).

---

## API

### `IdentityJS.init(options?)`

Returns `Promise<VisitorObject>`.

| Option | Type | Default | Description |
|---|---|---|---|
| `apiKey` | `string` | — | Project API key (`pk_live_...`) from your dashboard |
| `endpoint` | `string` | `https://www.identity-js.com/api/ping` | API endpoint (no need to change this) |
| `onReady` | `function` | — | Called with the visitor object once ready |
| `trackBehavior` | `boolean` | `true` | Track clicks, scrolls, keystrokes |
| `trackSpaNavigation` | `boolean` | `true` | Auto-track route changes |
| `sendOnLoad` | `boolean` | `true` | Send fingerprint on page load |
| `sendOnUnload` | `boolean` | `true` | Send session data on page close |

### `VisitorObject`

```ts
{
  visitorId: string;        // Persistent ID (localStorage + cookie)
  sessionId: string;        // Per-tab session ID
  isNewVisitor: boolean;    // True on first ever visit
  fingerprintHash: string;  // Hash of stable signals
  signals: object;          // Full fingerprint signal set

  track(name: string, data?: object): void;  // Send custom event
  getBehavior(): object;                     // Live behavioral snapshot
  flush(): void;                             // Flush session data immediately
  destroy(): void;                           // Remove event listeners
}
```

### `IdentityJS.track(name, data?)`

Queue-safe global track — works even before `init()` resolves.

```js
IdentityJS.track('added_to_cart', { productId: 'abc', price: 29.99 });

// Works before init too:
IdentityJS.track('page_loaded');
IdentityJS.init({ apiKey: 'pk_live_...' }); // queued event flushed after init
```

---

## Examples

### React

```jsx
import { useEffect } from 'react';
import IdentityJS from '@stevandric/identity-js';

function App() {
  useEffect(() => {
    IdentityJS.init({
      apiKey: process.env.REACT_APP_IDENTITY_KEY,
      onReady: (v) => console.log('visitor', v.visitorId),
    });
  }, []);

  return <div />;
}
```

### Next.js

```js
// app/layout.js or pages/_app.js
import IdentityJS from '@stevandric/identity-js';

if (typeof window !== 'undefined') {
  IdentityJS.init({ apiKey: process.env.NEXT_PUBLIC_IDENTITY_KEY });
}
```

### Custom events

```js
const visitor = await IdentityJS.init({ apiKey: 'pk_live_...' });

document.querySelector('#buy').addEventListener('click', () => {
  visitor.track('purchase_clicked', { plan: 'pro', price: 49 });
});

document.querySelector('form').addEventListener('submit', () => {
  visitor.track('form_submitted', { form: 'signup' });
});
```

---

## What gets tracked automatically

Once you call `init()`, these trackers start automatically:

| Tracker | What it detects |
|---|---|
| **Fingerprinting** | 40+ browser signals combined into a stable hash |
| **Dead Clicks** | Clicks on non-interactive elements |
| **Phantom Clicks** | Clicks on elements that look clickable but aren't |
| **Rage Clicks** | Rapid frustrated clicking |
| **Form Abandonment** | Forms started but not submitted |
| **Input Hesitation** | Time between focusing a field and first keystroke |
| **Reading Behavior** | Scroll velocity classification (reading/skimming/scanning) |
| **Frustration Score** | Weighted composite from rage clicks, dead clicks, errors, form abandons |
| **Error Tracking** | JS exceptions, promise rejections, console errors |
| **Text Copy** | When users copy text from your page |
| **Session Replay** | Lightweight event-based session recording |

---

## License

MIT