Skip to main content

What Are Events?

Events represent actions that happen in your application. Every time a user clicks a button, views a page, or completes a purchase, you can track it as an event. Think of events as a timeline of what users do in your app. By tracking these actions, you can:
  • Understand which features users engage with most
  • Identify where users drop off in your funnel
  • Measure the impact of changes to your product

Basic Event Tracking

The simplest way to track an event is with a name and properties:
Anatomy of an event:
  • Event name (button_clicked): What happened
  • Properties (button_name, page): Context about the event
Event names should be clear and descriptive. Use past tense to indicate an action that already happened.
Want a systematic approach to naming? Our Event Naming Convention guide provides a hierarchical structure that makes events consistent and easy to query.

Event Properties

Properties add context to events. They answer questions like “which button?” or “how much?”:
Best practices:
  • Include relevant context (IDs, names, amounts)
  • Use consistent naming (snake_case or camelCase)
  • Avoid sensitive data (passwords, credit cards)
  • Keep property names simple and clear

Automatic Batching

Here’s where Grain saves you effort: events are automatically batched for efficiency. What is batching? Instead of sending each event immediately (slow and expensive), Grain collects events and sends them in groups.
Default behavior:
  • Events batch every 5 seconds
  • Or when 50 events accumulate
  • Whichever comes first
You can customize this:

Manual Flushing

Sometimes you need to send events immediately:
When to flush manually:
  • Critical events (purchases, signups)
  • Before app closes or logs out
  • In serverless functions
One-time flush: Pass flush: true to track():

User Association

Events are more valuable when you know who performed them. Use identify() to associate events with a specific user:
Without a user ID, events are anonymous. This is fine for public websites, but for authenticated apps, always identify the user.

Event Lifecycle

Understanding what happens to events helps you track effectively:
  1. Track: You call track()
  2. Queue: Event added to internal queue
  3. Batch: Queue accumulates until batch size or interval
  4. Send: Batch sent to Grain API
  5. Retry: If failed, retry with exponential backoff
  6. Success: Event stored in Grain analytics

Reliable Delivery

Grain Tag ensures events are not lost, even when:
  • Network is slow or fails temporarily
  • User closes the browser
  • App crashes
Automatic page exit handling: Grain Tag automatically listens for beforeunload, pagehide, and visibilitychange events and uses the Beacon API to flush pending events. You do not need to add your own event listeners for page exit — this is handled for you out of the box.

Common Patterns

Page View Tracking

Grain Tag auto-tracks page views (including SPA navigations via the History API), so you typically do not need to track these manually. If you need custom page view events:

Button Click Tracking

Form Submission

Debug Mode

Not sure if events are sending? Enable debug mode in two ways: Via URL parameter — add ?grain_debug=1 to any page URL. This enables debug logging in the browser console without changing code. Via config:
You’ll see logs for queueing, batching, sending, and responses.

Next Steps

User Identification

Learn to track users across sessions

User Properties

Add attributes to user profiles

Template Events

Use pre-built event methods

API Reference

See all tracking methods
View your events in real-time at grainql.com/dashboard
These examples use @grainql/tag. If you’re using @grainql/analytics-web, replace imports with import { createGrainAnalytics } from '@grainql/analytics-web' and use grain.track() on the client instance.