Skip to main content
Most WordPress analytics plugins are slow and bloated. Grain is different: 6 KB, fast, and privacy-first.
Use a child theme! If you edit your theme directly, updates will overwrite your changes. Either use a child theme or the header/footer plugin method below.

What You’ll Need


The safest method—no theme editing required.

Install the Plugin

  1. Go to Plugins → Add New
  2. Search for “Insert Headers and Footers”
  3. Click Install NowActivate

Add Grain Analytics

  1. Go to Settings → Insert Headers and Footers
  2. In Scripts in Header, paste:
<script src="https://unpkg.com/@grainql/analytics-web/dist/index.global.js"></script>
<script>
  window.grain = Grain.createGrainAnalytics({
    tenantId: 'your-tenant-id' // Replace with your actual tenant ID
  });
  
  // Track page views
  grain.track('page_viewed', {
    page: window.location.pathname,
    title: document.title
  });
</script>
  1. Click Save
Done! Grain is now tracking your site. 🎉
Alternative plugins: “WP Code” or “Simple Custom CSS and JS” work great too!

Method 2: Functions.php (Advanced)

If you’re using a child theme, add this to functions.php:
<?php
function grain_analytics_header() {
  $tenant_id = 'your-tenant-id'; // Replace with your actual tenant ID
  ?>
  <script src="https://unpkg.com/@grainql/analytics-web/dist/index.global.js"></script>
  <script>
    window.grain = Grain.createGrainAnalytics({
      tenantId: '<?php echo esc_js($tenant_id); ?>'
    });
    
    grain.track('page_viewed', {
      page: window.location.pathname,
      title: document.title,
      post_type: '<?php echo get_post_type(); ?>',
      post_id: <?php echo get_the_ID(); ?>
    });
  </script>
  <?php
}
add_action('wp_head', 'grain_analytics_header');
?>
Using a child theme? Perfect! Add this to your child theme’s functions.php to keep it safe from updates.

Track Blog Posts

Track which posts people read:
<?php if (is_single()) : ?>
<script>
  if (window.grain) {
    grain.track('blog_post_viewed', {
      post_id: <?php echo get_the_ID(); ?>,
      post_title: '<?php echo esc_js(get_the_title()); ?>',
      author: '<?php echo esc_js(get_the_author()); ?>',
      categories: <?php echo json_encode(wp_get_post_categories(get_the_ID(), array('fields' => 'names'))); ?>
    });
  }
</script>
<?php endif; ?>

Track Form Submissions

For Contact Form 7:
document.addEventListener('wpcf7mailsent', function(event) {
  if (window.grain) {
    grain.track('contact_form_submitted', {
      form_id: event.detail.contactFormId
    });
  }
});

Track Search Queries

<?php if (is_search()) : ?>
<script>
  if (window.grain) {
    grain.track('search_performed', {
      query: '<?php echo esc_js(get_search_query()); ?>',
      results_count: <?php echo $wp_query->found_posts; ?>
    });
  }
</script>
<?php endif; ?>

Track Comments

function grain_track_comment() {
  ?>
  <script>
    document.addEventListener('DOMContentLoaded', function() {
      const commentForm = document.getElementById('commentform');
      if (commentForm && window.grain) {
        commentForm.addEventListener('submit', function() {
          grain.track('comment_submitted', {
            post_id: <?php echo get_the_ID(); ?>
          });
        });
      }
    });
  </script>
  <?php
}
add_action('comment_form_after', 'grain_track_comment');

WooCommerce Integration

If you run a WooCommerce store:

Track Product Views

function grain_track_product_view() {
  if (!is_product()) return;
  global $product;
  ?>
  <script>
    if (window.grain) {
      grain.track('product_viewed', {
        product_id: <?php echo $product->get_id(); ?>,
        product_name: '<?php echo esc_js($product->get_name()); ?>',
        price: <?php echo $product->get_price(); ?>
      });
    }
  </script>
  <?php
}
add_action('wp_footer', 'grain_track_product_view');

Track Add to Cart

add_action('woocommerce_add_to_cart', function($cart_item_key, $product_id) {
  ?>
  <script>
    if (window.grain) {
      grain.track('product_added_to_cart', {
        product_id: <?php echo $product_id; ?>
      });
    }
  </script>
  <?php
}, 10, 2);

Test Your Integration

  1. Open your site in incognito/private window
  2. Open browser console (F12 → Console)
  3. Type window.grain — you should see the Grain object
  4. Navigate a few pages
  5. Check your Grain dashboard
Debug mode: Add debug: true temporarily to see logs:
window.grain = Grain.createGrainAnalytics({
  tenantId: 'your-tenant-id',
  debug: true // Remove before going live!
});

Troubleshooting

Script Not Loading

  • Check PHP syntax (missing semicolons or quotes)
  • Clear cache (if using a cache plugin)
  • Check browser console for errors (F12)
  • Verify code is in <head> section

Events Not in Dashboard

  • Wait 1-2 minutes (slight delay is normal)
  • Check that window.grain exists in console
  • Verify tenant ID is correct
  • Make sure you’re not blocking analytics with browser extensions

Theme Broke

  • Revert immediately: Go to Appearance → Themes, activate a default theme
  • Fix PHP syntax errors (check for missing ?> or unclosed strings)
  • Use FTP to restore original file from backup

What’s Next?

Need help? Chat with us at grainql.com or email [email protected].