Install the Package
npm install @grainql/analytics-web
yarn add @grainql/analytics-web
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?
TypeScript users: All hooks are fully typed. You’ll get autocomplete and type checking out of the box.