> ## 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.

# React Quick Start

> Get Grain Analytics running in your React app in 5 minutes

<Note>
  **Using Next.js?** Check out the [Next.js Quick Start](/quickstart/nextjs) for App Router and Pages Router examples.
</Note>

## Install the Package

```bash npm theme={null}
npm install @grainql/tag
```

```bash yarn theme={null}
yarn add @grainql/tag
```

```bash pnpm theme={null}
pnpm add @grainql/tag
```

## Initialize Grain

Call `init()` once at your app's entry point. No provider or wrapper component needed:

```tsx theme={null}
// 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](https://grainql.com/dashboard) (not the UUID).

<Tip>
  **Pro tip**: Store your tenant ID in an environment variable like `VITE_GRAIN_TENANT_ID` or `REACT_APP_GRAIN_TENANT_ID`.
</Tip>

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:

```tsx theme={null}
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:

```tsx theme={null}
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>;
}
```

## Consent Management

Grain is cookieless by default with daily rotating IDs. When you need explicit consent handling:

```tsx theme={null}
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:

```tsx theme={null}
// 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>
);
```

```tsx theme={null}
// 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;
```

<Info>
  **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.
</Info>

## Cleanup on Unmount

If you need to tear down Grain (e.g., for testing or HMR), use `destroy()`:

```tsx theme={null}
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?

<CardGroup cols={2}>
  <Card title="Core API Reference" icon="book" href="/api-reference/core-methods">
    See all available methods and options
  </Card>

  <Card title="User Identification" icon="user" href="/core/user-identification">
    Learn about tracking users across sessions
  </Card>

  <Card title="Next.js Integration" icon="arrow-right" href="/quickstart/nextjs">
    App Router and Pages Router setup
  </Card>

  <Card title="Event Best Practices" icon="chart-line" href="/core/event-tracking">
    Learn what to track and how to structure events
  </Card>
</CardGroup>

<Tip>
  **TypeScript users**: `@grainql/tag` ships with full TypeScript declarations. You'll get autocomplete and type checking out of the box.
</Tip>

## 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](/react/overview) for details.
