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

@fire-signal/react-sdk

v0.2.0

Published

React SDK for Fire-Signal platform features

Readme

@fire-signal/react-sdk

React SDK for Fire Platform feature flags and client-side telemetry.

What this package is for

Use this package in React apps when you need:

  • Feature flag checks in UI (useFlag, useVariantValue, useFlagDecision, FireFlag)
  • Event tracking from user actions (useTrack)
  • Customer identification (useIdentify)

Do not use this package for backend jobs, queues, cron, or server automations.


Security keys (for end users)

  • fp_pub_* is a publishable key (safe for frontend)
  • Use your publishable/client key in frontend apps (NEXT_PUBLIC_* env)
  • Never put your server/private/live secret key in browser code

Rule of thumb: if key grants write/admin-level API access, keep it server-only.


Installation

npm install @fire-signal/react-sdk
pnpm add @fire-signal/react-sdk
yarn add @fire-signal/react-sdk
bun add @fire-signal/react-sdk

Requirements:

  • Node.js 18+
  • React 18+

60-second setup (Next.js App Router)

1) Create a client provider

// app/providers.tsx
'use client';

import { FireProvider } from '@fire-signal/react-sdk';

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <FireProvider
      publishableKey={process.env.NEXT_PUBLIC_FIRE_PUBLISHABLE_KEY!}
      host={process.env.NEXT_PUBLIC_API_URL} // optional (self-host/local)
      user={{ id: 'user_123' }}
      traits={{ plan: 'PLUS', locale: 'en-US' }}
    >
      {children}
    </FireProvider>
  );
}

2) Mount it in layout

// app/layout.tsx
import { Providers } from './providers';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

Which flag hook should I use?

If you want one default for most users, use useFlag first.

  • Use useFlag when you only care about on/off (enabled)
  • Use useVariantValue<T> when you need the flag value directly (promo code, number, JSON config)
  • Use useFlagDecision<T> when you need full decision metadata for debugging/analytics

So yes: useFlag is the easiest default mental model.


API: parameters and return values

Shared types

type FlagsContext = {
  user?: { id: string; [k: string]: unknown };
  company?: { id: string; [k: string]: unknown };
  traits?: Record<string, unknown>;
};

type UseFlagOptions = {
  enabled?: boolean;   // default: true
  refreshMs?: number;  // no auto-refresh when omitted/0
};

useFlag

useFlag(flag: string, context?: FlagsContext, options?: UseFlagOptions)

Returns:

  • enabled: boolean
  • loading: boolean
  • error?: Error
  • decision?: FlagDecision
  • refetch(): Promise<void>

Example:

const checkoutFlow = useFlag('checkout.new-flow');
if (checkoutFlow.loading) return null;
return checkoutFlow.enabled ? <NewCheckout /> : <ClassicCheckout />;

useVariantValue<T>

useVariantValue<T>(
  flag: string,
  context?: FlagsContext,
  fallback?: T | null,
  options?: UseFlagOptions
)

Returns:

  • value: T | null | undefined (or your fallback)
  • enabled: boolean
  • loading: boolean
  • error?: Error
  • decision?: FlagDecision<T>
  • refetch(): Promise<void>

Example:

const promo = useVariantValue<string>('checkout.promocode', {}, null);
return promo.enabled && promo.value ? <p>Promo: {promo.value}</p> : null;

useFlagDecision<T>

useFlagDecision<T>(flag: string, context?: FlagsContext, options?: UseFlagOptions)

Use when you need the whole decision object (reason, variantKey, fetchedAt, etc).

Example:

const d = useFlagDecision('checkout.new-flow', { traits: { country: 'BR' } });
if (d.loading) return null;
return <pre>{JSON.stringify(d.decision, null, 2)}</pre>;

Automatic refresh (refreshMs) explained

refreshMs is polling interval in milliseconds.

  • 10_000 means 10 seconds (_ is just numeric separator in JS/TS)
  • hook calls refetch() automatically every interval
  • useful when flags can change while user stays on page

Example:

const promo = useVariantValue<string>(
  'checkout.promocode',
  {},
  null,
  { refreshMs: 10_000 }
);

If you do not need polling, omit refreshMs and call refetch() only when needed.


Better identify + track example

'use client';

import { useIdentify, useTrack } from '@fire-signal/react-sdk';

export function CompleteCheckoutButton({
  userId,
  email,
  workspaceId,
  amount,
}: {
  userId: string;
  email: string;
  workspaceId: string;
  amount: number;
}) {
  const identify = useIdentify();
  const track = useTrack();

  const onClick = async () => {
    // 1) keep identity up to date
    await identify(userId, {
      email,
      plan: 'PLUS',
      workspaceId,
    });

    // 2) track action with explicit event properties
    await track('checkout.completed', {
      user: { id: userId },
      properties: {
        amount,
        currency: 'USD',
        workspaceId,
      },
    });
  };

  return <button onClick={onClick}>Complete checkout</button>;
}

Why this is better:

  • identifies user first
  • sends business properties in event payload
  • keeps event names explicit and consistent

FireProvider options

type FireProviderProps = {
  publishableKey: string;
  host?: string;
  strictPlatformProvider?: boolean;
  user?: { id: string; [k: string]: unknown };
  company?: { id: string; [k: string]: unknown };
  traits?: Record<string, unknown>;
};

Behavior of strictPlatformProvider:

  • false (default): evaluation failures return disabled decision with reason
  • true: evaluation failures throw and appear in hook error

Recommended:

  • true in development (faster setup debugging)
  • false in production (safe fallback behavior)

Runtime behavior notes

  • Decision fetch runs on mount for each flag + context key
  • Decisions are cached in memory in current runtime/tab
  • In-flight duplicate requests are deduplicated
  • refetch() invalidates cache for that key and fetches again
  • enabled: false disables evaluation for that hook call

Troubleshooting

"I enabled a flag but UI did not update"

  • No refreshMs: hook evaluates on mount, then stays cached
  • Call refetch() manually or enable polling with refreshMs

"Flag is always disabled"

  • verify publishableKey is correct (fp_pub_*)
  • verify component is inside FireProvider
  • verify host points to correct API
  • verify flag is enabled in correct project/environment

"Hook is always loading"

  • check browser network errors/CORS
  • check API host reachability
  • try strictPlatformProvider={true} to expose failures via error

Next.js hook/hydration issues

  • mark hook components with 'use client'
  • keep FireProvider in a client wrapper component

Vite example

import React from 'react';
import ReactDOM from 'react-dom/client';
import { FireProvider } from '@fire-signal/react-sdk';
import App from './App';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <FireProvider
      publishableKey={import.meta.env.VITE_FIRE_PUBLISHABLE_KEY}
      host={import.meta.env.VITE_FIRE_API_URL}
      user={{ id: 'user_123' }}
      traits={{ plan: 'PLUS' }}
    >
      <App />
    </FireProvider>
  </React.StrictMode>
);