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.

The primary way to install Grain. Perfect for any website — landing pages, static sites, CMSs, or full web apps. No build tools required. Grain Tag automatically tracks page views, clicks, scroll depth, heatmaps, and DOM snapshots with zero code. Just add the script and you’re collecting data.
Using React or Next.js? Try React Quick Start or Next.js Quick Start for framework-specific integration.

Add the Script Tag

Add this to your HTML <head>:
<script src="https://tag.grainql.com/v4/your-tenant-id.js"></script>
Replace your-tenant-id with your tenant identifier (not UUID) from your dashboard. That’s it! Grain is now loaded and tracking page views, heatmap clicks, scroll depth, and DOM snapshots automatically.

Complete HTML Example

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>My Landing Page</title>

  <!-- Grain Tag (auto-initializes) -->
  <script src="https://tag.grainql.com/v4/your-tenant-id.js"></script>
</head>
<body>
  <h1>Welcome!</h1>
  <button id="signup-btn">Get Started</button>

  <script>
    // Get SDK instance (already initialized)
    const grain = GrainTag.getInstance();

    // Track button clicks
    document.getElementById('signup-btn').addEventListener('click', function() {
      grain.track('signup_clicked', {
        location: 'hero'
      });

      // Your signup logic...
      window.location.href = '/signup';
    });
  </script>
</body>
</html>

Track Custom Events

const grain = GrainTag.getInstance();

grain.track('button_clicked', {
  button_name: 'signup',
  location: 'hero'
});
You can also use the top-level shortcut:
GrainTag.track('button_clicked', {
  button_name: 'signup',
  location: 'hero'
});
Events are automatically batched and sent. No manual flushing needed.

Track Form Submissions

<form id="contact-form">
  <input type="text" name="name" required>
  <input type="email" name="email" required>
  <button type="submit">Submit</button>
</form>

<script>
  const grain = GrainTag.getInstance();

  document.getElementById('contact-form').addEventListener('submit', function(e) {
    e.preventDefault();

    // Track the submission
    grain.track('form_submitted', {
      form_name: 'contact',
      page: window.location.pathname
    });

    // Your form submission logic...
  });
</script>
<a href="/pricing" id="pricing-link">View Pricing</a>

<script>
  const grain = GrainTag.getInstance();

  document.getElementById('pricing-link').addEventListener('click', function() {
    grain.track('link_clicked', {
      link_text: 'View Pricing',
      destination: '/pricing'
    });
  });
</script>

Identify Users

Track logged-in users:
<script>
  const grain = GrainTag.getInstance();

  // When user logs in — pass only the user ID
  function handleLogin(userId) {
    grain.identify(userId);

    // Track login event
    grain.track('user_logged_in', {
      method: 'email'
    });
  }
</script>
Grain is cookieless by default with daily rotating IDs. When you need explicit consent handling:
<script>
  const grain = GrainTag.getInstance();

  // Grant consent (enables persistent tracking)
  grain.consent.grant();

  // Revoke consent
  grain.consent.revoke();

  // Check consent status
  const status = grain.consent.status();
</script>

SPA Navigation

Grain Tag automatically tracks page views on initial load and hooks into the History API (pushState / replaceState) to track navigation in single-page apps. No manual page view tracking is needed for most SPAs. If your app uses custom routing that does not go through the History API, you can track navigation manually:
<script>
  const grain = GrainTag.getInstance();

  // Only needed for custom routing that bypasses the History API
  function navigateTo(url) {
    // Your custom navigation logic...
    grain.track('page_viewed', {
      page: url
    });
  }
</script>

Performance Tips

Do: Place Grain in the <head> for early initialization
Do: Use one script tag per page — Grain handles everything
Don’t: Load Grain multiple times — once per page is enough

What’s Next?

Core API Reference

See all available methods and options

Event Tracking Guide

Learn what to track and best practices

Trackers

Track element clicks without code

Vanilla JS, Vue & Svelte

Integration with other frameworks
Using Google Tag Manager instead? Check out the GTM Integration Guide for a no-code setup.
Need remote configuration or feature flags? See @grainql/analytics-web for remote config support.