npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

vue3-game-analytics

v0.2.2

Published

Comprehensive analytics tracking system for Vue 3 game applications

Readme

Vue 3 Game Analytics

License: MIT Vue version TypeScript

A lightweight, high-performance analytics tracking system for Vue 3 game applications. This package provides detailed tracking of user interactions with minimal dependencies and impact on gameplay performance.

🚀 Features

Hybrid Event Collection Architecture

  • App-level listeners for standard events (clicks, touches, keyboard input)
  • Game-specific context enrichment through data attributes
  • Support for both automatic collection and manual tracking

Lightweight Reactive Store

  • Custom reactive store for managing the events queue (no external dependencies)
  • Batch-processing events for API submission
  • Queue management (clear, filter, export) capabilities
  • Memory management to prevent excessive resource usage

Game-Specific Context

  • Tracks current game identifier and play_id for every interaction
  • Associates each event with its specific game context
  • Maintains game session continuity across different games

Rich Data Capture

  • Interaction coordinates (x, y positions)
  • Timestamps and duration of interactions
  • Element properties (type, state, game-specific attributes)
  • Game state association (level, score, progress)
  • Support for custom metadata attachment

Automatic Environment Data

  • Device info, viewport size, and browser details
  • Device orientation and screen resolution
  • Network connection status
  • Performance metrics relevant to gameplay

Performance Optimized

  • Efficient memory usage with circular buffer implementation
  • Throttling/debouncing for high-frequency events
  • Minimal impact on frame rates
  • Efficient data serialization

Debug Mode & Error Tracking

  • Debug mode with console logging
  • Error and exception tracking
  • Visual indicators of tracking in development mode
  • Verbose logging option for diagnostics

Developer Experience

  • Simple composable API (useGameAnalytics)
  • TypeScript definitions for strong typing
  • Vue directives for declarative tracking (v-track)
  • Support for both Options API and Composition API
  • Zero external dependencies (no Pinia required)

📦 Installation

npm install vue3-game-analytics

🔧 Basic Setup

// main.js or main.ts
import { createApp } from 'vue'
import App from './App.vue'
import VueGameAnalytics from 'vue3-game-analytics'
import { generateUUID } from 'vue3-game-analytics'

const app = createApp(App)

app.use(VueGameAnalytics, {
  apiEndpoint: '/api/analytics',
  gameId: 'memory-match',
  playId: generateUUID(),
  batchSize: 50,
  flushInterval: 60000, // 1 minute
  debug: process.env.NODE_ENV !== 'production'
})

app.mount('#app')

💻 Usage

Composition API

<script setup>
import { useGameAnalytics } from 'vue3-game-analytics';
import { ref } from 'vue';

const { trackEvent, trackElement, trackTimedInteraction } = useGameAnalytics();

// Tracking elements with refs
const buttonRef = ref(null);
const trackButton = trackElement(buttonRef, { 
  type: 'button_click',
  metadata: { section: 'game-controls' }
});

// Tracking custom events
function onLevelComplete(level, score) {
  trackEvent({
    type: 'level_complete',
    gameState: {
      level,
      score
    },
    metadata: {
      timeTaken: playTime,
      difficulty: currentDifficulty
    }
  });
}

// Tracking timed interactions
const gameTimer = trackTimedInteraction('gameplay_session');

function startGame() {
  gameTimer.start({ difficulty: 'hard' });
}

function endGame() {
  const duration = gameTimer.end({ 
    finalScore: playerScore,
    levelsCompleted: levels 
  });
  console.log(`Game lasted ${duration}ms`);
}
</script>

<template>
  <div>
    <button ref="buttonRef" @click="trackButton('click')">Start Game</button>
    
    <!-- Using directive for declarative tracking -->
    <button v-track="{ event: 'click', context: { buttonType: 'restart' } }">
      Restart Game
    </button>
    
    <!-- Track different events on the same element -->
    <div v-track:mouseenter="{ event: 'hover_start', context: { area: 'bonus' } }"
         v-track:mouseleave="{ event: 'hover_end', context: { area: 'bonus' } }">
      Bonus Area
    </div>
  </div>
</template>

Options API

<template>
  <button @click="trackButtonClick">Play</button>
</template>

<script>
export default {
  methods: {
    trackButtonClick() {
      this.$gameAnalytics.trackEvent({
        type: 'button_click',
        target: 'play_button',
        metadata: {
          screen: 'main_menu'
        }
      });
    },
    
    startLevel(level) {
      // Track game state
      this.$gameAnalytics.trackEvent({
        type: 'level_start',
        gameState: {
          level,
          lives: this.playerLives,
          score: this.score
        }
      });
    },
    
    flushDataBeforeNavigation() {
      // Force-send all pending events before navigation
      this.$gameAnalytics.flushEvents().then(() => {
        this.$router.push('/next-page');
      });
    }
  }
}
</script>

⚙️ Configuration Options

The plugin supports numerous configuration options to customize its behavior:

interface GameAnalyticsOptions {
  // Required configuration
  apiEndpoint: string;            // API endpoint for sending analytics data
  gameId: string;                 // Identifier for the current game
  playId: string;                 // Unique identifier for the current play session
  
  // Optional configuration with defaults
  batchSize?: number;             // Default: 50 - Events to collect before sending
  flushInterval?: number;         // Default: 60000 (1 min) - Time between auto-flush
  maxQueueSize?: number;          // Default: 1000 - Maximum events to store in memory
  
  // Tracking options
  trackClicks?: boolean;          // Default: true - Track clicks automatically
  trackTouches?: boolean;         // Default: true - Track touch events
  trackKeyboard?: boolean;        // Default: true - Track keyboard events
  trackErrors?: boolean;          // Default: true - Track JS errors
  trackNetwork?: boolean;         // Default: true - Track network status
  trackPerformance?: boolean;     // Default: false - Track performance metrics
  
  // Sampling and optimization
  sampleRate?: number;            // Default: 1 - Sampling rate for events (0-1)
  throttleHighFrequencyEvents?: boolean; // Default: true - Throttle high-frequency events
  throttleInterval?: number;      // Default: 100 - Throttle interval in ms
  
  // Debug options
  debug?: boolean;                // Default: false - Enable debug mode 
  verboseLogging?: boolean;       // Default: false - Enable verbose console logging
  visibleTracking?: boolean;      // Default: false - Show visual indicators
  
  // Privacy
  anonymizeIp?: boolean;          // Default: true - Anonymize IP addresses
  respectDoNotTrack?: boolean;    // Default: true - Respect DNT browser setting
  consentRequired?: boolean;      // Default: true - Require user consent
  
  // Advanced customization
  eventTransformer?: (event: GameAnalyticsEvent) => GameAnalyticsEvent;
}

📋 API Reference

Composable: useGameAnalytics()

// Core tracking methods
trackEvent(event: Partial<GameAnalyticsEvent>): void
trackElement(elementRef: Ref<HTMLElement>, options?: Object): Function
trackTimedInteraction(identifier: string): { start, end, cancel }
trackGameState(state: Record<string, any>): void

// Utility methods
flushEvents(): Promise<void>
clearEvents(): void

// Debug methods
enableDebug(): void
disableDebug(): void
isDebugMode: ComputedRef<boolean>

// Privacy and consent
setConsent(hasConsent: boolean): void
hasConsent: ComputedRef<boolean>

// Store information
eventCount: ComputedRef<number>
isEnabled: ComputedRef<boolean>
isOnline: ComputedRef<boolean>

Directive: v-track

<!-- Basic usage -->
<button v-track>Track clicks</button>

<!-- Specify event type -->
<button v-track:click>Track clicks</button>
<div v-track:mouseover>Track hover</div>

<!-- With options -->
<button v-track="{ event: 'button_click', target: 'play-button', context: { screen: 'menu' } }">
  Play
</button>

<!-- Multiple events on same element -->
<div v-track:mouseenter="{ event: 'hover_start' }"
     v-track:mouseleave="{ event: 'hover_end' }">
  Hover me
</div>

Global Properties

// Available on this.$gameAnalytics
interface GameAnalyticsGlobal {
  trackEvent: (event: any) => void;
  flushEvents: () => Promise<void>;
  enableDebug: () => void;
  disableDebug: () => void;
  clearEvents: () => void;
  getEventCount: () => number;
  setConsent: (hasConsent: boolean) => void;
}

📊 Event Structure

All tracked events follow this structure:

interface GameAnalyticsEvent {
  // Core properties
  id?: string;                    // Auto-generated unique ID
  timestamp: number;              // Auto-filled timestamp
  type: string;                   // Event type (e.g., 'click', 'level_complete')
  
  // Game context
  gameId: string;                 // From configuration
  playId: string;                 // From configuration
  gameState?: {                   // Current game state
    level?: number | string;
    score?: number;
    progress?: number;
    [key: string]: any;
  };
  
  // Interaction details
  target?: string;                // Target element identifier
  coordinates?: {                 // Position data for mouse/touch events
    x: number;
    y: number;
    screenX?: number;
    screenY?: number;
  };
  duration?: number;              // For timed interactions
  
  // Element data
  elementData?: {
    type?: string;                // Element type (button, div, etc.)
    state?: string;               // Element state
    attributes?: Record<string, string>; // Data attributes
    [key: string]: any;
  };
  
  // Environment data (auto-collected if enabled)
  environmentData?: {
    deviceType?: string;          // mobile, tablet, desktop
    browser?: string;
    os?: string;
    screenResolution?: string;
    orientation?: string;
    connectionType?: string;
    performanceMetrics?: {
      fps?: number;
      memoryUsage?: number;
      [key: string]: any;
    };
  };
  
  // Custom data
  metadata?: Record<string, any>; // Any additional information
  
  // Error context (for error events)
  error?: {
    message?: string;
    stack?: string;
    code?: string | number;
  };
}

💡 Best Practices

  1. Use data attributes for game context:

    <button data-game-id="play_button" data-game-level="3" data-game-context="main_screen">
      Play Level
    </button>
  2. Batch related events: For high-frequency events (like mouse movements in a drawing game), consider batching related events and sending only key points.

  3. Balance detail and performance: Capture enough detail to be useful without impacting game performance. Use the sampling rate for very high-frequency events.

  4. Structure game state consistently: Define a standard structure for your game state to make analytics data more consistent and easier to analyze.

  5. Handle offline scenarios: The plugin handles offline storage automatically, but consider adding UI indicators when in offline mode.

🎮 Demo Application

The package includes a demo application that shows real-time analytics tracking in action:

# Run the demo application
npm run demo

The demo application provides:

  • An interactive memory game example to generate tracking events
  • Real-time display of tracked events in the UI
  • Controls to enable/disable debug mode
  • Manual event flushing
  • Visual indicators when interactions are tracked
  • Interception of API calls to display the exact data being sent

This is an excellent way to understand how the analytics package works and to see the different tracking methods in action:

  • Automatic tracking through app-level event listeners
  • Manual tracking using trackEvent
  • Element tracking with trackElement
  • Timed interactions with trackTimedInteraction
  • Declarative tracking with the v-track directive

The demo code is available in the /demo directory and can serve as a reference implementation.

Demo Screenshot

When running the demo application, you'll see an interface like this:

+-----------------------------------------------+
| Game Analytics Demo              [Enable Debug]|
|                                  [Disable Debug]|
| +-----------------------------------------+   |
| |                                         |   |
| |  Memory Game Example                    |   |
| |                                         |   |
| |  [Start Game] [Reset]   Score: 0        |   |
| |                                         |   |
| |  +-----+ +-----+ +-----+ +-----+        |   |
| |  |  ?  | |  ?  | |  ?  | |  ?  |        |   |
| |  +-----+ +-----+ +-----+ +-----+        |   |
| |                                         |   |
| |  +-----+ +-----+ +-----+ +-----+        |   |
| |  |  ?  | |  ?  | |  ?  | |  ?  |        |   |
| |  +-----+ +-----+ +-----+ +-----+        |   |
| |                                         |   |
| +-----------------------------------------+   |
|                                               |
| Events Logged:                                |
| +------------------------------------------+  |
| | [                                        |  |
| |   {                                      |  |
| |     "id": "f47ac10b-58cc-4372-a567...",  |  |
| |     "timestamp": 1678234827412,          |  |
| |     "type": "click",                     |  |
| |     "gameId": "demo-game",               |  |
| |     "playId": "7b16e04c-5671-4b35...",   |  |
| |     "target": "#start-button",           |  |
| |     ...                                  |  |
| |   }                                      |  |
| | ]                                        |  |
| +------------------------------------------+  |
+-----------------------------------------------+

As you interact with the game, you'll see:

  1. Visual indicators appearing where you click (red dots)
  2. Events being logged in real-time in the bottom panel
  3. The number of events in the queue updating
  4. Console logs with detailed event information (when debug mode is enabled)

🛠️ Development and Testing

# Install dependencies
npm install

# Start development server
npm run dev

# Build for production
npm run build

# Run tests
npm run test

# Run tests with coverage
npm run test -- --coverage

# Run tests in watch mode
npm run test:watch

This package includes comprehensive unit tests for:

  • Utility functions - Basic helper functions and performance optimizations
  • CircularBuffer - The memory-efficient data structure for event storage
  • Composables - The useGameAnalytics hook and its functionality
  • Directives - The v-track directive for declarative event tracking

The tests use Vitest with JSDOM for DOM simulation. You can run the tests with code coverage to ensure high-quality, maintainable code.

🔄 Migration from Previous Versions

Removal of Pinia Dependency

Starting from version 0.2.0, this package no longer requires Pinia as a dependency. The analytics store is now implemented using Vue's native reactive system, making the package lighter and more portable while maintaining the same API.

What this means for you:

  • No need to install or configure Pinia
  • Smaller bundle size
  • Fewer potential version conflicts
  • Same familiar API - all composables and methods work exactly as before

If you're upgrading from a previous version:

  1. Remove Pinia installation from your setup code
  2. Remove the createPinia() and app.use(pinia) calls
  3. Everything else remains the same!

The change is completely backward compatible in terms of functionality - only the setup process has been simplified.

📄 License

License: MIT