Practical guide with real examples that show how to implement tracking across different scenarios.
"use client";
import { landingPageEvents } from "@/app/lib/analytics-events";
import { getCurrentPageMetadata } from "@/app/lib/analytics";
export default function CTAButton() {
const handleClick = () => {
const metadata = getCurrentPageMetadata();
landingPageEvents.storeCTAClick({
...metadata,
destination: "/pt/loja",
});
};
return (
<button
onClick={handleClick}
className="bg-accent-orange px-6 py-3 rounded-full"
>
View Store
</button>
);
}"use client";
import { landingPageEvents } from "@/app/lib/analytics-events";
import { getCurrentPageMetadata } from "@/app/lib/analytics";
export default function SocialLink({ platform, url }: { platform: string; url: string }) {
const handleClick = () => {
const metadata = getCurrentPageMetadata();
landingPageEvents.footerSocialClick({
...metadata,
social_platform: platform,
destination: url,
});
};
return (
<a
href={url}
target="_blank"
rel="noopener noreferrer"
onClick={handleClick}
>
{platform}
</a>
);
}"use client";
import { useState } from "react";
import { contactEvents } from "@/app/lib/analytics-events";
import { getCurrentPageMetadata } from "@/app/lib/analytics";
export default function ContactForm() {
const [hasStarted, setHasStarted] = useState(false);
const handleFirstInteraction = (fieldName: string) => {
if (hasStarted) return;
setHasStarted(true);
const metadata = getCurrentPageMetadata();
contactEvents.formStart({
...metadata,
form_id: "contact_main",
});
};
return (
<form>
<input
name="name"
onFocus={() => handleFirstInteraction("name")}
placeholder="Your name"
/>
<input
name="email"
onFocus={() => handleFirstInteraction("email")}
placeholder="Your email"
/>
</form>
);
}"use client";
import { contactEvents } from "@/app/lib/analytics-events";
import { getCurrentPageMetadata } from "@/app/lib/analytics";
export default function ContactForm() {
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData(e.currentTarget as HTMLFormElement);
const subject = formData.get("subject") as string;
try {
const response = await sendForm(formData);
if (response.success) {
// Track success
const metadata = getCurrentPageMetadata();
contactEvents.formSubmit({
...metadata,
form_id: "contact_main",
form_subject: subject,
success: true,
});
} else {
// Track error
const metadata = getCurrentPageMetadata();
contactEvents.formError({
...metadata,
form_id: "contact_main",
error_type: "validation",
error_field: response.errorField,
});
}
} catch (error) {
const metadata = getCurrentPageMetadata();
contactEvents.formError({
...metadata,
form_id: "contact_main",
error_type: "network",
});
}
};
return (
<form onSubmit={handleSubmit}>
{/* form fields */}
</form>
);
}"use client";
import Link from "next/link";
import { blogEvents } from "@/app/lib/analytics-events";
import { getCurrentPageMetadata } from "@/app/lib/analytics";
type BlogPostCardProps = {
post: {
id: string;
title: string;
slug: string;
category: string;
};
};
export default function BlogPostCard({ post }: BlogPostCardProps) {
const handleClick = () => {
const metadata = getCurrentPageMetadata();
blogEvents.postCardClick({
...metadata,
post_id: post.id,
post_title: post.title,
post_category: post.category,
});
};
return (
<Link
href={`/blog/${post.slug}`}
onClick={handleClick}
>
<h3>{post.title}</h3>
<span>{post.category}</span>
</Link>
);
}"use client";
import { storeEvents } from "@/app/lib/analytics-events";
import { getCurrentPageMetadata } from "@/app/lib/analytics";
type TemplateCardProps = {
template: {
id: string;
name: string;
price: number;
priceType: "free" | "one-time" | "subscription";
demoUrl: string;
};
};
export default function TemplateCard({ template }: TemplateCardProps) {
const metadata = getCurrentPageMetadata();
const handleDemoClick = () => {
storeEvents.templateDemoClick({
...metadata,
template_id: template.id,
template_name: template.name,
});
};
const handlePurchaseClick = () => {
storeEvents.initiateCheckout({
...metadata,
template_id: template.id,
template_name: template.name,
price: template.price,
price_type: template.priceType,
});
};
return (
<div>
<h3>{template.name}</h3>
<p>R$ {template.price}</p>
<a
href={template.demoUrl}
target="_blank"
onClick={handleDemoClick}
>
View Demo
</a>
<button onClick={handlePurchaseClick}>
{template.priceType === "free" ? "Download" : "Comprar"}
</button>
</div>
);
}"use client";
import { blogEvents } from "@/app/lib/analytics-events";
import { getCurrentPageMetadata } from "@/app/lib/analytics";
export default function CategoryFilter() {
const handleFilterChange = (category: string) => {
const metadata = getCurrentPageMetadata();
blogEvents.filterChange({
...metadata,
filter_type: "category",
filter_value: category,
});
};
return (
<select onChange={(e) => handleFilterChange(e.target.value)}>
<option value="all">Todas</option>
<option value="frontend">Frontend</option>
<option value="backend">Backend</option>
<option value="mobile">Mobile</option>
</select>
);
}"use client";
import { useState } from "react";
import { blogEvents } from "@/app/lib/analytics-events";
import { getCurrentPageMetadata } from "@/app/lib/analytics";
export default function SearchBar({ onSearch }: { onSearch: (query: string) => void }) {
const [query, setQuery] = useState("");
const handleSearch = () => {
const results = performSearch(query); // your search logic
const metadata = getCurrentPageMetadata();
blogEvents.searchQuery({
...metadata,
search_query: query,
results_count: results.length,
});
onSearch(query);
};
return (
<div>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
onKeyPress={(e) => e.key === "Enter" && handleSearch()}
placeholder="Buscar..."
/>
<button onClick={handleSearch}>Buscar</button>
</div>
);
}"use client";
import { useEffect } from "react";
import { insightsEvents } from "@/app/lib/analytics-events";
import { getCurrentPageMetadata } from "@/app/lib/analytics";
type LeadMagnetModalProps = {
isOpen: boolean;
insightId: string;
leadMagnetTitle: string;
};
export default function LeadMagnetModal({
isOpen,
insightId,
leadMagnetTitle
}: LeadMagnetModalProps) {
useEffect(() => {
if (isOpen) {
const metadata = getCurrentPageMetadata();
insightsEvents.leadMagnetView({
...metadata,
insight_id: insightId,
lead_magnet_title: leadMagnetTitle,
});
}
}, [isOpen, insightId, leadMagnetTitle]);
if (!isOpen) return null;
return (
<div className="modal">
<h2>{leadMagnetTitle}</h2>
{/* modal content */}
</div>
);
}"use client";
import { insightsEvents } from "@/app/lib/analytics-events";
import { getCurrentPageMetadata } from "@/app/lib/analytics";
type LeadMagnetModalProps = {
insightId: string;
leadMagnetTitle: string;
};
export default function LeadMagnetModal({ insightId, leadMagnetTitle }: LeadMagnetModalProps) {
const [email, setEmail] = useState("");
const handleDownload = async () => {
const hasEmail = email.trim().length > 0;
// Track download
const metadata = getCurrentPageMetadata();
insightsEvents.leadMagnetDownload({
...metadata,
insight_id: insightId,
lead_magnet_title: leadMagnetTitle,
email_captured: hasEmail,
});
// Proceed with download
if (hasEmail) {
await saveEmail(email);
}
downloadFile();
};
return (
<div>
<input
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email (optional)"
/>
<button onClick={handleDownload}>
Download
</button>
</div>
);
}"use client";
import { useEffect, useState } from "react";
import { blogEvents } from "@/app/lib/analytics-events";
import { getCurrentPageMetadata } from "@/app/lib/analytics";
type ReadingProgressProps = {
postId: string;
};
export default function ReadingProgress({ postId }: ReadingProgressProps) {
const [trackedMilestones, setTrackedMilestones] = useState<number[]>([]);
useEffect(() => {
const handleScroll = () => {
const windowHeight = window.innerHeight;
const documentHeight = document.documentElement.scrollHeight - windowHeight;
const scrolled = window.scrollY;
const progress = Math.round((scrolled / documentHeight) * 100);
// Track milestones: 25%, 50%, 75%, 100%
const milestones = [25, 50, 75, 100];
milestones.forEach((milestone) => {
if (
progress >= milestone &&
!trackedMilestones.includes(milestone)
) {
const metadata = getCurrentPageMetadata();
blogEvents.readingProgress({
...metadata,
post_id: postId,
progress_percentage: milestone,
});
setTrackedMilestones(prev => [...prev, milestone]);
}
});
};
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, [postId, trackedMilestones]);
return null; // This component does not render anything
}"use client";
import { uiEvents } from "@/app/lib/analytics-events";
import { getCurrentPageMetadata } from "@/app/lib/analytics";
export default function ScrollToSectionButton({ sectionId }: { sectionId: string }) {
const handleClick = () => {
const metadata = getCurrentPageMetadata();
uiEvents.scrollToSection({
...metadata,
section_id: sectionId,
});
// Scroll to section
const element = document.getElementById(sectionId);
element?.scrollIntoView({ behavior: "smooth" });
};
return (
<button onClick={handleClick}>
Go to {sectionId}
</button>
);
}"use client";
import { storeEvents } from "@/app/lib/analytics-events";
import { getCurrentPageMetadata } from "@/app/lib/analytics";
import { useStripeCheckout } from "@/app/hooks/use-stripe";
type BuyButtonProps = {
template: {
id: string;
name: string;
price: number;
priceType: "one-time" | "subscription";
stripePriceId: string;
};
};
export default function BuyButton({ template }: BuyButtonProps) {
const { initiateCheckout, isLoading } = useStripeCheckout();
const handleBuy = async () => {
// Track initiate checkout
const metadata = getCurrentPageMetadata();
storeEvents.initiateCheckout({
...metadata,
template_id: template.id,
template_name: template.name,
price: template.price,
price_type: template.priceType,
});
// Proceed with Stripe checkout
await initiateCheckout({
priceId: template.stripePriceId,
isSubscription: template.priceType === "subscription",
metadata: {
templateId: template.id,
templateName: template.name,
},
});
};
return (
<button onClick={handleBuy} disabled={isLoading}>
{isLoading ? "Processing..." : "Buy"}
</button>
);
}"use client";
import { useEffect } from "react";
import { useSearchParams } from "next/navigation";
import { storeEvents } from "@/app/lib/analytics-events";
import { getCurrentPageMetadata } from "@/app/lib/analytics";
export default function PurchaseSuccessPage() {
const searchParams = useSearchParams();
useEffect(() => {
const templateId = searchParams.get("template");
const sessionId = searchParams.get("session_id");
if (templateId && sessionId) {
// Fetch purchase details from your API
fetchPurchaseDetails(sessionId).then((purchase) => {
const metadata = getCurrentPageMetadata();
storeEvents.purchase({
...metadata,
template_id: purchase.templateId,
template_name: purchase.templateName,
price: purchase.amount,
price_type: purchase.priceType,
transaction_id: purchase.transactionId,
});
});
}
}, [searchParams]);
return (
<div>
<h1>Purchase completed successfully!</h1>
</div>
);
}getCurrentPageMetadata()// ✅ GOOD
const metadata = getCurrentPageMetadata();
landingPageEvents.heroCTAClick({
...metadata,
destination: "/pt#projects",
cta_type: "primary",
});
// ❌ BAD - missing parameters
landingPageEvents.heroCTAClick({
destination: "/pt#projects",
cta_type: "primary",
});// ✅ GOOD - Track on click
<button onClick={() => {
trackEvent();
performAction();
}}>
Click me
</button>
// ❌ RUIM - Track no render
useEffect(() => {
trackEvent(); // Will fire multiple times
}, []);// ✅ GOOD - TypeScript will validate
blogEvents.postCardClick({
...metadata,
post_id: "123",
post_title: "Title",
post_category: "frontend",
});
// ❌ BAD - incorrect parameter
blogEvents.postCardClick({
...metadata,
postId: "123", // Deveria ser post_id
});try {
const metadata = getCurrentPageMetadata();
blogEvents.postCardClick({
...metadata,
post_id: post.id,
post_title: post.title,
post_category: post.category,
});
} catch (error) {
// Do not break the app if tracking fails
console.error("Tracking error:", error);
}Now that you’ve seen the examples, add tracking to:
blog-list-client.tsx)post-reactions.tsx, post-share.tsx)templates-grid.tsx)project-card.tsx)insight-card.tsx)footer-client.tsx)Use estes exemplos como base e adapte para seus componentes!
Related documentation:
GA_EVENTS_DOCUMENTATION.md - Full documentationGA_EVENTS_QUICK_REFERENCE.md - Quick referencesrc/app/lib/analytics-events.ts - Source code