feat(analytics): enhance Google Analytics with privacy compliance and comprehensive tracking
- Add automatic route change tracking for SPA navigation - Implement Cookie consent banner for GDPR compliance - Add performance tracking (LCP, FID, CLS Web Vitals) - Add outbound link click tracking - Integrate contact form submission tracking with conversion events - Add CTA button click tracking in hero section - Integrate error tracking in ErrorBoundary component - Extend analytics utility library with 15+ tracking functions - Configure IP anonymization and privacy settings - Remove unused test files and deployment scripts - Update case studies to include only specified cases - Fix mobile navigation active state issues - Fix lint errors in test files and components BREAKING CHANGE: Google Analytics now requires user consent before tracking
This commit is contained in:
+125
-3
@@ -2,7 +2,11 @@ export const GA_MEASUREMENT_ID = process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID || ''
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
gtag: (command: string, targetId: string, config?: Record<string, unknown>) => void;
|
||||
gtag: (
|
||||
command: string,
|
||||
targetIdOrParams: string | Record<string, unknown>,
|
||||
config?: Record<string, unknown>
|
||||
) => void;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +28,16 @@ export const event = (action: string, category: string, label?: string, value?:
|
||||
}
|
||||
};
|
||||
|
||||
export const trackContactForm = (_formData: Record<string, string>) => {
|
||||
event('submit', 'contact_form', 'contact_form_submission');
|
||||
export const trackContactForm = (formData: Record<string, string>) => {
|
||||
event('generate_lead', 'engagement', 'contact_form_submission');
|
||||
|
||||
if (typeof window !== 'undefined' && window.gtag && GA_MEASUREMENT_ID) {
|
||||
window.gtag('event', 'contact_form', {
|
||||
event_category: 'lead_generation',
|
||||
event_label: formData.company || 'unknown_company',
|
||||
company_size: formData.company ? 'provided' : 'not_provided',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const trackButtonClick = (buttonName: string, location: string) => {
|
||||
@@ -35,3 +47,113 @@ export const trackButtonClick = (buttonName: string, location: string) => {
|
||||
export const trackPageView = (pageTitle: string, _pagePath: string) => {
|
||||
event('page_view', 'navigation', pageTitle);
|
||||
};
|
||||
|
||||
export const trackConversion = (conversionName: string, value?: number) => {
|
||||
if (typeof window !== 'undefined' && window.gtag && GA_MEASUREMENT_ID) {
|
||||
window.gtag('event', 'conversion', {
|
||||
send_to: `${GA_MEASUREMENT_ID}/${conversionName}`,
|
||||
value: value,
|
||||
currency: 'CNY',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const trackError = (errorType: string, errorMessage: string, fatal: boolean = false) => {
|
||||
if (typeof window !== 'undefined' && window.gtag && GA_MEASUREMENT_ID) {
|
||||
window.gtag('event', 'exception', {
|
||||
description: `${errorType}: ${errorMessage}`,
|
||||
fatal: fatal,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const trackPerformance = (metricName: string, value: number) => {
|
||||
if (typeof window !== 'undefined' && window.gtag && GA_MEASUREMENT_ID) {
|
||||
window.gtag('event', 'web_vitals', {
|
||||
name: metricName,
|
||||
value: Math.round(value),
|
||||
event_category: 'Web Vitals',
|
||||
non_interaction: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const trackScrollDepth = (percentage: number) => {
|
||||
event('scroll', 'engagement', `${percentage}%`, percentage);
|
||||
};
|
||||
|
||||
export const trackDownload = (fileName: string, fileType: string) => {
|
||||
if (typeof window !== 'undefined' && window.gtag && GA_MEASUREMENT_ID) {
|
||||
window.gtag('event', 'file_download', {
|
||||
event_category: 'downloads',
|
||||
event_label: fileName,
|
||||
file_extension: fileType,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const trackOutboundLink = (url: string) => {
|
||||
if (typeof window !== 'undefined' && window.gtag && GA_MEASUREMENT_ID) {
|
||||
window.gtag('event', 'click', {
|
||||
event_category: 'outbound',
|
||||
event_label: url,
|
||||
transport_type: 'beacon',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const trackVideo = (action: 'play' | 'pause' | 'complete' | 'progress', videoTitle: string, progress?: number) => {
|
||||
if (typeof window !== 'undefined' && window.gtag && GA_MEASUREMENT_ID) {
|
||||
window.gtag('event', `video_${action}`, {
|
||||
event_category: 'videos',
|
||||
event_label: videoTitle,
|
||||
video_percent: progress,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const trackEngagement = (action: string, details?: Record<string, unknown>) => {
|
||||
if (typeof window !== 'undefined' && window.gtag && GA_MEASUREMENT_ID) {
|
||||
window.gtag('event', action, {
|
||||
event_category: 'engagement',
|
||||
...details,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const trackSectionView = (sectionName: string) => {
|
||||
event('section_view', 'navigation', sectionName);
|
||||
};
|
||||
|
||||
export const trackCaseView = (caseId: string, caseTitle: string) => {
|
||||
if (typeof window !== 'undefined' && window.gtag && GA_MEASUREMENT_ID) {
|
||||
window.gtag('event', 'view_item', {
|
||||
event_category: 'case_studies',
|
||||
event_label: caseTitle,
|
||||
item_id: caseId,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const trackServiceInterest = (serviceName: string) => {
|
||||
event('service_interest', 'engagement', serviceName);
|
||||
};
|
||||
|
||||
export const trackProductView = (productId: string, productName: string) => {
|
||||
if (typeof window !== 'undefined' && window.gtag && GA_MEASUREMENT_ID) {
|
||||
window.gtag('event', 'view_item', {
|
||||
event_category: 'products',
|
||||
event_label: productName,
|
||||
item_id: productId,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const updateConsent = (granted: boolean) => {
|
||||
if (typeof window !== 'undefined' && window.gtag) {
|
||||
window.gtag('consent', 'update', {
|
||||
analytics_storage: granted ? 'granted' : 'denied',
|
||||
ad_storage: 'denied',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user