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

@zaraz/react

v1.0.0

Published

A powerful, type-safe React library for Cloudflare Zaraz Web API with Next.js optimizations

Downloads

4

Readme

@zaraz/react

A powerful, type-safe React library for Cloudflare Zaraz Web API with first-class Next.js support.

npm version TypeScript License: MIT

Features

  • 🎯 Type-Safe: Full TypeScript support with comprehensive type definitions
  • ⚡ Next.js Optimized: Built with Next.js in mind, handles SSR/SSG gracefully
  • 🪝 React Hooks: Modern hook-based API (useZaraz, useZarazEcommerce)
  • 🛒 E-commerce Ready: Dedicated e-commerce tracking with full event type safety
  • 🔧 Developer Experience: Excellent IntelliSense support and helpful error messages
  • 📦 Tree-Shakeable: Only bundle what you use
  • 🚀 Zero Dependencies: Minimal bundle size (peer deps: React only)
  • 🔍 Debug Mode: Built-in debug utilities for development
  • ♿ SSR Safe: Works seamlessly with server-side rendering

Installation

# Using bun (recommended)
bun add @zaraz/react

# Using npm
npm install @zaraz/react

# Using yarn
yarn add @zaraz/react

# Using pnpm
pnpm add @zaraz/react

Quick Start

1. Wrap your app with ZarazProvider

// app/layout.tsx (Next.js App Router)
import { ZarazProvider } from '@zaraz/react';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <ZarazProvider config={{ devMode: process.env.NODE_ENV === 'development' }}>
          {children}
        </ZarazProvider>
      </body>
    </html>
  );
}
// _app.tsx (Next.js Pages Router)
import { ZarazProvider } from '@zaraz/react';
import type { AppProps } from 'next/app';

export default function App({ Component, pageProps }: AppProps) {
  return (
    <ZarazProvider>
      <Component {...pageProps} />
    </ZarazProvider>
  );
}

2. Use the hooks in your components

'use client'; // Required for Next.js App Router

import { useZaraz } from '@zaraz/react';

export function SignUpButton() {
  const { track, isReady } = useZaraz();

  const handleSignUp = async () => {
    await track('sign_up_clicked', {
      source: 'landing_page',
      plan: 'pro',
    });

    // Your sign-up logic here
  };

  return (
    <button onClick={handleSignUp} disabled={!isReady}>
      Sign Up
    </button>
  );
}

Usage Examples

Basic Event Tracking

import { useZaraz } from '@zaraz/react';

function MyComponent() {
  const { track } = useZaraz();

  const handleButtonClick = () => {
    track('button_clicked', {
      label: 'Get Started',
      location: 'hero_section',
    });
  };

  return <button onClick={handleButtonClick}>Get Started</button>;
}

Setting Persistent Variables

import { useZaraz } from '@zaraz/react';
import { useEffect } from 'react';

function UserProfile({ user }) {
  const { set } = useZaraz();

  useEffect(() => {
    // Set user ID for all future events (persists across sessions)
    set('user_id', user.id, { scope: 'persist' });

    // Set temporary page-level variable
    set('page_type', 'profile', { scope: 'page' });

    // Unset a variable
    return () => {
      set('page_type', undefined);
    };
  }, [user.id, set]);

  return <div>Welcome, {user.name}</div>;
}

E-commerce Tracking

import { useZarazEcommerce } from '@zaraz/react';

function ProductPage({ product }) {
  const ecommerce = useZarazEcommerce();

  // Track product view
  useEffect(() => {
    ecommerce.viewProduct({
      product_id: product.id,
      name: product.name,
      price: product.price,
      brand: product.brand,
      category: product.category,
      currency: 'USD',
    });
  }, [product]);

  // Track add to cart
  const handleAddToCart = async () => {
    await ecommerce.addProduct({
      product_id: product.id,
      name: product.name,
      price: product.price,
      quantity: 1,
      currency: 'USD',
    });

    // Add to cart logic...
  };

  return (
    <div>
      <h1>{product.name}</h1>
      <p>${product.price}</p>
      <button onClick={handleAddToCart}>Add to Cart</button>
    </div>
  );
}

Complete Order Tracking

import { useZarazEcommerce } from '@zaraz/react';

function CheckoutSuccess({ order }) {
  const { completeOrder } = useZarazEcommerce();

  useEffect(() => {
    completeOrder({
      order_id: order.id,
      affiliation: 'Online Store',
      total: order.total,
      revenue: order.subtotal,
      shipping: order.shipping,
      tax: order.tax,
      discount: order.discount,
      coupon: order.couponCode,
      currency: 'USD',
      products: order.items.map((item) => ({
        product_id: item.id,
        sku: item.sku,
        name: item.name,
        price: item.price,
        quantity: item.quantity,
        category: item.category,
      })),
    });
  }, [order, completeOrder]);

  return <div>Thank you for your order!</div>;
}

Debug Mode

import { useZaraz } from '@zaraz/react';

function DebugPanel() {
  const { debug } = useZaraz();

  const enableDebug = () => {
    debug('your-debug-key-from-cloudflare');
  };

  const disableDebug = () => {
    debug(); // Call without key to disable
  };

  return (
    <div>
      <button onClick={enableDebug}>Enable Debug</button>
      <button onClick={disableDebug}>Disable Debug</button>
    </div>
  );
}

API Reference

<ZarazProvider>

The main provider component that wraps your application.

Props

interface ZarazProviderProps {
  config?: ZarazConfig;
  children: React.ReactNode;
}

interface ZarazConfig {
  /** Enable debug mode on initialization */
  debug?: boolean;
  /** Debug key from Zaraz settings */
  debugKey?: string;
  /** Wait for Zaraz to load before tracking (default: true) */
  waitForLoad?: boolean;
  /** Timeout in ms to wait for Zaraz (default: 5000) */
  loadTimeout?: number;
  /** Custom error handler */
  onError?: (error: Error) => void;
  /** Log events to console in development (default: false) */
  devMode?: boolean;
}

Example

<ZarazProvider
  config={{
    devMode: process.env.NODE_ENV === 'development',
    waitForLoad: true,
    loadTimeout: 10000,
    onError: (error) => console.error('Zaraz error:', error),
  }}
>
  <App />
</ZarazProvider>

useZaraz()

Hook to access core Zaraz functionality.

Returns

interface ZarazContextValue {
  /** Whether Zaraz is loaded and ready */
  isReady: boolean;
  /** Track a custom event */
  track: (eventName: string, eventProperties?: EventProperties) => Promise<void>;
  /** Set a persistent variable */
  set: (key: string, value: string | number | boolean | undefined, options?: ZarazSetOptions) => void;
  /** Track e-commerce events */
  ecommerce: <T extends ZarazEcommerceEvent>(
    eventName: T,
    parameters: ZarazEcommerceEventParams<T>
  ) => Promise<void>;
  /** Enable/disable debug mode */
  debug: (debugKey?: string) => void;
  /** Current configuration */
  config: ZarazConfig;
}

Example

const { track, set, isReady, debug, config } = useZaraz();

// Track event
await track('page_viewed', { page: 'home' });

// Set variable
set('user_tier', 'premium', { scope: 'persist' });

// Check if ready
if (isReady) {
  // Track something
}

useZarazEcommerce()

Hook providing convenient e-commerce tracking methods.

Returns

interface UseZarazEcommerceReturn {
  // Product interactions
  viewProduct: (params: SingleProductEventParams) => Promise<void>;
  clickProduct: (params: SingleProductEventParams) => Promise<void>;
  addProduct: (params: SingleProductEventParams) => Promise<void>;
  removeProduct: (params: SingleProductEventParams) => Promise<void>;
  addProductToWishlist: (params: SingleProductEventParams) => Promise<void>;

  // Lists and search
  viewProductList: (params: ProductListEventParams) => Promise<void>;
  searchProducts: (params: ProductSearchEventParams) => Promise<void>;

  // Cart
  viewCart: (params?: Partial<ProductListEventParams>) => Promise<void>;

  // Checkout flow
  startCheckout: (params?: Partial<OrderEventParams>) => Promise<void>;
  viewCheckoutStep: (params: CheckoutStepEventParams) => Promise<void>;
  completeCheckoutStep: (params: CheckoutStepEventParams) => Promise<void>;
  enterPaymentInfo: (params: PaymentInfoEventParams) => Promise<void>;
  enterShippingInfo: (params?: Partial<OrderEventParams>) => Promise<void>;

  // Orders
  completeOrder: (params: OrderEventParams) => Promise<void>;
  updateOrder: (params: OrderEventParams) => Promise<void>;
  refundOrder: (params: OrderEventParams) => Promise<void>;
  cancelOrder: (params: OrderEventParams) => Promise<void>;

  // Promotions
  viewPromotion: (params: PromotionEventParams) => Promise<void>;
  clickPromotion: (params: PromotionEventParams) => Promise<void>;

  // Raw access
  raw: <T extends ZarazEcommerceEvent>(
    eventName: T,
    parameters: ZarazEcommerceEventParams<T>
  ) => Promise<void>;
}

Next.js Integration

App Router (Next.js 13+)

// app/layout.tsx
import { ZarazProvider } from '@zaraz/react';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <head>
        {/* Zaraz script will be injected by Cloudflare */}
      </head>
      <body>
        <ZarazProvider config={{ devMode: process.env.NODE_ENV === 'development' }}>
          {children}
        </ZarazProvider>
      </body>
    </html>
  );
}
// app/page.tsx or any client component
'use client';

import { useZaraz } from '@zaraz/react';

export default function Home() {
  const { track } = useZaraz();

  return (
    <button onClick={() => track('cta_clicked')}>
      Click Me
    </button>
  );
}

Pages Router (Next.js 12 and below)

// pages/_app.tsx
import { ZarazProvider } from '@zaraz/react';
import type { AppProps } from 'next/app';

export default function App({ Component, pageProps }: AppProps) {
  return (
    <ZarazProvider>
      <Component {...pageProps} />
    </ZarazProvider>
  );
}

Page View Tracking (App Router)

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

import { useEffect } from 'react';
import { usePathname } from 'next/navigation';
import { useZaraz } from '@zaraz/react';

export function PageViewTracker() {
  const pathname = usePathname();
  const { track, isReady } = useZaraz();

  useEffect(() => {
    if (isReady) {
      track('page_view', { path: pathname });
    }
  }, [pathname, isReady, track]);

  return null;
}

Page View Tracking (Pages Router)

// pages/_app.tsx
import { useEffect } from 'react';
import { useRouter } from 'next/router';
import { ZarazProvider, useZaraz } from '@zaraz/react';

function PageViewTracker() {
  const router = useRouter();
  const { track, isReady } = useZaraz();

  useEffect(() => {
    const handleRouteChange = (url: string) => {
      track('page_view', { path: url });
    };

    if (isReady) {
      router.events.on('routeChangeComplete', handleRouteChange);
      return () => {
        router.events.off('routeChangeComplete', handleRouteChange);
      };
    }
  }, [router.events, isReady, track]);

  return null;
}

export default function App({ Component, pageProps }: AppProps) {
  return (
    <ZarazProvider>
      <PageViewTracker />
      <Component {...pageProps} />
    </ZarazProvider>
  );
}

TypeScript Support

This library is written in TypeScript and provides comprehensive type definitions.

Custom Event Types

import { useZaraz } from '@zaraz/react';

// Define your event types
interface MyEvents {
  user_signup: {
    plan: 'free' | 'pro' | 'enterprise';
    source: string;
  };
  purchase_completed: {
    amount: number;
    currency: string;
    items: number;
  };
}

function MyComponent() {
  const { track } = useZaraz();

  // Type-safe event tracking
  const handleSignup = (plan: MyEvents['user_signup']['plan']) => {
    track('user_signup', {
      plan,
      source: 'landing_page',
    });
  };

  return <button onClick={() => handleSignup('pro')}>Sign Up</button>;
}

E-commerce Type Safety

import { useZarazEcommerce, type OrderEventParams } from '@zaraz/react';

function Checkout() {
  const { completeOrder } = useZarazEcommerce();

  const order: OrderEventParams = {
    order_id: '12345',
    total: 99.99,
    currency: 'USD',
    products: [
      {
        product_id: 'abc',
        name: 'T-Shirt',
        price: 29.99,
        quantity: 2,
      },
    ],
  };

  return <button onClick={() => completeOrder(order)}>Complete Order</button>;
}

Advanced Usage

Conditional Tracking

import { useZaraz } from '@zaraz/react';

function useConditionalTracking() {
  const { track } = useZaraz();
  const userConsent = useUserConsent(); // Your consent logic

  return {
    track: (eventName: string, properties?: EventProperties) => {
      if (userConsent.analytics) {
        return track(eventName, properties);
      }
      return Promise.resolve();
    },
  };
}

Custom Hook for Specific Events

import { useZaraz } from '@zaraz/react';
import { useCallback } from 'react';

export function useFormTracking() {
  const { track } = useZaraz();

  const trackFormStart = useCallback(
    (formName: string) => {
      track('form_started', { form_name: formName });
    },
    [track]
  );

  const trackFormComplete = useCallback(
    (formName: string) => {
      track('form_completed', { form_name: formName });
    },
    [track]
  );

  const trackFormError = useCallback(
    (formName: string, error: string) => {
      track('form_error', { form_name: formName, error });
    },
    [track]
  );

  return { trackFormStart, trackFormComplete, trackFormError };
}

Accessing Zaraz Directly

For advanced use cases, you can access the Zaraz API directly:

import { getZarazAPI, isZarazAvailable, waitForZaraz } from '@zaraz/react';

// Check if Zaraz is available
if (isZarazAvailable()) {
  const zaraz = getZarazAPI();
  zaraz?.track('custom_event');
}

// Wait for Zaraz to load
async function ensureZaraz() {
  try {
    const zaraz = await waitForZaraz(10000);
    zaraz.track('zaraz_loaded');
  } catch (error) {
    console.error('Zaraz failed to load:', error);
  }
}

SSR Considerations

This library is fully SSR-safe and handles server-side rendering gracefully:

  • All Zaraz calls are automatically skipped on the server
  • No window object access errors
  • Hooks can be used in any component without SSR guards
  • Automatically detects and waits for Zaraz on client-side hydration
// ✅ This works perfectly in SSR
function MyComponent() {
  const { track } = useZaraz();

  // No need for window checks or useEffect guards
  const handleClick = () => {
    track('button_clicked'); // Automatically skipped on server
  };

  return <button onClick={handleClick}>Click Me</button>;
}

Browser Compatibility

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)
  • React 16.8+ (Hooks support required)
  • Next.js 12+ (Pages Router or App Router)

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT © [Your Name]

Resources

Support