Documentation Index Fetch the complete documentation index at: https://docs.grainql.com/llms.txt
Use this file to discover all available pages before exploring further.
What is GrainProvider?
GrainProvider is a React component that makes Grain available throughout your app using React’s Context API. Wrap your app with it once, then use hooks anywhere.
import { GrainProvider } from '@grainql/analytics-web/react' ;
function App () {
return (
< GrainProvider config = {{ tenantId : 'your-tenant-id' }} >
< YourApp />
</ GrainProvider >
);
}
Now any component inside can use Grain hooks like useConfig and useTrack.
Provider-Managed Pattern
The simplest way - let the provider create and manage the Grain client:
< GrainProvider config = {{ tenantId : 'your-tenant-id' }} >
< App />
</ GrainProvider >
Pass any configuration options:
< GrainProvider
config = {{
tenantId : 'your-tenant-id' ,
authStrategy : 'JWT' ,
authProvider : { getToken : () => getAccessToken () },
userId : currentUser ?. id ,
defaultConfigurations : {
hero_text : 'Welcome!' ,
feature_enabled : 'false'
}
}}
>
< App />
</ GrainProvider >
When to use : Most apps. Simple, works great, no external client needed.
External Client Pattern
Create the client yourself, then pass it to the provider:
import { GrainAnalytics } from '@grainql/analytics-web' ;
const grain = new GrainAnalytics ({
tenantId: 'your-tenant-id'
});
< GrainProvider client = { grain } >
< App />
</ GrainProvider >
When to use :
Need to access Grain outside React components
Want to share one instance across multiple apps
Need full control over client lifecycle
Dynamic User ID
Update the user ID when authentication changes:
function AppWithAuth () {
const { user } = useAuth (); // Your auth hook
return (
< GrainProvider
config = {{
tenantId : 'your-tenant-id' ,
userId : user ?. id // Updates automatically when user changes
}}
>
< App />
</ GrainProvider >
);
}
What happens : When userId changes, the provider updates the Grain client automatically. No manual setUserId() calls needed.
Multiple Providers
You can nest providers for different tenants (rare):
< GrainProvider config = {{ tenantId : 'tenant-1' }} >
< MainApp />
< GrainProvider config = {{ tenantId : 'tenant-2' }} >
< SubApp />
</ GrainProvider >
</ GrainProvider >
Inner provider overrides outer one for components inside it.
Provider Position
Place the provider high in your component tree:
// ✅ Good: High in the tree
< GrainProvider config = {{ tenantId : 'your-tenant-id' }} >
< Router >
< App />
</ Router >
</ GrainProvider >
// ❌ Bad: Below router means hooks can't be used in route components
< Router >
< GrainProvider config = {{ tenantId : 'your-tenant-id' }} >
< App />
</ GrainProvider >
</ Router >
Error Handling
If hooks are used outside a provider, you’ll get an error:
function Component () {
const track = useTrack (); // Error: must be inside GrainProvider
}
Always wrap your app with the provider before using hooks.
Configuration Updates
Configuration changes cause provider to re-render children. Use stable config objects:
// ✅ Good: Stable config
const config = useMemo (() => ({
tenantId: 'your-tenant-id' ,
userId: user ?. id
}), [ user ?. id ]);
< GrainProvider config = { config } >
< App />
</ GrainProvider >
// ⚠️ Creates new object every render
< GrainProvider config = {{ tenantId : 'your-tenant-id' }} >
< App />
</ GrainProvider >
The second example works but may cause unnecessary re-renders. Use useMemo if config is complex or changes frequently.
With Next.js
In Next.js, wrap your app in _app.tsx:
// pages/_app.tsx
import { GrainProvider } from '@grainql/analytics-web/react' ;
export default function MyApp ({ Component , pageProps }) {
return (
< GrainProvider config = {{ tenantId : 'your-tenant-id' }} >
< Component { ... pageProps } />
</ GrainProvider >
);
}
For App Router:
// app/layout.tsx
import { GrainProvider } from '@grainql/analytics-web/react' ;
export default function RootLayout ({ children }) {
return (
< html >
< body >
< GrainProvider config = {{ tenantId : 'your-tenant-id' }} >
{ children }
</ GrainProvider >
</ body >
</ html >
);
}
Next Steps
useConfig Access remote configurations
useTrack Track events efficiently