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
- Go to Plugins → Add New
- Search for “Insert Headers and Footers”
- Click Install Now → Activate
Add Grain Analytics
- Go to Settings → Insert Headers and Footers
- 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>
- 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; ?>
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; ?>
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
- Open your site in incognito/private window
- Open browser console (F12 → Console)
- Type
window.grain — you should see the Grain object
- Navigate a few pages
- 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?