关于 posthog-debugger
用于检查网站 PostHog 实现的只读调试技能,面向开发者和产品团队。它结合页面脚本、浏览器对象、网络请求和控制台信息,整理配置与数据采集情况。
主要功能
- 01通过浏览器检查网站中的 PostHog
- 02检查脚本、全局对象和远程配置
- 03分析网络请求与调试控制台信息
- 04诊断事件、录制和功能标记状态
- 05只读检查并结构化汇总结果
适用场景
- 01核实网站是否安装并运行 PostHog
- 02排查事件请求未发送或控制台错误
- 03检查会话录制、调查和功能标记状态
- 04识别网站使用的分析与追踪工具
MCP 相关
该技能建议使用 Chrome DevTools MCP 或 Playwright MCP 浏览器工具导航和检查页面,并读取网络请求与控制台信息。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ posthog/ skills --skill posthog-debugger安装后在 Claude Code 中输入/posthog-debugger确认已加载。
附带文件.claude-plugin/plugin.jsonREADME.md
详细介绍
PostHog 调试器
使用浏览器自动化工具检查和调试任何网站上的 PostHog 实现。此技能可帮助开发者和产品团队准确了解 PostHog 的配置方式以及正在采集的数据。
关键规则
- 如果未提供网址,始终先询问网址。
- 始终询问页面是否需要登录。 如果需要,请引导用户先通过 Chrome 登录。
- 使用浏览器工具导航和检查。 优先使用 Chrome DevTools MCP(
mcp__chrome-devtools__*)或 Playwright MCP(mcp__playwright__*)工具。 - 检查多个信号。 PostHog 可以通过多种方式实现,因此要检查脚本、网络请求和 window 对象。
- 清晰报告发现。 以结构化格式总结检查结果。
- 绝不修改任何内容。 仅进行只读检查。
初始流程
用户请求检查 PostHog 实现时:
- 获取网址(如果用户尚未提供)
- 导航到网址,并在末尾附加
?__posthog_debug=true - 通过截取快照并查找登录提示,检查是否需要登录
- 如果需要登录,请用户在浏览器中进行身份验证
- 完成身份验证后,继续检查
检测登录页面
导航后,截取快照并查找登录提示:
- 页面标题包含“login”“sign in”或“authenticate”
- 网址包含“login”“signin”“auth”或“sso”
- 页面上有用户名/密码字段
- 页面显示“使用 Google/GitHub 等登录”按钮
已验证身份的页面工作流
如果检测到登录页面,或用户提到页面需要身份验证:
-
保持浏览器打开——你已经导航到该页面
-
请用户登录:
"This page requires authentication. Please log in using the Chrome browser I just opened. Let me know when you're logged in and on the page you want to inspect." -
用户确认后,截取新快照,验证其是否已完成身份验证
-
如果网址中尚未包含调试参数,则添加该参数;必要时重新加载页面
-
继续检查
可用的浏览器工具
Chrome DevTools MCP
mcp__chrome-devtools__navigate_page- 导航到网址mcp__chrome-devtools__take_snapshot- 获取页面无障碍树mcp__chrome-devtools__evaluate_script- 运行 JavaScript 检查 PostHogmcp__chrome-devtools__list_network_requests- 查看网络流量mcp__chrome-devtools__get_network_request- 获取请求详情mcp__chrome-devtools__list_console_messages- 检查错误
Playwright MCP
mcp__playwright__browser_navigate- 导航到网址mcp__playwright__browser_snapshot- 获取页面快照mcp__playwright__browser_evaluate- 运行 JavaScriptmcp__playwright__browser_network_requests- 查看网络流量mcp__playwright__browser_console_messages- 检查控制台
检查工作流
步骤 1:以调试模式导航到页面
始终在网址中添加 ?__posthog_debug=true,以启用 PostHog 调试模式。这样会在控制台输出详细日志。
- 如果网址没有查询字符串:
https://example.com?__posthog_debug=true - 如果网址已有查询字符串:
https://example.com?foo=bar&__posthog_debug=true
工作流:
- 使用调试参数导航到网址
- 截取快照,查看加载的内容
- 检查是否有登录页面提示:
- 网址被重定向到
/login、/signin、/auth或/sso - 页面标题包含“log in”或“sign in”
- 页面上有登录表单字段
- 网址被重定向到
- 如果检测到登录页面:
- 告知用户:“我已打开页面,但该页面需要登录。请使用 Chrome 登录,然后告知我何时可以继续。”
- 等待用户确认
- 截取新快照,验证身份验证状态
- 如有需要,在新网址中添加调试参数
- **如果不需要登录:**继续检查
步骤 2:检查 PostHog 全局对象
运行 JavaScript,检查 window 上的 posthog 对象:
(() => {
if (typeof posthog === 'undefined') {
return { installed: false };
}
const ph = posthog;
return {
installed: true,
version: ph.version || ph.LIB_VERSION || 'unknown',
config: {
token: ph.config?.token || ph.get_config?.('token') || 'not accessible',
apiHost: ph.config?.api_host || ph.get_config?.('api_host') || 'not accessible',
autocapture: ph.config?.autocapture ?? ph.get_config?.('autocapture') ?? 'not accessible',
capturePageview: ph.config?.capture_pageview ?? ph.get_config?.('capture_pageview') ?? 'not accessible',
capturePageleave: ph.config?.capture_pageleave ?? ph.get_config?.('capture_pageleave') ?? 'not accessible',
sessionRecording: ph.config?.enable_recording_console_log !== undefined ||
ph.sessionRecording?.started ||
'check network',
persistence: ph.config?.persistence || ph.get_config?.('persistence') || 'not accessible',
debug: ph.config?.debug ?? ph.get_config?.('debug') ?? false
},
distinctId: ph.get_distinct_id?.() || 'not accessible',
sessionId: ph.get_session_id?.() || 'not accessible',
featureFlags: ph.getFeatureFlag ? Object.keys(ph.featureFlags?.flags || {}) : [],
activeFeatureFlags: ph.getFeatureFlag ?
Object.entries(ph.featureFlags?.flags || {})
.filter(([_, v]) => v)
.map(([k]) => k) : []
};
})()
步骤 2b:检查捆绑的 PostHog(远程配置)
如果 posthog 不在 window 上,请检查使用 _POSTHOG_REMOTE_CONFIG 的捆绑实现:
(() => {
const remoteConfig = window._POSTHOG_REMOTE_CONFIG;
if (!remoteConfig) {
return { found: false };
}
const tokens = Object.keys(remoteConfig);
const configs = tokens.map(token => {
const cfg = remoteConfig[token]?.config || {};
return {
token,
hasFeatureFlags: cfg.hasFeatureFlags || false,
autocapture: !cfg.autocapture_opt_out,
sessionRecording: cfg.sessionRecording || false,
heatmaps: cfg.heatmaps || false,
surveys: cfg.surveys || false,
capturePerformance: cfg.capturePerformance || {},
defaultIdentifiedOnly: cfg.defaultIdentifiedOnly || false
};
});
return {
found: true,
bundled: true,
configs
};
})()
第 2c 步:检查控制台中的 PostHog 调试消息
使用 ?__posthog_debug=true 时,PostHog 会输出详细日志。使用 list_console_messages 并查找 [PostHog.js] 条目:
需要查找的关键消息:
[PostHog.js] Persistence loaded- 显示持久化类型(localStorage、sessionStorage、cookie)[PostHog.js] [Surveys] Surveys loaded successfully- Surveys 模块已加载[PostHog.js] [Surveys] flags response received, isSurveysEnabled: X- Surveys 是否已启用[PostHog.js] [SessionRecording]- 会话录制状态[PostHog.js] [WebExperiments]- Web 实验/功能标记[PostHog.js] set_config- 配置变更
重要区别:
- 模块已加载 = JavaScript 文件已成功加载
- 功能已启用 = PostHog 设置中已开启该功能
模块可以已加载,但仍处于禁用状态。例如:
[PostHog.js] [Surveys] Surveys loaded successfully <- Module loaded
[PostHog.js] [Surveys] flags response received, isSurveysEnabled: false <- Feature disabled
第 3 步:检查 PostHog 脚本
查找页面中的 PostHog 脚本:
(() => {
const scripts = Array.from(document.querySelectorAll('script'));
const posthogScripts = scripts.filter(s =>
(s.src && (s.src.includes('posthog') || s.src.includes('ph.js'))) ||
(s.textContent && (s.textContent.includes('posthog.init') || s.textContent.includes('!function(t,e)')))
);
return {
found: posthogScripts.length > 0,
scripts: posthogScripts.map(s => ({
src: s.src || 'inline',
async: s.async,
defer: s.defer,
type: s.type || 'text/javascript'
}))
};
})()
第 4 步:检查网络请求
筛选网络请求以查找 PostHog 流量。PostHog 可能使用:
标准域名:
*.posthog.comus.i.posthog.com/eu.i.posthog.comus-assets.i.posthog.com/eu-assets.i.posthog.com
自定义代理域名(常见模式):
ph.yourcompany.comanalytics.yourcompany.comt.yourcompany.com- 路径中包含
/array/phc_的任意域名(PostHog 配置)
需要查找的端点:
/e/或/capture/- 事件/s/- 会话录制/decide/或/flags/- 功能标记/batch/- 批量事件/array/phc_*/config.js- 远程配置(捆绑式实现)/static/surveys.js- Surveys 模块/static/recorder.js- 会话录制模块
如何识别自定义代理:
- 查找包含 PostHog 特定路径(
/flags/、/array/phc_)的请求 - 检查网络请求详情中的 PostHog 标头
- 查找请求 URL 或请求正文中的
phc_令牌
第 5 步:检查常见问题
运行诊断:
(() => {
const issues = [];
// Check if posthog exists
if (typeof posthog === 'undefined') {
issues.push('PostHog not found on window object');
return { issues };
}
// Check for multiple instances
if (window.__POSTHOG_INSTANCES__ && window.__POSTHOG_INSTANCES__.length > 1) {
issues.push('Multiple PostHog instances detected - may cause duplicate events');
}
// Check if initialized
if (!posthog.get_distinct_id || !posthog.get_distinct_id()) {
issues.push('PostHog may not be fully initialized');
}
// Check consent mode
if (posthog.has_opted_out_capturing && posthog.has_opted_out_capturing()) {
issues.push('User has opted out of tracking');
}
// Check for debug mode in production
const isDebug = posthog.config?.debug || posthog.get_config?.('debug');
const hostname = window.location.hostname;
if (isDebug && !hostname.includes('localhost') && !hostname.includes('127.0.0.1')) {
issues.push('Debug mode is enabled in production');
}
// Check autocapture
const autocapture = posthog.config?.autocapture ?? posthog.get_config?.('autocapture');
if (autocapture === false) {
issues.push('Autocapture is disabled - only manual events will be tracked');
}
return {
issues: issues.length > 0 ? issues : ['No issues detected'],
checksRun: true
};
})()
第 6 步:捕获最近的事件(如果可用调试信息)
如果调试模式已开启,或我们可以访问队列:
(() => {
if (typeof posthog === 'undefined') return { events: [] };
// Try to get queued events
const queue = posthog._requestQueue?.queue ||
posthog.requestQueue?.queue ||
[];
// Get recent events from persistence if available
const stored = posthog.persistence?.props?.$stored_events || [];
return {
queuedEvents: queue.length,
recentEventTypes: [...new Set([...queue, ...stored].map(e => e?.event || 'unknown').slice(0, 20))]
};
})()
第 7 步:检测其他分析工具
扫描网络请求和脚本,以识别页面上的所有分析/跟踪工具。使用已知模式识别具名工具,并在无法识别时检测未知跟踪脚本作为后备。
(() => {
const scripts = Array.from(document.querySelectorAll('script[src]')).map(s => s.src);
const hostname = window.location.hostname.replace('www.', '');
const knownTools = [];
const matchedScripts = new Set();
const patterns = {
'Google Analytics': /google-analytics\.com|gtag\/js/i,
'Google Tag Manager': /googletagmanager\.com\/gtm/i,
'Facebook Pixel': /connect\.facebook\.net.*fbevents/i,
'LinkedIn Insight': /snap\.licdn\.com/i,
'HubSpot': /js\.hs-scripts\.com|js\.hsforms\.com/i,
'Hotjar': /static\.hotjar\.com/i,
'Segment': /cdn\.segment\.com/i,
'Mixpanel': /cdn\.mxpnl\.com|mixpanel\.com/i,
'Amplitude': /cdn\.amplitude\.com/i,
'Heap': /heap-analytics\.com|heapanalytics\.com/i,
'Intercom': /widget\.intercom\.io|intercomcdn\.com/i,
'Drift': /js\.driftt\.com/i,
'Zendesk': /static\.zdassets\.com/i,
'Crisp': /client\.crisp\.chat/i,
'FullStory': /fullstory\.com\/s\/fs\.js/i,
'LogRocket': /cdn\.logrocket\.com/i,
'Sentry': /browser\.sentry-cdn\.com/i,
'Datadog': /datadoghq\.com/i,
'Snowplow': /cdn\.snowplow/i,
'Rudderstack': /cdn\.rudderlabs\.com/i,
'Clearbit': /tag\.clearbitscripts\.com/i,
'Dreamdata': /cdn\.dreamdata\.cloud/i,
'GrowthBook': /cdn\.growthbook\.io/i,
'LaunchDarkly': /sdk\.launchdarkly\.com/i,
'Optimizely': /cdn\.optimizely\.com/i,
'VWO': /dev\.visualwebsiteoptimizer\.com/i,
'Ahrefs': /analytics\.ahrefs\.com/i,
'AdRoll': /s\.adroll\.com/i,
'Factors.ai': /app\.factors\.ai/i,
'Vector': /cdn\.vector\.co/i,
'Leadfeeder': /sc\.lfeeder\.com/i,
'Pendo': /cdn\.pendo\.io/i,
'Chameleon': /fast\.chameleon\.io/i,
'Appcues': /fast\.appcues\.com/i,
'UserPilot': /js\.userpilot\.io/i,
'Mouseflow': /cdn\.mouseflow\.com/i,
'Lucky Orange': /tools\.luckyorange\.com/i,
'Crazy Egg': /script\.crazyegg\.com/i,
'Plausible': /plausible\.io\/js/i,
'Fathom': /cdn\.usefathom\.com/i,
'Simple Analytics': /scripts\.simpleanalyticscdn\.com/i,
'Matomo': /matomo\.js|piwik\.js/i,
'Klaviyo': /static\.klaviyo\.com/i,
'Customer.io': /track\.customer\.io/i,
'Braze': /sdk\.iad-\d+\.braze\.com/i,
'OneSignal': /cdn\.onesignal\.com/i,
'Insider': /insr\.io/i,
'Mutiny': /cdn\.mutinycdn\.com/i,
'Qualified': /js\.qualified\.com/i,
'Chilipiper': /js\.chilipiper\.com/i,
'Typekit': /use\.typekit\.net/i,
'Google Fonts': /fonts\.googleapis\.com/i,
'Cookiebot': /consent\.cookiebot\.com/i,
'OneTrust': /cdn\.cookielaw\.org/i,
'TrustArc': /consent\.trustarc\.com/i,
'Osano': /cmp\.osano\.com/i,
'Usercentrics': /app\.usercentrics\.eu/i,
'OpenLI/Legal Monster': /widgets\.legalmonster\.com|openli\.com/i,
'Nelio A/B Testing': /nelio-ab-testing/i,
'Mesh': /mesh-interactive|withmesh\.com/i,
'Reddit Pixel': /redditstatic\.com|rdt\.li/i,
'Webflow': /wdfl\.co|webflow\.com\/js/i,
'Dub.co': /dubcdn\.com|dub\.co/i
};
// Match known tools
for (const [name, pattern] of Object.entries(patterns)) {
for (const src of scripts) {
if (pattern.test(src)) {
knownTools.push(name);
matchedScripts.add(src);
break;
}
}
}
// Find unknown tracking scripts
const trackingKeywords = /track|analytics|pixel|tag|beacon|collect|measure|metric|event|telemetry|monitor/i;
const unknownScripts = scripts.filter(src => {
if (matchedScripts.has(src)) return false;
try {
const url = new URL(src);
const scriptHost = url.hostname.replace('www.', '');
// Skip same-domain scripts
if (scriptHost === hostname || scriptHost.endsWith('.' + hostname)) return false;
// Skip common CDNs that host non-tracking code
if (/unpkg\.com|jsdelivr\.net|cdnjs\.cloudflare\.com|ajax\.googleapis\.com/i.test(scriptHost)) return false;
// Include if it has tracking-like keywords or is from a third-party
return trackingKeywords.test(src) || true;
} catch {
return false;
}
});
// Extract just the domain from unknown scripts for cleaner output
const unknownDomains = [...new Set(unknownScripts.map(src => {
try {
return new URL(src).hostname;
} catch {
return src;
}
}))].sort();
return {
knownTools: [...new Set(knownTools)].sort(),
unknownScripts: unknownDomains
};
})()
响应格式
检查完成后,提供结构化摘要。陈述事实并保持简洁——除非对方提出要求,否则不要添加评论或建议。使用表情符号一目了然地标示状态。
状态表情符号:
- ✅ = 是 / 已启用 / 活跃 / 已安装
- ❌ = 否 / 已禁用 / 未找到
- ⚠️ = 警告 / 检测到问题
## PostHog Implementation Summary
### Status
✅ Installed / ✅ Installed (bundled) / ❌ Not Found
### Implementation Type
[Global window.posthog / Bundled (not exposed globally) / Custom proxy]
### Configuration
- **Version:** [version]
- **API Host:** [host] ([US/EU Cloud] / [Custom proxy] / [Self-hosted])
- **Project Token:** [full token]
- **Persistence:** [localStorage/sessionStorage/cookie/memory]
### Features (Module Loaded → Feature Enabled)
| Feature | Module Loaded | Enabled |
|---------|---------------|---------|
| Autocapture | ✅ / ❌ | ✅ / ❌ |
| Session Recording | ✅ / ❌ | ✅ / ❌ |
| Surveys | ✅ / ❌ | ✅ / ❌ |
| Heatmaps | ✅ / ❌ | ✅ / ❌ |
| Feature Flags | ✅ / ❌ | ✅ / ❌ |
| Web Vitals | ✅ / ❌ | ✅ / ❌ |
### Identifiers
- **Distinct ID:** [id]
- **Session ID:** [id]
### Feature Flags
[List of active flags or "None loaded"]
### Network Activity
- Events endpoint: ✅ / ❌
- Session recording: ✅ / ❌
- Decide/flags endpoint: ✅ / ❌
- Surveys endpoint: ✅ / ❌
### Issues Found
✅ None detected
— or —
⚠️ [Issue description]
### Script Loading
- **Source:** [CDN/Self-hosted/NPM bundle/Custom proxy]
- **Loading:** [Async/Sync/Defer]
### Other Analytics Tools Detected
[List of recognized analytics, tracking, and marketing tools]
### Other External Scripts
[Third-party script domains not matched to known tools]
常见问题及回答方式
“此页面如何实现 PostHog?”
运行完整检查流程并提供完整摘要。
“PostHog 跟踪是否正常工作?”
- 检查 posthog 对象是否存在
- 验证是否正在发送网络请求
- 检查控制台中是否有错误
- 查找已选择退出的状态
“正在跟踪哪些事件?”
- 检查 autocapture 状态
- 查看发送到
/e/或/capture/的网络请求 - 尝试访问事件队列
- 注明是否启用了 $pageview、$pageleave 等事件
“会话录制是否已启用?”
- 检查配置中的录制设置
- 查找
/s/网络请求 - 检查 sessionRecording 对象状态
“哪些功能标记处于活跃状态?”
- 检查 posthog 上的 featureFlags 对象
- 查找
/decide/网络请求 - 列出所有标记及其值
“此实现是否存在问题?”
运行诊断检查并报告结果。
“使用的是 EU 云还是 US 云?”
检查 api_host 配置:
us.i.posthog.com= US 云eu.i.posthog.com= EU 云app.posthog.com= 旧版(默认为 US)- 自定义域名 = 自托管或代理
示例对话
用户:“PostHog 在 https://example.com 上是如何实现的?”
Claude:“我将启用调试模式并访问 example.com,检查 PostHog 的实现。”
[访问 https://example.com?__posthog_debug=true] [运行 JavaScript 检查] [检查控制台中的 PostHog 调试消息] [分析网络请求]
Claude:
## PostHog Implementation Summary
### Status
✅ Installed
### Implementation Type
Global window.posthog
### Configuration
- **Version:** 1.96.1
- **API Host:** https://us.i.posthog.com (US Cloud)
- **Project Token:** phc_abc123def456ghi789jkl012mno345
- **Persistence:** localStorage+cookie
### Features (Module Loaded → Feature Enabled)
| Feature | Module Loaded | Enabled |
|---------|---------------|---------|
| Autocapture | ✅ | ✅ |
| Session Recording | ✅ | ✅ |
| Surveys | ✅ | ❌ |
| Heatmaps | ❌ | ❌ |
| Feature Flags | ✅ | ✅ |
| Web Vitals | ✅ | ✅ |
### Identifiers
- **Distinct ID:** 018d4f2a-1234-7abc-def0-123456789abc
- **Session ID:** 018d4f2a-5678-7xyz-abc0-987654321xyz
### Feature Flags
- `new-checkout-flow` ✅
- `beta-features` ❌
### Network Activity
- Events endpoint: ✅
- Session recording: ✅
- Decide/flags endpoint: ✅
- Surveys endpoint: ✅
### Issues Found
✅ None detected
### Script Loading
- **Source:** CDN (us-assets.i.posthog.com)
- **Loading:** Async
### Other Analytics Tools Detected
- Google Tag Manager
- Google Analytics
- HubSpot
### Other External Scripts
- cdn.example-vendor.com
示例 2:使用自定义代理的身份验证页面
用户:“检查 https://app.example.com/dashboard 上的 PostHog”
Claude:“我将启用调试模式并访问该页面。”
[访问 https://app.example.com/dashboard?__posthog_debug=true] [获取页面快照,发现登录页面]
Claude:“我已打开页面,但需要登录。请使用我刚打开的 Chrome 浏览器登录。到达仪表板后请告诉我。”
用户:“我已登录”
Claude:[获取新的页面快照,确认已通过身份验证,然后运行检查]
## PostHog Implementation Summary
### Status
✅ Installed (bundled)
### Implementation Type
Bundled (not exposed globally) via custom proxy
### Configuration
- **Version:** 1.257.2
- **API Host:** ph.example.com (Custom proxy)
- **Project Token:** phc_abc123def456ghi789jkl012mno345
- **Persistence:** sessionStorage
### Features (Module Loaded → Feature Enabled)
| Feature | Module Loaded | Enabled |
|---------|---------------|---------|
| Autocapture | ✅ | ❌ |
| Session Recording | ❌ | ❌ |
| Surveys | ✅ | ❌ |
| Heatmaps | ❌ | ❌ |
| Feature Flags | ✅ | ✅ |
| Web Vitals | ✅ | ❌ |
### Identifiers
- **Distinct ID:** (not accessible - bundled)
- **Session ID:** (not accessible - bundled)
### Network Activity
- Events endpoint: ✅
- Session recording: ❌
- Decide/flags endpoint: ✅
- Surveys endpoint: ✅ (module loaded, feature disabled)
### Issues Found
✅ None detected
### Script Loading
- **Source:** Custom proxy (ph.example.com)
- **Loading:** Bundled in app