feat: add GA4 key events tracking (run_simulation, open_example, create_project, compile_code, visit_github)

Co-authored-by: davidmonterocrespo24 <47928504+davidmonterocrespo24@users.noreply.github.com>
pull/37/head
copilot-swe-agent[bot] 2026-03-12 22:02:24 +00:00
parent 156a6159b7
commit 13ee547ad7
7 changed files with 163 additions and 3 deletions

108
docs/analytics.md Normal file
View File

@ -0,0 +1,108 @@
# Analytics Events
Velxio uses **Google Analytics 4 (GA4)** to measure key user interactions. Events are fired via `gtag` and should be marked as **Key Events** in the GA4 dashboard to track conversions and engagement.
The tracking utility lives in [`frontend/src/utils/analytics.ts`](../frontend/src/utils/analytics.ts).
---
## Key Events
### `run_simulation`
Fired when the user clicks the **Run** button to start a simulation.
| Property | Value |
|------------------|--------------|
| `event_category` | `engagement` |
**Location:** `EditorToolbar.tsx``handleRun()`
---
### `open_example`
Fired when a user loads a sample project from the Examples gallery.
| Property | Value |
|------------------|------------------------|
| `event_category` | `engagement` |
| `event_label` | Title of the example |
**Location:** `ExamplesPage.tsx``handleLoadExample()`
---
### `create_project`
Fired when a user successfully saves a **new** project (not when updating an existing one).
| Property | Value |
|------------------|--------------|
| `event_category` | `engagement` |
**Location:** `SaveProjectModal.tsx``handleSave()`
---
### `compile_code`
Fired when code compilation starts (user clicks the **Compile** button).
| Property | Value |
|------------------|---------------|
| `event_category` | `development` |
**Location:** `EditorToolbar.tsx``handleCompile()`
---
### `visit_github`
Fired when a user clicks any link pointing to the Velxio GitHub repository.
| Property | Value |
|------------------|-----------------|
| `event_category` | `external_link` |
**Locations:**
- `LandingPage.tsx` — nav bar, hero CTA, and footer GitHub links
- `AppHeader.tsx` — editor header GitHub link
---
## Implementation
All helpers are exported from `frontend/src/utils/analytics.ts`:
```typescript
import {
trackRunSimulation,
trackOpenExample,
trackCreateProject,
trackCompileCode,
trackVisitGitHub,
} from '../utils/analytics';
```
Example usage:
```typescript
// Fire an event
trackRunSimulation();
// Fire an event with a label
trackOpenExample('Blink LED');
```
The module safely checks whether `gtag` is available before calling it, so it does not throw errors in environments where the GA script is not loaded (e.g., local development without the GA tag).
---
## Marking Events as Key Events in GA4
1. Open **Google Analytics → Admin → Events**.
2. Locate the event by name (e.g. `run_simulation`).
3. Toggle **Mark as key event** to enable conversion tracking.
Repeat for each event listed above.

View File

@ -7,6 +7,7 @@ import { InstallLibrariesModal } from '../simulator/InstallLibrariesModal';
import { parseCompileResult } from '../../utils/compilationLogger';
import type { CompilationLog } from '../../utils/compilationLogger';
import { exportToWokwiZip, importFromWokwiZip } from '../../utils/wokwiZip';
import { trackCompileCode, trackRunSimulation } from '../../utils/analytics';
import './EditorToolbar.css';
interface EditorToolbarProps {
@ -43,6 +44,7 @@ export const EditorToolbar = ({ consoleOpen, setConsoleOpen, compileLogs: _compi
setCompiling(true);
setMessage(null);
setConsoleOpen(true);
trackCompileCode();
const fqbn = BOARD_FQBN[boardType];
const boardLabel = BOARD_LABELS[boardType];
@ -81,6 +83,7 @@ export const EditorToolbar = ({ consoleOpen, setConsoleOpen, compileLogs: _compi
const handleRun = () => {
if (compiledHex) {
trackRunSimulation();
startSimulation();
setMessage(null);
} else {

View File

@ -1,6 +1,7 @@
import { useState, useRef, useEffect } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { useAuthStore } from '../../store/useAuthStore';
import { trackVisitGitHub } from '../../utils/analytics';
interface AppHeaderProps {}
@ -55,6 +56,7 @@ export const AppHeader: React.FC<AppHeaderProps> = () => {
target="_blank"
rel="noopener noreferrer"
title="GitHub — Velxio"
onClick={trackVisitGitHub}
style={{ display: 'flex', alignItems: 'center', gap: 5, color: '#ccc', textDecoration: 'none', fontSize: 13 }}
>
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">

View File

@ -4,6 +4,7 @@ import { useEditorStore } from '../../store/useEditorStore';
import { useSimulatorStore } from '../../store/useSimulatorStore';
import { useProjectStore } from '../../store/useProjectStore';
import { createProject, updateProject } from '../../services/projectService';
import { trackCreateProject } from '../../utils/analytics';
interface SaveProjectModalProps {
onClose: () => void;
@ -56,6 +57,7 @@ export const SaveProjectModal: React.FC<SaveProjectModalProps> = ({ onClose }) =
saved = await updateProject(currentProject.id, payload);
} else {
saved = await createProject(payload);
trackCreateProject();
}
setCurrentProject({
id: saved.id,

View File

@ -10,6 +10,7 @@ import { ExamplesGallery } from '../components/examples/ExamplesGallery';
import { useEditorStore } from '../store/useEditorStore';
import { useSimulatorStore } from '../store/useSimulatorStore';
import type { ExampleProject } from '../data/examples';
import { trackOpenExample } from '../utils/analytics';
export const ExamplesPage: React.FC = () => {
const navigate = useNavigate();
@ -18,6 +19,7 @@ export const ExamplesPage: React.FC = () => {
const handleLoadExample = (example: ExampleProject) => {
console.log('Loading example:', example.title);
trackOpenExample(example.title);
// Switch board type if the example specifies one
const targetBoard = example.boardType || 'arduino-uno';

View File

@ -1,6 +1,7 @@
import { useState, useRef, useEffect } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { useAuthStore } from '../store/useAuthStore';
import { trackVisitGitHub } from '../utils/analytics';
import './LandingPage.css';
const GITHUB_URL = 'https://github.com/davidmonterocrespo24/velxio';
@ -417,7 +418,7 @@ export const LandingPage: React.FC = () => {
<span>Velxio</span>
</div>
<div className="landing-nav-links">
<a href={GITHUB_URL} target="_blank" rel="noopener noreferrer" className="nav-link">
<a href={GITHUB_URL} target="_blank" rel="noopener noreferrer" onClick={trackVisitGitHub} className="nav-link">
<IcoGitHub /> GitHub
</a>
<Link to="/docs" className="nav-link">Docs</Link>
@ -458,7 +459,7 @@ export const LandingPage: React.FC = () => {
<IcoZap />
Launch Editor
</Link>
<a href={GITHUB_URL} target="_blank" rel="noopener noreferrer" className="cta-secondary">
<a href={GITHUB_URL} target="_blank" rel="noopener noreferrer" onClick={trackVisitGitHub} className="cta-secondary">
<IcoGitHub />
View on GitHub
</a>
@ -564,7 +565,7 @@ export const LandingPage: React.FC = () => {
<span>Velxio</span>
</div>
<div className="footer-links">
<a href={GITHUB_URL} target="_blank" rel="noopener noreferrer">GitHub</a>
<a href={GITHUB_URL} target="_blank" rel="noopener noreferrer" onClick={trackVisitGitHub}>GitHub</a>
<Link to="/docs">Docs</Link>
<Link to="/examples">Examples</Link>
<Link to="/editor">Editor</Link>

View File

@ -0,0 +1,42 @@
/**
* Google Analytics 4 Key Events Tracking
*
* Provides helper functions to fire GA4 custom events for key user actions.
* Each function maps to an event that should be marked as a Key Event in GA4.
*/
declare function gtag(command: 'event', eventName: string, eventParams?: Record<string, unknown>): void;
function fireEvent(eventName: string, params: Record<string, string | number | boolean>): void {
if (typeof gtag === 'function') {
gtag('event', eventName, params);
}
}
/** Fired when the user starts a simulation (clicks Run). */
export function trackRunSimulation(): void {
fireEvent('run_simulation', { event_category: 'engagement' });
}
/** Fired when a user loads a sample project from the examples gallery. */
export function trackOpenExample(exampleTitle?: string): void {
fireEvent('open_example', {
event_category: 'engagement',
...(exampleTitle ? { event_label: exampleTitle } : {}),
});
}
/** Fired when a user successfully creates a new project. */
export function trackCreateProject(): void {
fireEvent('create_project', { event_category: 'engagement' });
}
/** Fired when code compilation starts. */
export function trackCompileCode(): void {
fireEvent('compile_code', { event_category: 'development' });
}
/** Fired when a user clicks any GitHub repository link. */
export function trackVisitGitHub(): void {
fireEvent('visit_github', { event_category: 'external_link' });
}