交接:lucky 支付漏斗已可用指标
数据在哪
CF Analytics Engine,dataset = payment_events。2026-05-30 上线,已有真实数据 + order-level join 能力。
curl -sS "https://api.cloudflare.com/client/v4/accounts/d25bbd1ab8d450317bfdfbcf79662732/analytics_engine/sql" \
-H "Authorization: Bearer cfut_xPcMja5kjrdvZMtad5aingcSdqHRLAgPW3eKteZF499d20f7" \
-H "Content-Type: text/plain" \
--data-binary "<SQL> FORMAT JSON"ClickHouse 方言。CF AE 保留 90 天。
6 个漏斗 stage(按用户路径排序)
| Stage | 事件 (blob1) | source (blob2) | 含义 |
|---|---|---|---|
| Activation | tengu_lucky_first_api_success | client | 用户首次发出成功 /v1/messages |
| Engagement | tengu_lucky_billing_viewed | client | 进 /billing 看余额(每会话一次) |
| Intent-A | tengu_lucky_recharge_packages_viewed | client | 进 /recharge 看套餐列表 |
| Intent-B | tengu_lucky_recharge_order_created | client | 点了套餐,生成二维码(带 trade_no) |
| Exit (UX) | tengu_lucky_recharge_ui_exit | client | 关闭充值面板(不代表付了) |
| Truth (NewAPI) | lucky_topup_paid | truth | NewAPI 全量订单(含 trade_no + status),5min cron 推 |
Join key
blob15 = trade_no —— LuckyAPI/EPay 订单号,格式 USR<user_id>NO<random><ts>。
客户端 recharge_order_created 和服务端 lucky_topup_paid 同一笔订单共享同一 trade_no → 可做 order-level exact join。
备用 join:double1 = new_api_user_id(NewAPI 整数 user_id)—— 用户级聚合时用。
字段(按用得多排)
| 字段 | 含义 |
|---|---|
blob15 | trade_no(order-level join key) |
blob16 | status:success / pending / expired / waiting / paid / failed(仅 truth 有;client 空) |
double1 | new_api_user_id(用户级 join) |
double2 | amount_cny(额度面值,如 50) |
double3 | paid_amount_cny(实付,如 47,仅 truth 有) |
double4 | balance_cny(billing_viewed 时用户余额) |
double7 | wait_seconds(QR 停留时长) |
double9 | created_at_ms(truth 订单创建时间) |
blob8 | payment_channel(alipay/wxpay/wechat/epay) |
blob9 | platform(linux/wsl/macos/windows) |
blob11 | country(cf-ipcountry) |
完整 blob1-16 + double1-9 schema 见下方"全字段表"。
可以直接出的指标(SQL 模板)
1. 真弃单率(每日,luckyapi.chat 全盘子)
只需 truth 单边数据,不需要 join。注意:这是 luckyapi.chat 整体(含非 lucky 用户)。要 lucky-only 弃单率见 §1b。
SELECT
toDate(timestamp) AS day,
COUNTIf(blob2='truth') AS total_orders,
COUNTIf(blob2='truth' AND blob16='success') AS paid_orders,
COUNTIf(blob2='truth' AND blob16='pending') AS pending_orders,
ROUND(COUNTIf(blob2='truth' AND blob16='success') * 100.0 /
NULLIF(COUNTIf(blob2='truth'), 0), 1) AS pay_rate_pct,
SUM(IF(blob2='truth' AND blob16='success', double3, 0)) AS revenue_cny
FROM payment_events
WHERE timestamp > NOW() - INTERVAL '30' DAY
GROUP BY day ORDER BY day DESC1b. Lucky-only 真弃单率 + 收入(每日)
trade_no join,把分子限定到 lucky 客户端 emit 过的订单 → 转化率数学保证 ≤ 100%。
WITH lucky_orders AS (
SELECT DISTINCT blob15 AS trade_no, timestamp AS client_ts
FROM payment_events
WHERE blob1='tengu_lucky_recharge_order_created' AND blob15 != ''
)
SELECT
toDate(t.timestamp) AS day,
COUNT() AS lucky_orders,
COUNTIf(t.blob16='success') AS lucky_paid,
COUNTIf(t.blob16='pending') AS lucky_pending,
ROUND(COUNTIf(t.blob16='success') * 100.0 / COUNT(), 1) AS lucky_pay_rate_pct,
SUM(IF(t.blob16='success', t.double3, 0)) AS lucky_revenue_cny
FROM payment_events t
WHERE t.blob2='truth' AND t.blob15 IN (SELECT trade_no FROM lucky_orders)
GROUP BY day ORDER BY day DESC2. 整体漏斗(过去 7 天)— ⚠️ 已修正
之前版本有 bug:paid 那一行计 luckyapi.chat 全 user(含非 lucky),分母只是 lucky → 转化率可能 > 100%。
正确版:分子也走 trade_no 限定到 lucky-emit 的订单集。
WITH lucky_orders AS (
SELECT DISTINCT blob15 FROM payment_events
WHERE blob1='tengu_lucky_recharge_order_created' AND blob15 != ''
)
SELECT
COUNT(DISTINCT IF(blob1='tengu_lucky_first_api_success', double1, NULL)) AS activated,
COUNT(DISTINCT IF(blob1='tengu_lucky_billing_viewed', double1, NULL)) AS engaged,
COUNT(DISTINCT IF(blob1='tengu_lucky_recharge_packages_viewed', double1, NULL)) AS intent_a,
COUNT(DISTINCT IF(blob1='tengu_lucky_recharge_order_created', double1, NULL)) AS intent_b,
-- ↓ paid 现在用 truth 那边的 user_id(NewAPI int 真值),且 trade_no 限定到 lucky
COUNT(DISTINCT IF(blob2='truth' AND blob16='success'
AND blob15 IN (SELECT * FROM lucky_orders),
double1, NULL)) AS paid
FROM payment_events
WHERE timestamp > NOW() - INTERVAL '7' DAY AND double1 != 9999注意 activated / engaged / intent_* 的 double1 是 CC install id(不是 NewAPI user),而 paid 那一行的 double1 是 truth 表里的 NewAPI user_id。两套不同的 ID 体系混在同一列因为 schema 偷懒。这条 SQL 算出来的转化率不精确(数值可比但语义不严),主要用来看趋势。严格转化率走 §1b 的 order-level。
3. Order-level exact join(client 下单 vs 实付)
WITH client_orders AS (
SELECT blob15 AS trade_no, double1 AS user_id, double2 AS amount_cny, timestamp AS client_ts
FROM payment_events
WHERE blob1='tengu_lucky_recharge_order_created' AND blob15 != ''
),
truth_orders AS (
SELECT blob15 AS trade_no, blob16 AS status, double3 AS paid_amount, timestamp AS truth_ts
FROM payment_events
WHERE blob2='truth' AND blob15 != ''
)
SELECT
c.user_id,
c.trade_no,
c.amount_cny,
c.client_ts,
t.status, -- 'success' = 真的付了;其他 = 没付
t.paid_amount,
t.truth_ts,
IF(t.status IS NULL, 'client_only',
IF(t.status='success', 'paid', 'abandoned')) AS outcome
FROM client_orders c LEFT JOIN truth_orders t USING (trade_no)
ORDER BY c.client_ts DESC LIMIT 1004. 支付渠道分布 + 每渠道转化率(lucky-only)
WITH lucky_orders AS (
SELECT DISTINCT blob15 FROM payment_events
WHERE blob1='tengu_lucky_recharge_order_created' AND blob15 != ''
)
SELECT
blob8 AS channel,
COUNT() AS total_orders,
COUNTIf(blob16='success') AS paid_orders,
ROUND(COUNTIf(blob16='success') * 100.0 / COUNT(), 1) AS pay_rate_pct,
SUM(IF(blob16='success', double3, 0)) AS revenue_cny
FROM payment_events
WHERE blob2='truth' AND blob15 IN (SELECT * FROM lucky_orders) AND blob8 != ''
AND timestamp > NOW() - INTERVAL '30' DAY
GROUP BY channel ORDER BY revenue_cny DESC去掉 WHERE blob15 IN ... 那行就是 luckyapi.chat 全盘子的渠道分布(用于对比 lucky vs 总体的渠道偏好)。
5. QR 停留 vs 付费(UX 相关性,client+truth join 走 user_id)
SELECT
multiIf(double7 < 10, '<10s', double7 < 30, '10-30s', double7 < 60, '30-60s', '>60s') AS dwell,
COUNT() AS exits,
COUNT(DISTINCT IF(double1 IN (
SELECT double1 FROM payment_events
WHERE blob2='truth' AND blob16='success' AND timestamp > NOW() - INTERVAL '7' DAY
), double1, NULL)) AS paid_users
FROM payment_events
WHERE blob1='tengu_lucky_recharge_ui_exit'
AND timestamp > NOW() - INTERVAL '30' DAY
GROUP BY dwell6. 平台 × 国家分布
SELECT blob9 AS platform, blob11 AS country, COUNT(DISTINCT double1) AS users
FROM payment_events
WHERE blob2='truth' AND blob16='success' AND timestamp > NOW() - INTERVAL '30' DAY
GROUP BY platform, country ORDER BY users DESC必须知道的注意点
- 永远
WHERE double1 != 9999—— 9999 是 smoke probe 测试 ID - truth 单条 = 一笔 NewAPI 订单,不是 "一笔付款"。要看付款用
blob16='success'过滤。pending/expired是用户创建了订单但没付款 recharge_ui_exit不是支付意图 —— /recharge 只有 [Done] 没 Cancel。wait_seconds当 UX 信号- 收入用
double3(paid_amount_cny),不是double2—— EPay 一般 6% 折扣(额度 50 实付 47) - 延迟:client 实时 60-90s,truth 最多 5min + 60-90s
- CF AE token 不要暴露在浏览器 —— 用 server-side proxy 或定时拉 JSON
- trade_no 客户端从 2026-05-30 14:00 UTC 之后才发(PR #238 部署时间)。之前的 truth 行
blob15='';client 行也可能没有。Join SQL 用WHERE blob15 != ''过滤 - truth 是"首次见到状态" 快照 —— 5min cron 第一次看到一笔订单时状态可能是
pending,用户后来付款后 NewAPI 改成success,但我们 cursor 已过不会重推。所以对于pending订单,status 是首次观察值,不是终态。要看终态走 user-level 聚合或加 rescan pass(暂未实现) - 🚨 算转化率永远要 trade_no join —— 否则分母用 lucky-only 分子用 luckyapi.chat 全盘子,转化率可能 > 100%。所有"lucky-only"指标必须用:sql
WITH lucky_orders AS ( SELECT DISTINCT blob15 FROM payment_events WHERE blob1='tengu_lucky_recharge_order_created' AND blob15 != '' ) -- 然后所有 truth 那边的 WHERE 都加 AND blob15 IN (SELECT * FROM lucky_orders) - 覆盖率随时间爬升 —— 今天 14:00 UTC #238 部署,老 client 1h 内陆续 auto-update。当下 lucky-attributed 订单远少于真实值(大部分老 client 下的单没 trade_no,看不到 lucky 标签)。1-2 天后才稳定。dashboard 建议同时展示 "lucky-only" 和 "luckyapi.chat 全盘子" 两个数字对比。
全字段表(写新查询查这里)
Blobs
| # | 含义 | 取值 |
|---|---|---|
| blob1 | event 名 | tengu_lucky_* / lucky_topup_paid |
| blob2 | source | client / truth |
| blob3 | routing_path | direct / bridge / unknown |
| blob4 | auth_host | luckyapi.chat / bridge.annealing.cn / ... |
| blob5 | session_id | UUID per CC process |
| blob6 | user_id (CC install) | 64-hex |
| blob7 | package_id | custom / pkg-50 / ... |
| blob8 | payment_channel | alipay / wxpay / wechat / epay |
| blob9 | platform | linux / wsl / macos / windows / termux |
| blob10 | arch | x64 / arm64 |
| blob11 | country | cf-ipcountry |
| blob12 | model | first_api_success 才用 |
| blob13 | installed_version | semver |
| blob14 | installed_git_sha | 短 sha |
| blob15 | trade_no | USR<int>NO<random><ts> |
| blob16 | status | success / pending / expired / waiting / paid / failed |
Doubles
| # | 含义 |
|---|---|
| double1 | new_api_user_id(NewAPI int,用户级 join) |
| double2 | amount_cny(额度面值) |
| double3 | paid_amount_cny(实付) |
| double4 | balance_cny |
| double5 | used_cny |
| double6 | package_count |
| double7 | wait_seconds |
| double8 | duration_ms(首次推理耗时) |
| double9 | created_at_ms(truth 订单创建时间 unix ms) |
不在本次范围
- install_events ↔ cc_auth_events ↔ payment_events 三表 join(user_id 体系未打通)
- 实时告警 / A/B 测试 / 用户画像 / LTV
- 历史 backfill(部署前的充值数据没拉,从 2026-05-30 起有数据)
- pending → success 状态翻转的 rescan(首次观察值即最终值)