# JavaScript SDK

> Use Revfaro's typed browser tracker in JavaScript or TypeScript applications, with cookie or cookieless tracking and lifecycle cleanup.

**In short:** The revfaro browser SDK is an optional alternative to the script tag. It provides typed initialization, automatic pageviews, goals, identify and teardown without runtime dependencies, with a dedicated cookieless entry. Initialize only in the browser and copy the website ID and endpoint from Setup.

## Package availability

The official `revfaro` package is available on npm. Install it in your app, or use the
[script installation](https://revfaro.com/docs/install/) without a build tool. Both methods use the same tracking engine.

The SDK uses the MIT license and has no runtime dependencies. It is a browser tracker installed with
npm, not a Node.js server event client. For server-side revenue, use the [Payments API](https://revfaro.com/docs/payments-api/).

## Start tracking

Choose **npm package** under **Settings → Setup**. The snippet includes your website ID and collection
endpoint. Install the package in your app:

```sh
npm install revfaro
```

Initialize once from your browser entry point:

```ts
import { init } from 'revfaro';

const tracker = init({
  siteId: 'YOUR_SITE_ID',
  endpoint: 'https://revfaro.com/api/event',
});

// Keep this instance for goals, identity and unmount cleanup.
```

Use the npm tracker or the hosted script once per page. The npm API does not create `window.revfaro`;
keep the returned instance to record actions and clean up. Different tracking configurations can
record separate events, so remove the script tag when switching to npm.

Pageviews and History API navigation are automatic. Hash-only navigation does not add a pageview.
HTML [goal attributes](https://revfaro.com/docs/goals/), outbound clicks and visible engagement work as with the hosted script.

For a router that records views itself, use `autoTrack: false`, then call `tracker.pageview()` after each
route change. Each manual call records a view of the current URL, including repeated calls.

## Cookieless tracking

```ts
import { init } from 'revfaro/cookieless';

const tracker = init({
  siteId: 'YOUR_SITE_ID',
  endpoint: 'https://revfaro.com/api/event',
});
```

The dedicated entry excludes cookie identity code. It follows the same [cookieless rules](https://revfaro.com/docs/cookieless/)
as the hosted script. `tracker.attribution()` returns `{}`. The explicit `rf_ignore` opt-out flag remains
available; it is the only local-storage use. The main entry also accepts `mode: 'cookieless'`.

## Server rendering and cleanup

Importing the SDK during server rendering is safe. Calling `init()` without a browser returns an inactive
instance and sends nothing. Initialize a new instance in your framework's browser mount hook.

For React or Next.js, mount one client component in the root layout. Route changes are automatic;
do not add the current pathname to the effect dependencies or manually send every pageview.

```tsx
'use client';

import { useEffect } from 'react';
import { init } from 'revfaro';

export function Analytics() {
  useEffect(() => {
    const tracker = init({
      siteId: 'YOUR_SITE_ID',
      endpoint: 'https://revfaro.com/api/event',
    });
    return () => tracker.destroy();
  }, []);
  return null;
}
```

If other components send goals or identify visitors, share the initialized instance through a module
or your framework's context. The Setup snippet includes a shared `getTracker()` helper. Do not create
a tracker during a component render, and do not reuse an inactive server instance after hydration.

Matching `init()` calls share one tracking engine, while each caller receives its own handle. Call
`destroy()` on the handle you own when your integration unmounts. The last active handle removes the
engine's listeners, observers and timers and stops future retries, preserving other scripts' later
history wrappers. Cleanup does not erase cookies, retract requests already sent or send a final event.

The initial automatic pageview waits until the next task. This allows React Strict Mode to discard its
temporary mount without counting two visits. Goals, identity calls and navigation flush a pending
initial pageview first. Different site or tracking configurations are not deduplicated.

## Goals, identity and attribution

Call `tracker.goal('signup', { source: 'pricing' })` after a successful action. `tracker.track()` is an
alias for `goal()`. Use `tracker.identify({ user_id: 'customer-123' })` after sign-in to connect visits
to a known customer. Avoid sending passwords, API keys or other secrets as properties.

With SDK 0.1.1 or later, call `tracker.reset()` after logout or before identifying a different account.
In cookie mode this rotates both the visitor and session IDs, including the in-memory fallback when
cookies are blocked. It discards pending engagement and retries and refreshes existing checkout-link
metadata. Shared handles on the same cookie domain observe the new identity; other tabs detect changed
visitor cookies before their next send. Clear queued user-specific actions and synchronize authentication
across tabs in your application as well.

Reset keeps tracking active and does not send a pageview. When driving pageviews manually, record the
next view yourself. Already sent requests and previously collected data are not erased. `destroy()`
only releases a handle and does not rotate identity. In cookieless mode, `reset()` clears local timers
and engagement but cannot change the server-derived daily identity. Avoid identifying users in
cookieless mode when accounts on a shared browser must remain separate.

In cookie mode, `tracker.attribution()` returns `rf_visitor_id` and `rf_session_id`. Your checkout
integration can forward these as metadata using your payment provider's guide. The SDK never needs
your payment-provider secret. Cookieless mode returns an empty attribution object.

## Privacy and delivery

SDK 0.1.1 or later supports a strict query allowlist:

```ts
const tracker = init({
  siteId: 'YOUR_SITE_ID',
  endpoint: 'https://revfaro.com/api/event',
  allowedQueryParams: ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'],
});
```

Only these case-insensitive query names survive in every event's page URL and in its initial referrer.
Empty values are removed. Use `[]` to remove all query parameters; omit the option to retain the default
sensitive-name filter. Sensitive names such as `token` and `email` are always removed, even if listed.
Fragments and URL credentials are removed in either mode. Outbound destinations omit all query values.
Automatic pageviews ignore navigation that only changes removed parameters. Manual `pageview()` calls
still record one view each.

This does not sanitize URL path segments, custom goal properties or identity traits. Keep secrets out
of those values. An allowlist that removes payment return IDs prevents return-page revenue matching;
forward `tracker.attribution()` as provider metadata to preserve attribution.

For the hosted script, the equivalent is `data-allowed-query-params="utm_source,utm_campaign"`.
An empty attribute removes all query parameters. Use `window.revfaro('reset')` after logout.

Initialize only after your application's required consent decision. `autoTrack: false` disables
automatic pageviews but leaves other tracking enabled; it is not a consent switch. To stop tracking,
destroy every active instance. Existing cookies and already collected data are not removed.

Automated browsers, localhost and the explicit `rf_ignore` opt-out are ignored by default. The
`allowLocalhost` option enables browser sending for development; the collector still checks the site's
registered domain. Use a registered staging subdomain for end-to-end verification.

Events are delivered in the background. Fetch omits credentials; beacons follow the browser's cookie
policy and cannot override credentials. Network errors and server errors retry at most twice with
the same event ID; 4xx responses are not retried. Closing a tab, blockers or connectivity can still
lose events. A `202` response does not mean the event is already visible on the dashboard.

## First-party proxy

Use `endpoint: '/rf/event'` when your server forwards this path to Revfaro. Follow the [proxy guide](https://revfaro.com/docs/proxy/)
and keep the site's proxy secret on the server. Never put a site API key or proxy secret in browser code.

---

Source: https://revfaro.com/docs/javascript-sdk/ · Last updated 2026-11-02
