新用户流失得最多的地方,往往不在功能,而在安装引导。第一版只放了一个跳转按钮,结果一半用户倒在 GitHub 的授权页面上,既不知道这个 App 要动他们哪些仓库,装完又不知道下一步去哪。来回改了三个版本,最后把引导拆成”介绍 → 安装 → 选仓库”三步,每一步都有明确动作和退路,流失率才真正降下来。这套设计的取舍和踩过的坑,下面按模块写清楚。
一、用户旅程
动笔写页面之前,我们先把用户从登录到建任务的全过程画成一张流程图,再对着每个箭头问一句”用户在这里会不会犹豫、会不会走丢”。翻译工具的目标用户熟悉 Git,但未必装过第三方 GitHub App,链路里任何一个断点,都可能把新用户挡在门外。
登录成功 → 进入引导 → 第 1 步介绍权限
↓
第 2 步跳转到 GitHub 安装
↓
GitHub 回调 → 第 3 步选仓库
↓
创建第一个翻译任务
对照这张图,我们很快定位到三个高流失点:权限说明不清楚、安装回调后丢了上下文、选仓库那一步没有默认值。后面每一节的做法,基本都是冲着这三个点去的。
二、第一步:权限介绍
目标
让用户理解 App 会访问什么、为什么需要这些权限。
我们试过把”安装到 GitHub”按钮直接放在首页,用户点了之后在 GitHub 的权限确认页上反复犹豫,因为他们不知道这个 App 要读哪些仓库、会不会乱改代码。后来把权限说明挪到安装动作之前,用图标加一句人话解释用途,用户看完再点安装,犹豫时间明显缩短。
设计要点
- 用图标 + 文字列出权限项(仓库读写、PR 写、订阅事件);
- 每个权限点 1 句话解释用途;
- 提供”查看详细权限”链接,跳转到 GitHub App 页面;
- 不夸大也不淡化,避免”最””唯一”等极限词。
权限文案我们也试过照搬 GitHub 权限页的描述,结果太长,用户根本读不完。最后压成每条一句,主语落在用户能感知的结果上,比如”把译文以 PR 形式提交”,而不是”获得 contents 的写权限”这类接口术语。
组件
权限列表用独立组件渲染,方便后续在不同入口复用,也便于统一替换文案。
<PermissionList
items={[
{ icon: <Repo />, title: "读取仓库内容", desc: "翻译时读取 Markdown 原文" },
{ icon: <Branch />, title: "创建分支与 PR", desc: "把译文以 PR 形式提交" },
{ icon: <Webhook />, title: "接收 push 事件", desc: "可选自动翻译" },
]}
/>
这里有两个注意点:一是权限项只列当前版本真实用到的,别把整套权限一股脑塞给用户,少就是多;二是每条 desc 都要对着 GitHub 实际授权范围核对一遍,写错一项,等用户在授权页上发现对不上,信任就打了折扣。
三、第二步:跳转到 GitHub 安装
权限介绍通过之后,才让用户点”安装到 GitHub”。这一步我们对比过两种做法:把授权流程内嵌进自己的页面(试完就放弃了,GitHub 的安装流程本质是重定向到它自己的域名,跨域下 cookie 和弹窗策略都会出问题),以及直接整页跳转。最终选了跳转,简单可靠,还能在 URL 里带上 state 参数做回调校验。
- 按钮文案:”安装到 GitHub”;
- 跳转 URL:
https://github.com/apps/{app-slug}/installations/new; - 带
state参数,回调时校验防 CSRF; - 提供”暂不安装”返回首页。
state 设计
state 必须由服务端签发并绑定登录态,不能在前端随便拼。它的作用是让 GitHub 回调回来时,我们能确认”这个安装动作确实是当前登录用户发起的”。
const state = await signState({
userId,
redirect: "/onboarding/select-repo",
});
const installUrl = `https://github.com/apps/{slug}/installations/new?state=${state}`;
这里踩过一个坑:早期版本把 redirect 路径写死在 state 里,用户从中途别的入口进来,回调就落到错误页面。后来改成按来源动态生成,并限制白名单域名,问题才消停。
四、第三步:选仓库
安装成功后,用户会被 GitHub 回调到我们的页面,接下来要解决”翻译任务到底建在哪些仓库上”。这一步直接决定用户能不能马上看到价值,所以交互上给了大量默认值,尽量不让用户做多余决策。
步骤
- 解析 GitHub 回调中的
installation_id; - 用 Installation Token 拉仓库列表;
- 用户勾选要授权的仓库(可多选);
- 后端创建 Repository 记录;
- 引导用户创建首个翻译任务。
步骤 2 的关键在 token 获取:GitHub App 的 App Token 只能验证 App 身份,操作仓库必须换发 Installation Token。我们最初直接用 App Token 拉列表,接口返回 403,查了文档才弄明白这套两段式鉴权,改完代码仓库列表秒级返回。
体验细节
- 默认勾选用户最近更新的仓库;
- 提供”全选 / 反选”;
- 显示仓库大小、最后更新时间;
- 选完仓库后给出”开始翻译” CTA。
仓库列表按最近更新时间倒序,默认勾上前几个,用户基本不用改动就能进入下一步。这个细节把”选仓库”从一次决策变成一次确认,对转化率的提升比我们预想的更明显。
五、状态持久化
- 引导进度用
OnboardingState模型记录; - 用户中途离开可恢复;
- 安装失败显示重试按钮,并提供手动安装链接。
加这一层,是因为真实用户不会按我们设计的路径走:装到一半去开别的标签页,或者回来看一眼又关掉。如果每次进来都从第 1 步开始,用户会明显烦躁。我们把进度存进数据库,按 userId 恢复,用户回到页面直接落在上次离开的那一步。
六、错误与回退
引导流程里,最容易被忽略的是各种”用户不想走完”的场景。我们把能想到的异常列成一张表,逐个确认页面上的兜底体验,保证任何一步失败都不至于让用户卡死。
| 场景 | 体验 |
|---|---|
| 用户拒绝安装 | 保留登录态,跳回”介绍页”给再次尝试按钮 |
| GitHub 回调失败 | 显示错误码 + 重试 |
| 安装成功但无仓库 | 提示先去 GitHub 把仓库加进安装 |
| 用户选完但未保存 | 引导进度保留,下次进入自动跳到第 3 步 |
这张表里最难处理的是”安装成功但无仓库”:用户装好了 App 却选不出一个仓库,很容易误以为工具坏了。我们的方案是把责任引导回 GitHub 页面,同时放上手动安装链接,两条路都走不通再引导用户联系支持。
七、可观测性
- 漏斗:介绍页 → 安装页 → 回调 → 选仓库 → 创建任务;
- 转化率:每步流失率;
- 错误:state 校验失败、回调超时、API 错误;
- 告警:转化率断崖式下跌触发排查。
埋点只做关键路径,五步漏斗加错误码,足够定位大部分问题。我们有过一次教训:回调超时事件量大,把错误日志整个淹没,后来给不同错误分开计数,才看清真正常发的是 state 校验失败,顺着修掉了 session 过期策略。
八、视觉与交互
- 顶部步骤条显示当前进度;
- 文案语气直接,避免技术黑话;
- 不堆砌”免费””最简单”等营销词;
- 移动端布局自适应,CTA 始终可见。
文案这块我们内部过了两轮:第一版写得太”产品腔”,用户读完不知道下一步干嘛;改成直接的动作句之后,页面停留时间反而变短了,说明用户读懂了。步骤条在移动端只显示当前步和总步数,避免挤占屏幕空间。
九、安全考虑
state必须与服务端 session 绑定;- 安装回调只接受可信域名;
- 跳转到 GitHub 时用 302 而不是 link,避免被预取。
state 是我们排查最久的一块。回调时如果只校验 state 存在、不校验它和当前 session 的绑定关系,攻击者就能伪造回调,把别人的安装绑到自己账号下。绑定校验加域名白名单加一次性使用,三层都补上之后,安全测试才通过。
十、给同类项目的建议
- 安装步骤拆分要细,每步一个目标;
- 引导页要可回退,不能让用户卡死;
- 状态要持久化,允许用户离开再回来;
- 关键路径埋点,定位流失。
这套流程跑通之后,从安装到创建第一个翻译任务,全程稳定在几分钟内,用户不用翻任何文档。如果再做一遍,我们会在第 1 步就加入组织维度的引导,把”个人仓库”和”组织仓库”的安装差异提前讲清楚。
常见问题(FAQ)
Q1:要不要强制安装?
不要。用户可以先浏览文档,App 真正需要时才弹安装。
Q2:state 校验失败怎么处理?
提示用户重试,并清掉当前 state 重新生成。
Q3:用户多组织怎么办?
第 3 步选仓库时按组织分组,逐个安装到对应账号。