mcpField
P
posthog-debugger

posthog-debugger

github.com/posthog测试与质量76267 次安装今天更新
代码仓库

关于 posthog-debugger

用于检查网站 PostHog 实现的只读调试技能,面向开发者和产品团队。它结合页面脚本、浏览器对象、网络请求和控制台信息,整理配置与数据采集情况。

主要功能

  1. 01通过浏览器检查网站中的 PostHog
  2. 02检查脚本、全局对象和远程配置
  3. 03分析网络请求与调试控制台信息
  4. 04诊断事件、录制和功能标记状态
  5. 05只读检查并结构化汇总结果

适用场景

  1. 01核实网站是否安装并运行 PostHog
  2. 02排查事件请求未发送或控制台错误
  3. 03检查会话录制、调查和功能标记状态
  4. 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 的配置方式以及正在采集的数据。

关键规则

  1. 如果未提供网址,始终先询问网址。
  2. 始终询问页面是否需要登录。 如果需要,请引导用户先通过 Chrome 登录。
  3. 使用浏览器工具导航和检查。 优先使用 Chrome DevTools MCP(mcp__chrome-devtools__*)或 Playwright MCP(mcp__playwright__*)工具。
  4. 检查多个信号。 PostHog 可以通过多种方式实现,因此要检查脚本、网络请求和 window 对象。
  5. 清晰报告发现。 以结构化格式总结检查结果。
  6. 绝不修改任何内容。 仅进行只读检查。

初始流程

用户请求检查 PostHog 实现时:

  1. 获取网址(如果用户尚未提供)
  2. 导航到网址,并在末尾附加 ?__posthog_debug=true
  3. 通过截取快照并查找登录提示,检查是否需要登录
  4. 如果需要登录,请用户在浏览器中进行身份验证
  5. 完成身份验证后,继续检查

检测登录页面

导航后,截取快照并查找登录提示:

  • 页面标题包含“login”“sign in”或“authenticate”
  • 网址包含“login”“signin”“auth”或“sso”
  • 页面上有用户名/密码字段
  • 页面显示“使用 Google/GitHub 等登录”按钮

已验证身份的页面工作流

如果检测到登录页面,或用户提到页面需要身份验证:

  1. 保持浏览器打开——你已经导航到该页面

  2. 请用户登录:

    "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."
    
  3. 用户确认后,截取新快照,验证其是否已完成身份验证

  4. 如果网址中尚未包含调试参数,则添加该参数;必要时重新加载页面

  5. 继续检查

可用的浏览器工具

Chrome DevTools MCP
  • mcp__chrome-devtools__navigate_page - 导航到网址
  • mcp__chrome-devtools__take_snapshot - 获取页面无障碍树
  • mcp__chrome-devtools__evaluate_script - 运行 JavaScript 检查 PostHog
  • mcp__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 - 运行 JavaScript
  • mcp__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

工作流:

  1. 使用调试参数导航到网址
  2. 截取快照,查看加载的内容
  3. 检查是否有登录页面提示:
    • 网址被重定向到 /login、/signin、/auth 或 /sso
    • 页面标题包含“log in”或“sign in”
    • 页面上有登录表单字段
  4. 如果检测到登录页面:
    • 告知用户:“我已打开页面,但该页面需要登录。请使用 Chrome 登录,然后告知我何时可以继续。”
    • 等待用户确认
    • 截取新快照,验证身份验证状态
    • 如有需要,在新网址中添加调试参数
  5. **如果不需要登录:**继续检查
步骤 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.com
  • us.i.posthog.com / eu.i.posthog.com
  • us-assets.i.posthog.com / eu-assets.i.posthog.com

自定义代理域名(常见模式):

  • ph.yourcompany.com
  • analytics.yourcompany.com
  • t.yourcompany.com
  • 路径中包含 /array/phc_ 的任意域名(PostHog 配置)

需要查找的端点:

  • /e/ 或 /capture/ - 事件
  • /s/ - 会话录制
  • /decide/ 或 /flags/ - 功能标记
  • /batch/ - 批量事件
  • /array/phc_*/config.js - 远程配置(捆绑式实现)
  • /static/surveys.js - Surveys 模块
  • /static/recorder.js - 会话录制模块

如何识别自定义代理:

  1. 查找包含 PostHog 特定路径(/flags/、/array/phc_)的请求
  2. 检查网络请求详情中的 PostHog 标头
  3. 查找请求 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 跟踪是否正常工作?”
  1. 检查 posthog 对象是否存在
  2. 验证是否正在发送网络请求
  3. 检查控制台中是否有错误
  4. 查找已选择退出的状态
“正在跟踪哪些事件?”
  1. 检查 autocapture 状态
  2. 查看发送到 /e/ 或 /capture/ 的网络请求
  3. 尝试访问事件队列
  4. 注明是否启用了 $pageview、$pageleave 等事件
“会话录制是否已启用?”
  1. 检查配置中的录制设置
  2. 查找 /s/ 网络请求
  3. 检查 sessionRecording 对象状态
“哪些功能标记处于活跃状态?”
  1. 检查 posthog 上的 featureFlags 对象
  2. 查找 /decide/ 网络请求
  3. 列出所有标记及其值
“此实现是否存在问题?”

运行诊断检查并报告结果。

“使用的是 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

评论

支持 Markdown