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

@badgerlytics/sdk

v1.0.2

Published

Badgerlytics SDK — SSR experiment assignment and React helpers for the tracking script.

Readme

@badgerlytics/sdk

Package for users of Badgerlytics, the AI-Powered Analytics and A/B Testing Platform. More info →. COMING SOON!

Official SDK — server-side experiment assignment (no flash of wrong content) and React helpers around the browser tracking script.

Install

npm install @badgerlytics/sdk

Install the peer dependency for the integration you use:

| Import path | Peer dependency | |-------------|-----------------| | @badgerlytics/sdk/nextjs | next >= 13.4 | | @badgerlytics/sdk/react | react >= 18 | | @badgerlytics/sdk/remix | react-router >= 7 or @remix-run/node >= 2 | | @badgerlytics/sdk/nuxt | nuxt >= 3 | | @badgerlytics/sdk/astro | astro >= 4 |

You also need the tracking script on your pages (see React below). SSR middleware and the script share the same _bai_visitor / _bai_flags / _bai_traits cookies.

TypeScript

Type definitions ship with the package — no extra @types install and no typescript dependency required in your app.

import { createBadgerlyticsMiddleware, getVariation } from '@badgerlytics/sdk/nextjs';
import { useVariation } from '@badgerlytics/sdk/react';

Plain JavaScript projects are unchanged; bundlers and Node resolve the same .js entry points.

Pre-release builds

To try a build before it lands on latest:

npm install @badgerlytics/sdk@test

Middleware parity

All four framework entry points share the same assignment engine (runAssignment). Each export is listed below.

Shared exports (every middleware package)

| Export | Description | |--------|-------------| | createBadgerlyticsMiddleware(options) | Framework middleware factory | | getVariation(source, flagKey, fallback?) | Variation from forwarded x-bai-* headers | | getAssignments(source) | Full { flagKey: { i, v } } map from headers | | getVisitorId(source) | Visitor id from x-bai-visitor | | getTraits(source) | Trait bag from x-bai-traits | | isFlagEnabled(source, flagKey) | true when assigned to v1 (control is off) | | isVariation(source, flagKey, expected) | Compare variation key | | setTraitsOnResponse(response, traits) | Set/clear _bai_traits cookie (see traits) | | runBadgerlyticsAssignment(request, options) | Manual assignment for one Request | | readVisitorFromRequest / readTraitsFromRequest / readFlagsFromRequest | Read cookies from a Web Request | | writeAssignmentCookiesOnResponse(response, opts) | Append visitor + flags Set-Cookie on a Web Response | | buildTraitsSetCookieHeader(traits, opts) | Low-level Set-Cookie string | | Cookie/header constants | VISITOR_COOKIE, FLAGS_COOKIE, TRAITS_COOKIE, x-bai-* headers |

Framework-specific helpers

| Package | Read assignments in SSR | Set traits on login | |---------|-------------------------|---------------------| | nextjs | getVariation(req \| headers(), …) | setTraitsOnResponse(NextResponse \| Response \| pages/api res, …) | | remix | getVariation(request, …) after middleware forwards headers | setTraitsOnResponse(action Response, …) | | nuxt | getVariationFromEvent(event, …) from event.context.badgerlytics | setTraitsOnEvent(event, …) | | astro | getVariationFromLocals(Astro.locals, …) | setTraitsOnResponse(route Handler Response, …) |

| Package | Manual assignment without global middleware | |---------|---------------------------------------------| | nextjs / remix / astro | runBadgerlyticsAssignment(request, options) | | nuxt | runBadgerlyticsAssignmentForEvent(event, options) |

nextjs-only: writeAssignmentCookies(NextResponse, opts) — sets visitor + flags via NextResponse.cookies (used by the built-in middleware).

astro / nuxt locals & event helpers: getAssignmentsFromLocals, getTraitsFromLocals, getVisitorIdFromLocals, isFlagEnabledFromLocals, and the Nuxt mirrors getAssignmentsFromEvent, getTraitsFromEvent, setTraitsOnEvent, etc.

Fundamental incompatibilities

  1. Where SSR reads assignments

    • Next.js and Remix forward x-bai-assignments (and related headers) on the request. Use getVariation(req) or getVariation(request).
    • Nuxt stores assignment on event.context.badgerlytics (middleware also patches event.node.req.headers). Prefer getVariationFromEvent(event) in server routes.
    • Astro does not replace the incoming Request; assignments live on Astro.locals.badgerlytics. Use getVariationFromLocals(Astro.locals)not getVariation(Astro.request).
  2. Setting traits

    • setTraitsOnResponse works on Web Response, Next.js NextResponse, and legacy pages/api res (setHeader).
    • Nuxt server routes should use setTraitsOnEvent(event, traits).
  3. React (@badgerlytics/sdk/react) is client-only: useSetTraits() calls window.badgerlytics.setTraits(), which re-evaluates enrollment immediately — flag hooks (useVariation, useIsFlagEnabled) re-render in place once the returned promise resolves. Server-rendered output only picks the traits up on the next request unless you also set _bai_traits on the server.

  4. Edge vs Node: Middleware runs wherever your framework runs it (Next Edge, Nitro, etc.). The property CDN embed must be reachable from that runtime.


Next.js

Server-side assignment via middleware, then read variants in pages or server components.

1. Middleware

Create middleware.js at your project root:

import { createBadgerlyticsMiddleware } from '@badgerlytics/sdk/nextjs';

export const middleware = createBadgerlyticsMiddleware({
  propertyId: 'your-property-id',
});

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};

2. Read assignments

Pages router (getServerSideProps):

import { getVariation } from '@badgerlytics/sdk/nextjs';

export async function getServerSideProps({ req }) {
  return {
    props: {
      heroVariation: getVariation(req, 'hero_test', 'control'),
    },
  };
}

App router (server components):

import { headers } from 'next/headers';
import { getVariation } from '@badgerlytics/sdk/nextjs';

export default async function Page() {
  const h = await headers();
  const variation = getVariation(h, 'hero_test', 'control');
  return variation === 'v1' ? <HeroB /> : <HeroA />;
}

3. Audience traits on the server

import { setTraitsOnResponse } from '@badgerlytics/sdk/nextjs';

// App Router Route Handler
export async function POST(request) {
  const user = await authenticate(request);
  const response = Response.json({ ok: true });
  setTraitsOnResponse(response, { signed_in: true, plan: user.plan });
  return response;
}

// Legacy pages/api — Node `res` is supported
export default function handler(req, res) {
  setTraitsOnResponse(res, { signed_in: true });
  res.status(200).json({ ok: true });
}

4. Tracking script

<script>window.badgerlyticsConfig = { propertyId: 'your-property-id' };</script>
<script src="https://cdn.badgerlytics.com/scripts/badgerlytics.min.js" defer></script>

React

Client-side hooks and context around window.badgerlytics. Pass config to BadgerlyticsProvider to set window.badgerlyticsConfig and inject the tracking script — no separate embed component required.

import { BadgerlyticsProvider, useVariation, useIsFlagEnabled, useSetTraits } from '@badgerlytics/sdk/react';

export default function App() {
  return (
    <BadgerlyticsProvider config={{ propertyId: 'your-property-id' }}>
      <Home />
    </BadgerlyticsProvider>
  );
}

| Prop | Description | |------|-------------| | config | badgerlyticsConfig (at minimum propertyId). When set, the script loads automatically. | | scriptSrc | Optional full URL to badgerlytics.min.js (default: production CDN). | | autoLoad | Default true when config is passed. Set false if the script is already in HTML. |

| Export | Description | |--------|-------------| | BadgerlyticsProvider | Loads script (when config is set), waits for init, exposes context | | ensureTrackingScript({ config, scriptSrc }) | Imperative load without React | | useVariation(flagKey, fallback?) | Current variation after script loads | | useIsFlagEnabled(flagKey) | true when assigned to v1 | | useSetTraits() | Calls badgerlytics.setTraits(...) in the browser |

If you already load the script via <script> tags, omit config or use autoLoad={false} and wrap with <BadgerlyticsProvider autoLoad={false}>.

Hooks wait for the tracker automatically (via callWhenTrackerReady), so you never need to poll for window.badgerlytics yourself. The tracking script also buffers tracking calls (e.g. trackConversion) made while its configuration is still loading and sends them as one batch once it's ready — calls are only lost if the script tag itself hasn't executed yet, which the provider's injection ordering prevents.


Remix / React Router

import { createBadgerlyticsMiddleware, getVariation, setTraitsOnResponse } from '@badgerlytics/sdk/remix';

export const middleware = [
  createBadgerlyticsMiddleware({ propertyId: 'your-property-id' }),
];

In loaders:

export async function loader({ request }) {
  return { hero: getVariation(request, 'hero_test', 'control') };
}

In a login action:

export async function action({ request }) {
  const user = await login(request);
  const response = redirect('/app');
  setTraitsOnResponse(response, { signed_in: true, plan: user.plan });
  return response;
}

Nuxt

server/middleware/badgerlytics.ts:

import { createBadgerlyticsMiddleware } from '@badgerlytics/sdk/nuxt';

export default createBadgerlyticsMiddleware({
  propertyId: 'your-property-id',
});

In server routes:

import { getVariationFromEvent, setTraitsOnEvent } from '@badgerlytics/sdk/nuxt';

export default defineEventHandler((event) => {
  const hero = getVariationFromEvent(event, 'hero_test', 'control');
  return { hero };
});

// Login handler
export default defineEventHandler(async (event) => {
  const user = await login(event);
  setTraitsOnEvent(event, { signed_in: true, plan: user.plan });
  return { ok: true };
});

Astro

src/middleware.js:

import { defineMiddleware } from 'astro:middleware';
import { createBadgerlyticsMiddleware } from '@badgerlytics/sdk/astro';

export const onRequest = defineMiddleware(
  createBadgerlyticsMiddleware({ propertyId: 'your-property-id' })
);

In pages (use locals, not Astro.request headers):

---
import { getVariationFromLocals, setTraitsOnResponse } from '@badgerlytics/sdk/astro';
const hero = getVariationFromLocals(Astro.locals, 'hero_test', 'control');
---
{hero === 'v1' ? <HeroB /> : <HeroA />}

For Astro API routes that return a Response, setTraitsOnResponse works the same as Remix.


How SSR assignment works

Browser ──▶ Your framework middleware (@badgerlytics/sdk)
                │ read cookies → fetch CDN embed → bucket visitor
                │ Set-Cookie + forward x-bai-* headers (or locals / event.context)
                ▼
            SSR reads getVariation() / getVariationFromLocals() / getVariationFromEvent()
                ▼
            HTML + cookies ──▶ Browser tracking script

Bucketing matches the tracking script exactly for the same (visitorId, flagKey, iteration).