This guide works with Vue, Svelte, Angular, or plain JavaScript. Using React? Try the React Quick Start for a better experience.
Install the Package
npm install @grainql/analytics-web
yarn add @grainql/analytics-web
pnpm add @grainql/analytics-web
Initialize the SDK
Import and create a Grain client:
import { createGrainAnalytics } from '@grainql/analytics-web';
const grain = createGrainAnalytics({
tenantId: 'your-tenant-id'
});
Replace 'your-tenant-id' with the alias from your dashboard.
Pro tip: Create the client in a separate file and export it so you can use it throughout your app.
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',
fields: ['name', 'email', 'message']
});
Events are automatically batched and sent every 5 seconds. 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.
To set default values:
const grain = createGrainAnalytics({
tenantId: 'your-tenant-id',
defaultConfigurations: {
hero_text: 'Welcome!',
new_ui_enabled: 'false'
}
});
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
grain.identify('user_123', {
email: '[email protected]',
name: 'Jane Doe',
plan: 'pro'
});
// Now all events include this user ID and properties
grain.track('feature_used', {
feature_name: 'export'
});
Complete Example
Here’s a small app that puts it all together:
import { createGrainAnalytics } from '@grainql/analytics-web';
// Initialize
const grain = createGrainAnalytics({
tenantId: 'your-tenant-id',
defaultConfigurations: {
hero_text: 'Welcome!',
show_banner: 'false'
}
});
// 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');
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'
});
// Your signup logic...
});
// Update UI when fresh config loads
grain.onConfigsUpdated(() => {
const newHeroText = grain.getConfig('hero_text');
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, {
email: user.email,
name: user.name
});
}
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';
import { grain } from './grain'; // Your initialized client
const heroText = ref('Welcome!');
onMounted(() => {
// Get initial config value
heroText.value = grain.getConfig('hero_text');
// Update when remote config loads
grain.onConfigsUpdated(() => {
heroText.value = grain.getConfig('hero_text');
});
});
const handleClick = () => {
grain.track('button_clicked', {
location: 'hero'
});
};
</script>
Svelte Example
Using Grain in a Svelte component:
<script>
import { onMount } from 'svelte';
import { grain } from './grain'; // Your initialized client
let heroText = 'Welcome!';
onMount(() => {
// Get initial config value
heroText = grain.getConfig('hero_text');
// Update when remote config loads
grain.onConfigsUpdated(() => {
heroText = grain.getConfig('hero_text');
});
});
function handleClick() {
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:
// 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
});
});
// For client-side navigation (general)
const originalPushState = history.pushState;
history.pushState = function(...args) {
originalPushState.apply(this, args);
grain.track('page_viewed', {
page: window.location.pathname
});
};
What’s Next?
TypeScript users: The SDK is written in TypeScript and includes full type definitions. You’ll get autocomplete and type checking out of the box.