PostHog Desktop 本地开发环境接入指南:OAuth 配置、区域机制与调试技巧
【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog
本篇指南讲解如何把 PostHog 仓库中的 Desktop(桌面端)应用连接到本地后端(http://localhost:8010)或共享 Dev Cloud(app.dev.posthog.dev),覆盖 OAuth 应用注册、RSA 密钥配置、区域(region)机制、Custom 自托管实例接入、本地 feature flag 调试与常见故障排查。读完后你可以独立搭建 Desktop 的完整开发环境,理解桌面端 OAuth 授权链路(client ID、scope ceiling、回调端口)的源码实现,并掌握 devtools 控制台调试命令。
开发连接方式总览
Desktop 的开发构建(development build)支持两种数据后端选择,而生产构建只显示 US Cloud 和 EU Cloud——两个开发选项仅出现在开发构建中:
| 选项 | PostHog 主机 | 适用场景 |
|---|---|---|
| Local development | http://localhost:8010 | 本地后端改动与本地测试数据 |
| Dev Cloud | https://app.dev.posthog.dev | 已部署到共享开发环境的代码 |
一个容易混淆的点:VITE_POSTHOG_API_HOST不用于选择数据后端。它只控制独立的 analytics / feature flag 客户端(即 posthog-js 的指向),数据 API 走的是你在登录时选择的区域。这一职责划分在后文"本地开发中的 Feature Flags"一节会详细展开。
前提条件
- Local development:一个运行在
http://localhost:8010的 PostHog 实例(即本 monorepo 用 docker compose 拉起的本地栈); - Dev Cloud:能访问
https://app.dev.posthog.dev; - Node.js 22+;
- pnpm 10+。
如果你在 posthog/posthog monorepo 中开发 Desktop 应用(代码位于products/desktop),注意 Desktop 需要 Node 22(见products/desktop目录下的.node-version),而不是 monorepo flox 环境提供的 Node 版本——先用自己的版本管理器切换再执行安装。
在 PostHog 侧注册 OAuth 应用
Desktop 通过 OAuth 向 PostHog 认证,因此目标实例上必须存在一个与桌面端硬编码 client ID 匹配的 OAuth 应用。有两种注册方式:
方式 A:生成演示数据(推荐)
PostHog 的 demo data 生成器会创建一个带正确 client ID 的预配置 OAuth 应用:
# 在你的 PostHog 仓库(本 monorepo 根目录) python manage.py generate_demo_data生成的 OAuth 应用属性为:
- Client ID:
DC5uRLVbGI02YQ82grxgnK6Qn12SXWpCqdPb60oZ - Redirect URIs:包含
http://localhost:8237/callback和http://localhost:8239/callback
方式 B:通过 Django admin 手动创建
- 访问
http://localhost:8010/admin/posthog/oauthapplication/; - 点击Add OAuth Application;
- 按如下字段填写:
- Name:
PostHog Desktop(任意名称均可); - Client ID:
DC5uRLVbGI02YQ82grxgnK6Qn12SXWpCqdPb60oZ。必须与应用源码中的POSTHOG_DEV_CLIENT_ID一致; - Client type:
Public(桌面端是 Electron 应用,无 client secret,走 PKCE); - Authorization grant type:
Authorization code; - Redirect URIs:
http://localhost:8237/callback http://localhost:8239/callback; - Algorithm:
RS256;
- Name:
- 保存。
重要:client ID 必须严格等于
DC5uRLVbGI02YQ82grxgnK6Qn12SXWpCqdPb60oZ。这个值定义在 oauth.ts 中。
源码印证:client ID 与授权 URL 的构造
在 oauth.ts 中,四个区域各自对应一个硬编码 client ID:
export const POSTHOG_US_CLIENT_ID = "HCWoE0aRFMYxIxFNTTwkOORn5LBjOt2GVDzwSw5W"; export const POSTHOG_EU_CLIENT_ID = "AIvijgMS0dxKEmr5z6odvRd8Pkh5vts3nPTzgzU9"; export const POSTHOG_DEV_CLIENT_ID = "DC5uRLVbGI02YQ82grxgnK6Qn12SXWpCqdPb60oZ"; export const POSTHOG_DEV_CLOUD_CLIENT_ID = "7D6O76iHBMAioX5bLy4smEJ7qehtanmBRYOAQoEw";getOauthClientIdFromRegion()按区域做映射:dev返回POSTHOG_DEV_CLIENT_ID,dev-cloud返回POSTHOG_DEV_CLOUD_CLIENT_ID,custom则读取用户输入的 client ID。这就是"Local development 必须用DC5uRL…这个 client ID"的根源——它不是可配置的,而是编译进应用里的。
同文件中还定义了开发构建的回调端口常量:
export const DEV_CALLBACK_PORT = 8237; export const DEV_REDIRECT_URI = `http://localhost:${DEV_CALLBACK_PORT}/callback`;在 core 包的 OAuth 服务 中,getRedirectUri()的逻辑是:开发构建(host.isDev)使用DEV_REDIRECT_URI(即http://localhost:8237/callback),生产构建使用 deep-link 协议(posthog-code://callback)。startFlow()会生成 PKCE code verifier 并构造 authorize URL,因此 OAuth 应用的 client type 必须设为Public。应用启动开发模式时会在 8237 端口拉起一个回调 HTTP 服务器(源码中日志为 "Dev OAuth callback server listening on port 8237")。文档同时要求注册8239端口的回调 URI,是为了覆盖其他构建形态下回调端口的取值;harness 侧的 OAuth provider 同样以 8237 为默认回调端口(见 harness/oauth.ts)。
在 PostHog 侧配置 RSA 密钥
OAuth 令牌签名需要 RSA 私钥。在 PostHog 仓库中:
# 把 .env.example 中的 RSA 密钥拷贝到 .env grep OIDC_RSA_PRIVATE_KEY .env.example >> .env或者自行生成一个新的:
openssl genrsa 2048 | openssl pkcs8 -topk8 -nocrypt -outform PEM | \ awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}' # 结果以单行 JSON 字符串形式加入 PostHog 的 .env: # OIDC_RSA_PRIVATE_KEY="<generated_key>"若这一步缺失,OAuth 授权页会直接加载失败(见文末排障)。
运行应用
在 monorepo 中开发:
cd products/desktop pnpm install cp .env.example .env pnpm dev全新克隆(独立的 PostHog/code 仓库已归档、不再接收改动):
git clone https://github.com/PostHog/posthog.git cd posthog/products/desktop pnpm install cp .env.example .env pnpm dev连接步骤
- 在登录界面选择区域:Local development(指向
localhost:8010)或Dev Cloud(指向app.dev.posthog.dev); - Desktop 会打开所选 PostHog 主机上的 OAuth 授权页;
- 授权应用并选择 project / organization 访问级别;
- PostHog 重定向回 Desktop 监听的 localhost 回调端口,完成登录。
区域机制源码解析
开发构建内部维护两个相互独立的 region 值,定义在 regions.ts:
export const CLOUD_REGIONS = ["us", "eu", "dev", "dev-cloud", "custom"] as const;区域展示元数据(标签与提示)如下:
| region | 标签 | 提示(hint) |
|---|---|---|
us | US Cloud | us.posthog.com |
eu | EU Cloud | eu.posthog.com |
dev | Local development | localhost:8010 |
dev-cloud | Dev Cloud | app.dev.posthog.dev |
custom | Custom | 用户实例的 host |
dev保持指向http://localhost:8010,使用它自己的 OAuth client ID(即POSTHOG_DEV_CLIENT_ID);dev-cloud连接https://app.dev.posthog.dev,使用专用的 client ID(POSTHOG_DEV_CLOUD_CLIENT_ID);- Dev Cloud 的 agent 请求走
https://gateway.dev.posthog.dev网关。
保留dev与dev-cloud两个独立值,是为了保住已保存的 Local development 会话——若复用同一个 region 值,切换到 Dev Cloud 会覆盖本地开发会话。
Custom:连接任意自托管实例
Custom区域指向任意 PostHog 实例(例如自托管部署)。选择 Custom 后会出现若干输入字段,每个字段旁都有信息图标。Custom 作为最后一项出现在开发构建的区域列表中,也出现在Desktop Build Testworkflow 产出的测试构建中(PR 上打desktop-build-installerlabel 触发);release 构建不显示它,且 release 构建会忽略已保存的 Custom 目标。打包的测试构建使用独立的用户数据目录(posthog-code-test),其会话与设置与同机器的 release 构建隔离。
接入自托管实例的完整流程:
在实例上创建 OAuth 应用。以 staff 用户打开
https://<your-instance>/admin/posthog/oauthapplication/,点击Add OAuth application,设置:- Name:任意,如
PostHog Desktop; - Client type:
Public。应用使用 PKCE,没有 client secret; - Authorization grant type:
Authorization code(表单固定该值,算法RS256); - Redirect URIs:打包构建用
posthog-code://callback;本地开发构建追加http://localhost:8237/callback;打包开发构建用posthog-code-dev://callback;Desktop Build Test workflow 的测试构建用posthog-code-test://callback; - 实例侧令牌签名需要
OIDC_RSA_PRIVATE_KEY,正规部署通常已具备。
- Name:任意,如
拷贝列表页上的 client ID,并在实例上播种 scope ceiling:
python manage.py seed_oauth_app_scopes --client-id <id> --scopes @default,llm_gateway:read空的 ceiling 会解析为无权限 scope 集,其中不包含
llm_gateway:read。LLM 网关会拒绝不带该 scope 的令牌,导致 agent 运行失败。在登录界面选择Custom(区域列表最后一项,位于 Local development 之后)。
输入实例 URL 与 OAuth 应用的 client ID。URL 必须是
httpsorigin(如https://posthog.example.com),不带 path、query 或 fragment。只有 loopback host 才接受纯http——因为 OAuth 令牌会跨越该 origin。登录。应用会保存这些值,并一致地应用于登录、API 请求与 agent 运行。
Custom 实例的 LLM 网关与 MCP 要求
Agent 运行需要一个能读懂你实例令牌的 LLM 网关,因此在LLM gateway URL字段填入一个读取你实例数据库的网关地址(参见 services/llm-gateway 目录下的实现)。PostHog Cloud 网关无法服务自定义实例:它把令牌对 Cloud 数据库做 introspection,且其posthog_code产品拒绝个人 API key。字段留空时应用会从 host 推导网关,未知 host 会落到 US 网关并返回 403。
PostHog 官方 MCP 服务器对自定义实例不可用——mcp.posthog.com同样读不懂你实例的令牌,需通过POSTHOG_MCP_URL指定可用的 MCP 服务器。
us、eu、dev、dev-cloud区域从不读取这些 Custom 值,实例 URL 字段也会拒绝输入这些内置 host。
headless harness 运行:独立无头运行时通过环境变量指定目标——POSTHOG_CUSTOM_CLOUD_URL、POSTHOG_CUSTOM_CLOUD_OAUTH_CLIENT_ID、POSTHOG_CUSTOM_CLOUD_GATEWAY_URL三者承载目标配置,POSTHOG_REGION=custom选择该区域。URL 与 client ID 均为必填:缺POSTHOG_REGION时 harness 停留在 US;有 region 但目标不完整时会失败,错误信息会点名缺失的变量。
同时测试本地代码与 Skills 改动
Desktop 的 agent skills 有两种来源,开发时按需切换:
hogli start(Desktop intent)使用本地 checkout 的 skills,并在你编辑时自动重建。intent 只需通过hogli dev:setup选择一次;hogli desktop:dev(或在products/desktop下执行pnpm dev)默认使用production skills。
切换来源(在仓库根目录执行):
POSTHOG_DESKTOP_SKILLS=production hogli start POSTHOG_DESKTOP_SKILLS=local hogli desktop:dev本地 skills 需要执行uv sync,且要求本地后端至少有一个 project。skills 重建后要开新的 agent 会话才生效。
本地 cloud tasks 在SANDBOX_PROVIDER=docker时使用栈的配置;production保持镜像内置 skills。每个新 sandbox 拥有自己的 skill 副本;skill 编辑不影响正在运行的任务;构建失败会阻止新任务启动。
Dev 控制台调试命令
在 dev 构建中打开 devtools,可执行以下命令(源码位置见原文档标注的apps/code/src/renderer/features/inbox/devtools/inboxDemoConsole.ts):
__codeInboxDemo()— 显示帮助;__codeInboxDemo('seed')— 用假数据填充 inbox;__codeInboxDemo('seed', 'artefacts-unavailable')— 假数据,artefacts 不可用模式;__codeInboxDemo('seed', 'empty')— 假数据,空状态;__codeInboxDemo('clear')— 清除假数据,回到真实 API。
本地开发中的 Feature Flags
Feature flags 通过 posthog-js 读取,由.env中的VITE_POSTHOG_*变量配置。默认指向 PostHog 内部 analytics 实例,所以你在本地创建的 flag 在 dev 构建中永远不会解析。
要让 flag/analytics 客户端指向你的本地 PostHog,使本地同步的 flag 生效:
# 在你的 PostHog 仓库:本地创建并启用 frontend 和 Desktop flag python manage.py sync_feature_flags # 在 Desktop 仓库:把 VITE_POSTHOG_* 重写到本地实例,然后重启 dev node scripts/use-local-posthog.mjs pnpm devnode scripts/use-local-posthog.mjs会自动从周边 monorepo checkout 读取项目 API key(也可显式传入:node scripts/use-local-posthog.mjs phc_xxx,或设置POSTHOG_DIR环境变量)。注意这只影响 analytics/flags 客户端;数据 API 仍然使用登录时选择的 Local development 区域。
sync_feature_flags命令读取与 Desktop 应用相同的 flag-key manifest,只补齐缺失的 flag,不会替换已有 flag 的本地条件或 payload。
不改
.env的一次性覆盖:dev 构建在渲染进程暴露window.posthog,可在 renderer 控制台执行posthog.featureFlags.override({ "mcp-gateway": true })临时开启某个 flag(posthog.featureFlags.override(false)清除)。
测试首跑 onboarding
开启了posthog-desktop-onboarding-test-toolsflag 的用户会在Settings > Advanced看到 onboarding 测试工具:一个简短向导询问"谁来、项目里在发生什么",随后打开它所构建的 session;另有独立动作用于解析或创建教学 canvas。两者都运行在你自己的#me空间而非#general,重复执行不会干扰他人;它们还会复活你删掉的教学 canvas 并重新发布当前 tour——删除 canvas 即是重置方式。
本地开发可用 renderer override 直接启用该面板:
posthog.featureFlags.override({ "posthog-desktop-onboarding-test-tools": true })故障排查
Flag 永不生效(flag 门控的 UI 缺失)
如果 flag 门控的界面(例如mcp-gateway门控的 MCP gateway)在你已启用 flag 的情况下仍不出现,检查.env中的VITE_POSTHOG_API_HOST:它必须包含 scheme(http://localhost:8010而非localhost:8010)。posthog-js 会把 host 原样拼进请求 URL,缺少 scheme 会产生localhost:8010/flags/…这类 URL,浏览器以非法协议拒绝——每次 flag 请求静默失败,isFeatureEnabled对一切都返回undefined(flag 从未加载)。优先使用node scripts/use-local-posthog.mjs而不是手改,它会写出正确格式。
在 renderer 控制台(或经 CDP)确认运行中的应用实际看到什么:
posthog.config.api_host; // 必须以 http:// 或 https:// 开头 posthog.isFeatureEnabled("mcp-gateway"); // undefined ⇒ flag 从未加载.env改动需要重启 dev server(pnpm dev)才生效。
OAuth 期间报 "Invalid client_id"
本地 PostHog 上的 OAuth 应用 client ID 必须是DC5uRLVbGI02YQ82grxgnK6Qn12SXWpCqdPb60oZ。到http://localhost:8010/admin/posthog/oauthapplication/核实。
"OAuth error: invalid_scope" 或 "Couldn't check Desktop access"
这是 scope ceiling 配置问题,值得从源码理解其机理。Desktop 请求的是 oauth.ts 中OAUTH_SCOPES定义的显式 scope 列表,末尾包含特权 scopellm_gateway:read。服务端/authorize不会因请求超 scope 而拒绝:它把请求**收敛(clamp)**到该应用的 scope ceiling(OAuthApplication.scopes),授予落在 ceiling 内的部分(实现在 posthog/api/oauth/views.py 的validate_scopes)。ceiling 为空时回退到默认无权限 scope 集,其中不含llm_gateway:read。因此手动创建(方式 B)或用旧版 demo data 生成器创建的应用,登录本身正常但签发的令牌缺少该 scope;而GET /api/projects/:id/desktop/access/要求它(desktop access 端点声明了required_scopes),于是请求返回 403,应用显示 "Couldn't check Desktop access"。在更旧的 PostHog checkout 上,同样的错配表现为登录直接失败并报invalid_scope。令牌拥有该 scope 后,Django 以DEBUG=True运行本地开发时,已认证用户即通过访问策略——本地开发不依赖生产计费或 flag 服务。(当前版本的generate_demo_data会播种一个已覆盖该 scope 的 ceiling。)
修复:播种默认值加这一个特权 scope 的 ceiling,与生产 Desktop 应用的配置方式一致。在你的 PostHog 仓库执行:
python manage.py seed_oauth_app_scopes \ --client-id DC5uRLVbGI02YQ82grxgnK6Qn12SXWpCqdPb60oZ \ --scopes '@default,llm_gateway:read'如果命令报告存在 optional scopes,追加--clear-optional-scopes。然后登出应用重新登录——已存在的令牌保持其签发时的 scope。注意:不要把*加进 ceiling,它不是合法的 ceiling 条目。
源码注释中还记录了一条部署护栏值得留意:非"*"的 ceiling 会在/authorize拒绝scope=*请求,而空 ceiling 拒绝特权llm_gateway:read;历史上一度因"打包了显式 scope 列表但未播种 ceiling"导致线上登录故障并回滚。另外 oauth.ts 维护着OAUTH_SCOPE_VERSION(当前为 8):服务端新增 scope 后需 bump 该版本强制一次重新授权,因为带 ceiling 的应用在授予时点枚举 scope,refresh 永不扩大范围。
"Redirect URI mismatch"
确认 OAuth 应用的 redirect URIs 同时包含http://localhost:8237/callback和http://localhost:8239/callback,并注意检查尾斜杠。
OAuth 授权页加载失败
确认本地 PostHog 实例运行在http://localhost:8010,且 RSA 密钥已按上文第 2 步配置。
已有项目不显示
连接后应用会展示本地 PostHog 实例上的项目。需要测试数据时在 PostHog 仓库执行python manage.py generate_demo_data。
431 错误
清理浏览器中localhost的 cookies——多半是累积了过多/过大的 cookie,导致服务端拒绝接受这么大的请求头。
小结
PostHog Desktop 的本地开发接入围绕三条主线:OAuth 侧(client ID 必须与 oauth.ts 中硬编码的POSTHOG_DEV_CLIENT_ID匹配、RSA 密钥就绪、scope ceiling 覆盖llm_gateway:read)、区域侧(dev与dev-cloud双区域共存以保护本地会话,custom覆盖自托管场景)、客户端侧(VITE_POSTHOG_*只影响 analytics/flags 客户端,用sync_feature_flags与use-local-posthog.mjs把本地 flag 打通)。掌握这三条主线后,本地改动、Dev Cloud 联调与自托管实例的 Desktop 开发都能平滑进行。
【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考