@grainql/analytics-web/react. Every hook must run inside
a GrainProvider. Read React hooks for the setup and for when to use Grain
Tag instead.
| Export | Kind | Returns or renders |
|---|---|---|
GrainProvider | Component | The context for every hook |
useGrainAnalytics() | Hook | GrainAnalytics |
useConfig(key, options?) | Hook | UseConfigResult |
useAllConfigs(options?) | Hook | UseAllConfigsResult |
useTrack() | Hook | TrackFunction |
useConsent() | Hook | The consent state and the consent functions |
usePrivacyPreferences() | Hook | The three preference flags and their setters |
useDataDeletion(options) | Hook | Two request functions, loading, and error |
ConsentBanner | Component | A consent popup |
PrivacyPreferenceCenter | Component | A preference modal |
CookieNotice | Component | A cookie notice bar |
GrainProvider
function GrainProvider({ children, client, config }: GrainProviderProps): React.JSX.Element
interface GrainProviderProps {
children: React.ReactNode;
client?: GrainAnalytics;
config?: GrainConfig;
}
| Prop | Type | Rule |
|---|---|---|
config | GrainConfig | The provider creates the client and calls destroy on unmount. |
client | GrainAnalytics | You create the client and own its lifecycle. |
children | React.ReactNode | The tree that uses the hooks. |
config or client, not both.
import { GrainProvider } from '@grainql/analytics-web/react';
export function Root() {
return (
<GrainProvider config={{ tenantId: 'your-tenant-id' }}>
<App />
</GrainProvider>
);
}
useGrainAnalytics
function useGrainAnalytics(): GrainAnalytics
GrainProvider. Use it for
identify, setProperty, the template methods, flush, and consent.
import { useGrainAnalytics } from '@grainql/analytics-web/react';
function LoginButton({ userId }: { userId: string }) {
const grain = useGrainAnalytics();
const onLogin = async () => {
grain.identify(userId);
await grain.setProperty({ plan: 'premium' });
};
return <button onClick={onLogin}>Log in</button>;
}
useConfig
function useConfig(key: string, options?: UseConfigOptions): UseConfigResult
interface UseConfigOptions {
forceRefresh?: boolean;
immediateKeys?: string[];
properties?: Record<string, string>;
}
| Parameter | Type | Rule |
|---|---|---|
key | string | The configuration key. |
options.forceRefresh | boolean | Optional. true skips the cache on mount. |
options.immediateKeys | string[] | Optional. The keys that the API must resolve in the first response. |
options.properties | Record<string, string> | Optional. User properties for personalization. |
| Result field | Type | Meaning |
|---|---|---|
value | string | undefined | The cached or default value first, then the fresh value. |
isRefreshing | boolean | true while a request runs. |
error | Error | null | The error of the last request. |
refresh | () => Promise<void> | Starts a request. |
import { useConfig } from '@grainql/analytics-web/react';
function Hero() {
const { value, isRefreshing, error, refresh } = useConfig('hero_text');
if (error) {
return <h1>Welcome</h1>;
}
return (
<div>
<h1>{value ?? 'Welcome'}</h1>
{isRefreshing && <span>Updating</span>}
<button onClick={refresh}>Refresh</button>
</div>
);
}
key changes.
useAllConfigs
function useAllConfigs(options?: UseAllConfigsOptions): UseAllConfigsResult
interface UseAllConfigsOptions {
forceRefresh?: boolean;
immediateKeys?: string[];
properties?: Record<string, string>;
}
| Parameter | Type | Rule |
|---|---|---|
options | UseAllConfigsOptions | Optional. The same three fields as UseConfigOptions. |
| Result field | Type | Meaning |
|---|---|---|
configs | Record<string, string> | Every configuration value. |
isRefreshing | boolean | true while a request runs. |
error | Error | null | The error of the last request. |
refresh | () => Promise<void> | Starts a request. |
import { useAllConfigs } from '@grainql/analytics-web/react';
function ConfigList() {
const { configs } = useAllConfigs();
return (
<ul>
{Object.entries(configs).map(([key, value]) => (
<li key={key}>
{key}: {value}
</li>
))}
</ul>
);
}
useTrack
function useTrack(): TrackFunction
type TrackFunction = (
eventName: string,
properties?: Record<string, unknown>,
options?: SendEventOptions
) => Promise<void>;
useCallback.
import { useTrack } from '@grainql/analytics-web/react';
function SignupButton() {
const track = useTrack();
return (
<button onClick={() => track('button_clicked', { button: 'signup', page: '/home' })}>
Sign up
</button>
);
}
useConsent
function useConsent(): {
consentState: ConsentState;
grantConsent: (categories?: string[]) => void;
revokeConsent: (categories?: string[]) => void;
hasConsent: (category?: string) => boolean;
isGranted: boolean;
categories: string[];
}
| Result field | Type | Meaning |
|---|---|---|
consentState | ConsentState | The full state object. |
grantConsent | (categories?: string[]) => void | Calls grantConsent on the client. |
revokeConsent | (categories?: string[]) => void | Calls revokeConsent on the client. |
hasConsent | (category?: string) => boolean | Calls hasConsent on the client. |
isGranted | boolean | consentState.granted. |
categories | string[] | consentState.categories. |
import { useConsent } from '@grainql/analytics-web/react';
function ConsentButtons() {
const { isGranted, grantConsent, revokeConsent } = useConsent();
if (isGranted) {
return <button onClick={() => revokeConsent()}>Revoke</button>;
}
return <button onClick={() => grantConsent(['analytics'])}>Accept analytics</button>;
}
usePrivacyPreferences
function usePrivacyPreferences(): {
preferences: PrivacyPreferences;
updatePreferences: (newPreferences: Partial<PrivacyPreferences>) => void;
acceptAll: () => void;
rejectAll: () => void;
}
interface PrivacyPreferences {
necessary: boolean;
analytics: boolean;
functional: boolean;
}
| Result field | Type | Meaning |
|---|---|---|
preferences | PrivacyPreferences | One flag per category. |
updatePreferences | (newPreferences: Partial<PrivacyPreferences>) => void | Sets one or more flags. |
acceptAll | () => void | Sets every flag to true. |
rejectAll | () => void | Rejects every category. |
import { usePrivacyPreferences } from '@grainql/analytics-web/react';
function AnalyticsToggle() {
const { preferences, updatePreferences } = usePrivacyPreferences();
return (
<label>
<input
type="checkbox"
checked={preferences.analytics}
onChange={(e) => updatePreferences({ analytics: e.target.checked })}
/>
Analytics
</label>
);
}
useDataDeletion
function useDataDeletion(options: DataDeletionOptions): {
requestDeletion: (userId: string) => Promise<any>;
requestAnonymization: (userId: string) => Promise<any>;
loading: boolean;
error: string;
}
interface DataDeletionOptions {
apiUrl: string;
tenantId: string;
onSuccess?: (message: string) => void;
onError?: (error: string) => void;
}
| Parameter | Type | Rule |
|---|---|---|
options.apiUrl | string | The API base URL. |
options.tenantId | string | The tenant alias. |
options.onSuccess | (message: string) => void | Optional. Runs after a request succeeds. |
options.onError | (error: string) => void | Optional. Runs after a request fails. |
| Result field | Type | Meaning |
|---|---|---|
requestDeletion | (userId: string) => Promise<any> | Sends a deletion request for the user. |
requestAnonymization | (userId: string) => Promise<any> | Sends an anonymization request for the user. |
loading | boolean | true while a request runs. |
error | string | The last error text. Empty when there is no error. |
import { useDataDeletion } from '@grainql/analytics-web/react';
function DeleteMyData({ userId }: { userId: string }) {
const { requestDeletion, loading } = useDataDeletion({
apiUrl: 'https://clientapis.grainql.com',
tenantId: 'your-tenant-id',
});
return (
<button disabled={loading} onClick={() => requestDeletion(userId)}>
Delete my data
</button>
);
}
ConsentBanner
function ConsentBanner(props: ConsentBannerProps): React.JSX.Element
interface ConsentBannerProps {
position?: 'top' | 'bottom' | 'center';
theme?: 'light' | 'dark' | 'glass';
customText?: string;
onAccept?: () => void;
onDecline?: () => void;
showPreferences?: boolean;
privacyPolicyUrl?: string;
}
| Prop | Type | Meaning |
|---|---|---|
position | 'top' | 'bottom' | 'center' | Where the banner renders. |
theme | 'light' | 'dark' | 'glass' | The visual theme. |
customText | string | Replaces the default banner text. |
onAccept | () => void | Runs after the user accepts. |
onDecline | () => void | Runs after the user declines. |
showPreferences | boolean | Shows a button that opens the preference center. |
privacyPolicyUrl | string | The link target of the privacy policy. |
import { ConsentBanner } from '@grainql/analytics-web/react';
function App() {
return (
<>
<ConsentBanner position="bottom" theme="light" privacyPolicyUrl="/privacy" />
<Main />
</>
);
}
PrivacyPreferenceCenter
function PrivacyPreferenceCenter(props: PrivacyPreferenceCenterProps): React.JSX.Element
interface PrivacyPreferenceCenterProps {
isOpen: boolean;
onClose: () => void;
onSave?: (categories: string[]) => void;
}
| Prop | Type | Meaning |
|---|---|---|
isOpen | boolean | Required. true shows the modal. |
onClose | () => void | Required. Runs when the user closes the modal. |
onSave | (categories: string[]) => void | Runs with the granted categories after the user saves. |
import { useState } from 'react';
import { PrivacyPreferenceCenter } from '@grainql/analytics-web/react';
function PrivacySettings() {
const [open, setOpen] = useState(false);
return (
<>
<button onClick={() => setOpen(true)}>Privacy settings</button>
<PrivacyPreferenceCenter isOpen={open} onClose={() => setOpen(false)} />
</>
);
}
CookieNotice
function CookieNotice(props: CookieNoticeProps): React.JSX.Element
interface CookieNoticeProps {
message?: string;
privacyPolicyUrl?: string;
onDismiss?: () => void;
position?: 'top' | 'bottom';
}
| Prop | Type | Meaning |
|---|---|---|
message | string | Replaces the default notice text. |
privacyPolicyUrl | string | The link target of the privacy policy. |
onDismiss | () => void | Runs when the user closes the notice. |
position | 'top' | 'bottom' | Where the notice renders. |
import { CookieNotice } from '@grainql/analytics-web/react';
function App() {
return (
<>
<CookieNotice position="bottom" privacyPolicyUrl="/privacy" />
<Main />
</>
);
}