Skip to main content

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.

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

Install the Package

npm
npm install @grainql/tag
yarn
yarn add @grainql/tag
pnpm
pnpm add @grainql/tag

Initialize Grain

Call init() once at your app’s entry point. No provider or wrapper component needed:
// src/main.tsx or src/index.tsx
import { init } from '@grainql/tag';

init({ tenantId: 'your-tenant-id' });

// ... rest of your app setup
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.
Page views, heatmap clicks, scroll depth, and DOM snapshots are tracked automatically. No manual setup required.

Track Events

Import track directly from @grainql/tag and call it from any component:
import { track } from '@grainql/tag';

function SignupButton() {
  const handleClick = () => {
    track('signup_clicked', {
      location: 'hero',
      button_text: 'Get Started'
    });
  };

  return <button onClick={handleClick}>Get Started</button>;
}
Events are automatically batched and sent every few seconds. No manual flushing needed.

Identify Users

Associate events with a specific user after login:
import { identify } from '@grainql/tag';

function LoginForm() {
  const handleLogin = async (email: string, password: string) => {
    const user = await yourLoginFunction(email, password);
    identify(user.id);
  };

  return <form onSubmit={handleLogin}>...</form>;
}
Grain is cookieless by default with daily rotating IDs. When you need explicit consent handling:
import { getInstance } from '@grainql/tag';

function ConsentBanner() {
  const handleAccept = () => {
    const grain = getInstance();
    grain?.consent.grant();
  };

  const handleDecline = () => {
    const grain = getInstance();
    grain?.consent.revoke();
  };

  return (
    <div>
      <p>We use analytics to improve your experience.</p>
      <button onClick={handleAccept}>Accept Analytics</button>
      <button onClick={handleDecline}>Decline</button>
    </div>
  );
}

Complete Example

Here’s a small app that puts it all together:
// src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { init } from '@grainql/tag';
import App from './App';

// Initialize Grain once at startup
init({ tenantId: 'your-tenant-id' });

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
// src/App.tsx
import { track, identify, getInstance } from '@grainql/tag';

function App() {
  const handleSignup = (userId: string) => {
    identify(userId);
    track('signup_completed', { method: 'email' });
  };

  return (
    <div>
      <h1>Welcome!</h1>
      <button onClick={() => track('cta_clicked', { location: 'hero' })}>
        Get Started
      </button>
    </div>
  );
}

export default App;
Automatic page views: Grain Tag hooks into the History API to track navigation automatically. You do not need a PageViewTracker component or manual page_viewed calls — this works out of the box with React Router and other History API-based routers.

Cleanup on Unmount

If you need to tear down Grain (e.g., for testing or HMR), use destroy():
import { useEffect } from 'react';
import { init, destroy, isInitialized } from '@grainql/tag';

function App() {
  useEffect(() => {
    if (!isInitialized()) {
      init({ tenantId: 'your-tenant-id' });
    }

    return () => {
      destroy();
    };
  }, []);

  return <YourApp />;
}

What’s Next?

Core API Reference

See all available methods and options

User Identification

Learn about tracking users across sessions

Next.js Integration

App Router and Pages Router setup

Event Best Practices

Learn what to track and how to structure events
TypeScript users: @grainql/tag ships with full TypeScript declarations. You’ll get autocomplete and type checking out of the box.

Need Remote Config or React Hooks?

If you need remote configuration, feature flags, or React hooks (useConfig, useTrack, GrainProvider), install @grainql/analytics-web instead. See the Analytics Web React SDK for details.