Skip to main content
Using Next.js? Check out the Next.js Quick Start for App Router and Pages Router examples.

Install the Package

npm
npm install @grainql/analytics-web
yarn
yarn add @grainql/analytics-web
pnpm
pnpm add @grainql/analytics-web

Wrap Your App

Add the GrainProvider at the top of your component tree:
import { GrainProvider } from '@grainql/analytics-web/react';

function App() {
  return (
    <GrainProvider config={{ tenantId: 'your-tenant-id' }}>
      <YourApp />
    </GrainProvider>
  );
}
Replace 'your-tenant-id' with the alias from your dashboard (not the UUID).
Pro tip: Store your tenant ID in an environment variable like VITE_GRAIN_TENANT_ID or REACT_APP_GRAIN_TENANT_ID.

Track Events

Use the useTrack hook anywhere in your app:
import { useTrack } from '@grainql/analytics-web/react';

function SignupButton() {
  const track = useTrack();
  
  const handleClick = () => {
    track('signup_clicked', {
      location: 'hero',
      button_text: 'Get Started'
    });
    
    // Your signup logic here
  };
  
  return <button onClick={handleClick}>Get Started</button>;
}
Events are automatically batched and sent every few seconds. No manual flushing needed.

Use Remote Config

Access configuration values with useConfig:
import { useConfig } from '@grainql/analytics-web/react';

function Hero() {
  const { value: heroText, loading } = useConfig('hero_text');
  
  return (
    <div>
      <h1>{heroText || 'Welcome!'}</h1>
      {loading && <span>Loading fresh content...</span>}
    </div>
  );
}
The component automatically re-renders when config updates. Default values load instantly from cache or the defaultConfigurations you provided.
How it works: Config uses a cache-first strategy. Your UI loads instantly with cached values, while fresh data loads in the background.

Set User Identity

Identify users to track them across sessions:
import { useGrainAnalytics } from '@grainql/analytics-web/react';

function LoginForm() {
  const { identify } = useGrainAnalytics();
  
  const handleLogin = async (email, password) => {
    const user = await yourLoginFunction(email, password);
    
    // Associate all future events with this user
    identify(user.id, {
      email: user.email,
      name: user.name,
      plan: user.plan
    });
  };
  
  return <form onSubmit={handleLogin}>...</form>;
}

Complete Example

Here’s a small app that puts it all together:
import { 
  GrainProvider, 
  useTrack, 
  useConfig,
  useGrainAnalytics 
} from '@grainql/analytics-web/react';

// 1. Wrap your app
function App() {
  return (
    <GrainProvider 
      config={{ 
        tenantId: 'your-tenant-id',
        defaultConfigurations: {
          hero_text: 'Welcome to Our App',
          feature_enabled: 'false'
        }
      }}
    >
      <HomePage />
    </GrainProvider>
  );
}

// 2. Use hooks in components
function HomePage() {
  const track = useTrack();
  const { value: heroText } = useConfig('hero_text');
  const { value: featureEnabled } = useConfig('feature_enabled');
  const { identify } = useGrainAnalytics();
  
  const handleSignup = (userId: string) => {
    // Identify the user
    identify(userId, { signup_date: new Date().toISOString() });
    
    // Track the event
    track('signup_completed', {
      method: 'email'
    });
  };
  
  return (
    <div>
      <h1>{heroText}</h1>
      
      {featureEnabled === 'true' && (
        <NewFeature />
      )}
      
      <button onClick={() => track('cta_clicked', { location: 'hero' })}>
        Get Started
      </button>
    </div>
  );
}

Track Page Views

For single-page apps, track route changes manually:
import { useEffect } from 'react';
import { useTrack } from '@grainql/analytics-web/react';
import { useLocation } from 'react-router-dom'; // or your router

function PageViewTracker() {
  const track = useTrack();
  const location = useLocation();
  
  useEffect(() => {
    track('page_viewed', {
      page: location.pathname,
      title: document.title
    });
  }, [location.pathname, track]);
  
  return null; // This component just tracks
}

// Add to your app
function App() {
  return (
    <GrainProvider config={{ tenantId: 'your-tenant-id' }}>
      <Router>
        <PageViewTracker />
        <Routes>...</Routes>
      </Router>
    </GrainProvider>
  );
}

What’s Next?

React Hooks Reference

See all available hooks and their options

User Identification

Learn about tracking users across sessions

Authentication

Secure your analytics with Auth0 or JWT

Event Best Practices

Learn what to track and how to structure events
TypeScript users: All hooks are fully typed. You’ll get autocomplete and type checking out of the box.