1. ✅ 安装依赖: posthog-js@^1.280.1 2. ✅ 创建核心文件: - src/lib/posthog.js - PostHog SDK 封装(271 行) - src/lib/constants.js - 事件常量定义(AARRR 框架) - src/hooks/usePostHog.js - PostHog React Hook - src/hooks/usePageTracking.js - 页面追踪 Hook - src/components/PostHogProvider.js - Provider 组件 3. ✅ 集成到应用: - 修改 src/App.js,在最外层添加 <PostHogProvider> - 自动追踪所有页面浏览 4. ✅ 配置环境变量: - 在 .env 添加 PostHog 配置项 - REACT_APP_POSTHOG_KEY 留空,需要用户填写 5. ✅ 创建文档: POSTHOG_INTEGRATION.md 包含完整的使用说明
272 lines
6.9 KiB
JavaScript
272 lines
6.9 KiB
JavaScript
// src/lib/posthog.js
|
|
import posthog from 'posthog-js';
|
|
|
|
/**
|
|
* Initialize PostHog SDK
|
|
* Should be called once when the app starts
|
|
*/
|
|
export const initPostHog = () => {
|
|
// Only run in browser environment
|
|
if (typeof window === 'undefined') return;
|
|
|
|
const apiKey = process.env.REACT_APP_POSTHOG_KEY;
|
|
const apiHost = process.env.REACT_APP_POSTHOG_HOST || 'https://app.posthog.com';
|
|
|
|
if (!apiKey) {
|
|
console.warn('⚠️ PostHog API key not found. Analytics will be disabled.');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
posthog.init(apiKey, {
|
|
api_host: apiHost,
|
|
|
|
// Pageview tracking - manual control for better accuracy
|
|
capture_pageview: false, // We'll manually capture with custom properties
|
|
capture_pageleave: true, // Auto-capture when user leaves page
|
|
|
|
// Session Recording Configuration
|
|
session_recording: {
|
|
enabled: process.env.REACT_APP_ENABLE_SESSION_RECORDING === 'true',
|
|
|
|
// Privacy: Mask sensitive input fields
|
|
maskInputOptions: {
|
|
password: true,
|
|
email: true,
|
|
phone: true,
|
|
'data-sensitive': true, // Custom attribute for sensitive fields
|
|
},
|
|
|
|
// Record canvas for charts/graphs
|
|
recordCanvas: true,
|
|
|
|
// Network payload capture (useful for debugging API issues)
|
|
networkPayloadCapture: {
|
|
recordHeaders: true,
|
|
recordBody: true,
|
|
// Don't record sensitive endpoints
|
|
urlBlocklist: [
|
|
'/api/auth/session',
|
|
'/api/auth/login',
|
|
'/api/auth/register',
|
|
'/api/payment',
|
|
],
|
|
},
|
|
},
|
|
|
|
// Performance optimization
|
|
batch_size: 10, // Send events in batches of 10
|
|
batch_interval_ms: 3000, // Or every 3 seconds
|
|
|
|
// Privacy settings
|
|
respect_dnt: true, // Respect Do Not Track browser setting
|
|
persistence: 'localStorage+cookie', // Use both for reliability
|
|
|
|
// Feature flags (for A/B testing)
|
|
bootstrap: {
|
|
featureFlags: {},
|
|
},
|
|
|
|
// Autocapture settings
|
|
autocapture: {
|
|
// Automatically capture clicks on buttons, links, etc.
|
|
dom_event_allowlist: ['click', 'submit', 'change'],
|
|
|
|
// Capture additional element properties
|
|
capture_copied_text: false, // Don't capture copied text (privacy)
|
|
},
|
|
|
|
// Development debugging
|
|
loaded: (posthogInstance) => {
|
|
if (process.env.NODE_ENV === 'development') {
|
|
console.log('✅ PostHog initialized successfully');
|
|
posthogInstance.debug(); // Enable debug mode in development
|
|
}
|
|
},
|
|
});
|
|
|
|
console.log('📊 PostHog Analytics initialized');
|
|
} catch (error) {
|
|
console.error('❌ PostHog initialization failed:', error);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Get PostHog instance
|
|
* @returns {object} PostHog instance
|
|
*/
|
|
export const getPostHog = () => {
|
|
return posthog;
|
|
};
|
|
|
|
/**
|
|
* Identify user with PostHog
|
|
* Call this after successful login/registration
|
|
*
|
|
* @param {string} userId - Unique user identifier
|
|
* @param {object} userProperties - User properties (email, name, subscription_tier, etc.)
|
|
*/
|
|
export const identifyUser = (userId, userProperties = {}) => {
|
|
if (!userId) {
|
|
console.warn('⚠️ Cannot identify user: userId is required');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
posthog.identify(userId, {
|
|
email: userProperties.email,
|
|
username: userProperties.username,
|
|
subscription_tier: userProperties.subscription_tier || 'free',
|
|
role: userProperties.role,
|
|
registration_date: userProperties.registration_date,
|
|
last_login: new Date().toISOString(),
|
|
...userProperties,
|
|
});
|
|
|
|
console.log('👤 User identified:', userId);
|
|
} catch (error) {
|
|
console.error('❌ User identification failed:', error);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Update user properties
|
|
* Use this to update user attributes without re-identifying
|
|
*
|
|
* @param {object} properties - Properties to update
|
|
*/
|
|
export const setUserProperties = (properties) => {
|
|
try {
|
|
posthog.people.set(properties);
|
|
console.log('📝 User properties updated');
|
|
} catch (error) {
|
|
console.error('❌ Failed to update user properties:', error);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Track custom event
|
|
*
|
|
* @param {string} eventName - Name of the event
|
|
* @param {object} properties - Event properties
|
|
*/
|
|
export const trackEvent = (eventName, properties = {}) => {
|
|
try {
|
|
posthog.capture(eventName, {
|
|
...properties,
|
|
timestamp: new Date().toISOString(),
|
|
});
|
|
|
|
if (process.env.NODE_ENV === 'development') {
|
|
console.log('📍 Event tracked:', eventName, properties);
|
|
}
|
|
} catch (error) {
|
|
console.error('❌ Event tracking failed:', error);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Track page view
|
|
*
|
|
* @param {string} pagePath - Current page path
|
|
* @param {object} properties - Additional properties
|
|
*/
|
|
export const trackPageView = (pagePath, properties = {}) => {
|
|
try {
|
|
posthog.capture('$pageview', {
|
|
$current_url: window.location.href,
|
|
page_path: pagePath,
|
|
page_title: document.title,
|
|
referrer: document.referrer,
|
|
...properties,
|
|
});
|
|
|
|
if (process.env.NODE_ENV === 'development') {
|
|
console.log('📄 Page view tracked:', pagePath);
|
|
}
|
|
} catch (error) {
|
|
console.error('❌ Page view tracking failed:', error);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Reset user session
|
|
* Call this on logout
|
|
*/
|
|
export const resetUser = () => {
|
|
try {
|
|
posthog.reset();
|
|
console.log('🔄 User session reset');
|
|
} catch (error) {
|
|
console.error('❌ Session reset failed:', error);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* User opt-out from tracking
|
|
*/
|
|
export const optOut = () => {
|
|
try {
|
|
posthog.opt_out_capturing();
|
|
console.log('🚫 User opted out of tracking');
|
|
} catch (error) {
|
|
console.error('❌ Opt-out failed:', error);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* User opt-in to tracking
|
|
*/
|
|
export const optIn = () => {
|
|
try {
|
|
posthog.opt_in_capturing();
|
|
console.log('✅ User opted in to tracking');
|
|
} catch (error) {
|
|
console.error('❌ Opt-in failed:', error);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Check if user has opted out
|
|
* @returns {boolean}
|
|
*/
|
|
export const hasOptedOut = () => {
|
|
try {
|
|
return posthog.has_opted_out_capturing();
|
|
} catch (error) {
|
|
console.error('❌ Failed to check opt-out status:', error);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Get feature flag value
|
|
* @param {string} flagKey - Feature flag key
|
|
* @param {any} defaultValue - Default value if flag not found
|
|
* @returns {any} Feature flag value
|
|
*/
|
|
export const getFeatureFlag = (flagKey, defaultValue = false) => {
|
|
try {
|
|
return posthog.getFeatureFlag(flagKey) || defaultValue;
|
|
} catch (error) {
|
|
console.error('❌ Failed to get feature flag:', error);
|
|
return defaultValue;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Check if feature flag is enabled
|
|
* @param {string} flagKey - Feature flag key
|
|
* @returns {boolean}
|
|
*/
|
|
export const isFeatureEnabled = (flagKey) => {
|
|
try {
|
|
return posthog.isFeatureEnabled(flagKey);
|
|
} catch (error) {
|
|
console.error('❌ Failed to check feature flag:', error);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
export default posthog;
|