This guide uses the Grain Tag script, which works with Vue, Svelte, Angular, or plain JavaScript. Using React? Try the React Quick Start for a better experience.
Add the Grain Tag
Add the Grain Tag script to your HTML:
<script src="https://tag.grainql.com/v4/your-tenant-id.js"></script>
Replace your-tenant-id with your tenant identifier from your dashboard.
Then get the SDK instance in your JavaScript:
const grain = GrainTag.getInstance();
Need npm module imports? Install @grainql/tag via npm for use with bundlers. See the Installation guide for details.
Track Events
Call track() with an event name and optional properties:
// Track a button click
grain.track('button_clicked', {
button_name: 'signup',
location: 'hero'
});
// Track a page view
grain.track('page_viewed', {
page: window.location.pathname,
title: document.title
});
// Track a form submission
grain.track('form_submitted', {
form_name: 'contact'
});
Events are automatically batched and sent. You don’t need to manually flush.
Use Remote Config
Get configuration values instantly:
// Get a config value (returns from cache or default)
const heroText = grain.getConfig('hero_text');
console.log(heroText); // "Welcome!"
// Check if a feature is enabled
const isNewUIEnabled = grain.getConfig('new_ui_enabled');
if (isNewUIEnabled === 'true') {
showNewUI();
} else {
showOldUI();
}
Cache-first loading: getConfig() returns immediately with cached or default values. Fresh values load in the background and update automatically.
Listen for Config Updates
Subscribe to changes when remote values load:
grain.onConfigsUpdated((configs) => {
console.log('Configs updated!', configs);
// Update your UI with the new values
const heroText = grain.getConfig('hero_text');
document.querySelector('h1').textContent = heroText;
});
Identify Users
Associate events with a specific user:
// When a user logs in — pass the user ID
grain.identify('user_123');
// All subsequent events include this user ID
grain.track('feature_used', {
feature_name: 'export'
});
Consent Management
Grain is cookieless by default. When you need explicit consent handling:
// Grant consent (enables persistent tracking)
grain.consent.grant();
// Revoke consent
grain.consent.revoke();
// Check consent status
const status = grain.consent.status();
Complete Example
Here’s a small app that puts it all together:
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://tag.grainql.com/v4/your-tenant-id.js"></script>
</head>
<body>
<div id="hero">
<h1>Welcome!</h1>
</div>
<div id="banner" style="display: none;">
<p>Special offer!</p>
</div>
<button id="signup-btn">Get Started</button>
<script>
const grain = GrainTag.getInstance();
// Track page view on load
grain.track('page_viewed', {
page: window.location.pathname,
title: document.title
});
// Use remote config to control UI
const heroText = grain.getConfig('hero_text');
if (heroText) {
document.querySelector('#hero h1').textContent = heroText;
}
const showBanner = grain.getConfig('show_banner');
if (showBanner === 'true') {
document.querySelector('#banner').style.display = 'block';
}
// Track button clicks
document.querySelector('#signup-btn').addEventListener('click', () => {
grain.track('signup_clicked', { location: 'hero' });
});
// Update UI when fresh config loads
grain.onConfigsUpdated(() => {
const newHeroText = grain.getConfig('hero_text');
if (newHeroText) {
document.querySelector('#hero h1').textContent = newHeroText;
}
});
// Identify user after login
async function handleLogin(email, password) {
const user = await loginUser(email, password);
grain.identify(user.id);
}
</script>
</body>
</html>
Vue.js Example
Using Grain in a Vue component:
<template>
<div>
<h1>{{ heroText }}</h1>
<button @click="handleClick">Get Started</button>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const heroText = ref('Welcome!');
onMounted(() => {
const grain = GrainTag.getInstance();
// Get initial config value
heroText.value = grain.getConfig('hero_text') || 'Welcome!';
// Update when remote config loads
grain.onConfigsUpdated(() => {
heroText.value = grain.getConfig('hero_text') || 'Welcome!';
});
});
const handleClick = () => {
const grain = GrainTag.getInstance();
grain.track('button_clicked', { location: 'hero' });
};
</script>
Svelte Example
Using Grain in a Svelte component:
<script>
import { onMount } from 'svelte';
let heroText = 'Welcome!';
onMount(() => {
const grain = GrainTag.getInstance();
// Get initial config value
heroText = grain.getConfig('hero_text') || 'Welcome!';
// Update when remote config loads
grain.onConfigsUpdated(() => {
heroText = grain.getConfig('hero_text') || 'Welcome!';
});
});
function handleClick() {
const grain = GrainTag.getInstance();
grain.track('button_clicked', { location: 'hero' });
}
</script>
<div>
<h1>{heroText}</h1>
<button on:click={handleClick}>Get Started</button>
</div>
Track Page Views Automatically
For single-page apps, track route changes:
const grain = GrainTag.getInstance();
// For browser history API
window.addEventListener('popstate', () => {
grain.track('page_viewed', {
page: window.location.pathname
});
});
// For Vue Router
router.afterEach((to) => {
grain.track('page_viewed', {
page: to.path,
name: to.name
});
});
What’s Next?