Skip to content

交接:lucky 支付漏斗已可用指标

数据在哪

CF Analytics Engine,dataset = payment_events。2026-05-30 上线,已有真实数据 + order-level join 能力。

bash
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)含义
Activationtengu_lucky_first_api_successclient用户首次发出成功 /v1/messages
Engagementtengu_lucky_billing_viewedclient进 /billing 看余额(每会话一次)
Intent-Atengu_lucky_recharge_packages_viewedclient进 /recharge 看套餐列表
Intent-Btengu_lucky_recharge_order_createdclient点了套餐,生成二维码(带 trade_no
Exit (UX)tengu_lucky_recharge_ui_exitclient关闭充值面板(不代表付了
Truth (NewAPI)lucky_topup_paidtruthNewAPI 全量订单(含 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)—— 用户级聚合时用。

字段(按用得多排)

字段含义
blob15trade_no(order-level join key)
blob16status:success / pending / expired / waiting / paid / failed(仅 truth 有;client 空)
double1new_api_user_id(用户级 join)
double2amount_cny(额度面值,如 50)
double3paid_amount_cny(实付,如 47,仅 truth 有)
double4balance_cny(billing_viewed 时用户余额)
double7wait_seconds(QR 停留时长)
double9created_at_ms(truth 订单创建时间)
blob8payment_channel(alipay/wxpay/wechat/epay)
blob9platform(linux/wsl/macos/windows)
blob11country(cf-ipcountry)

完整 blob1-16 + double1-9 schema 见下方"全字段表"。

可以直接出的指标(SQL 模板)

1. 真弃单率(每日,luckyapi.chat 全盘子)

只需 truth 单边数据,不需要 join。注意:这是 luckyapi.chat 整体(含非 lucky 用户)。要 lucky-only 弃单率见 §1b。

sql
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 DESC

1b. Lucky-only 真弃单率 + 收入(每日)

trade_no join,把分子限定到 lucky 客户端 emit 过的订单 → 转化率数学保证 ≤ 100%。

sql
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 DESC

2. 整体漏斗(过去 7 天)— ⚠️ 已修正

之前版本有 bugpaid 那一行计 luckyapi.chat 全 user(含非 lucky),分母只是 lucky → 转化率可能 > 100%。

正确版:分子也走 trade_no 限定到 lucky-emit 的订单集。

sql
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 实付)

sql
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 100

4. 支付渠道分布 + 每渠道转化率(lucky-only)

sql
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)

sql
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 dwell

6. 平台 × 国家分布

sql
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

必须知道的注意点

  1. 永远 WHERE double1 != 9999 —— 9999 是 smoke probe 测试 ID
  2. truth 单条 = 一笔 NewAPI 订单,不是 "一笔付款"。要看付款用 blob16='success' 过滤。pending / expired 是用户创建了订单但没付款
  3. recharge_ui_exit 不是支付意图 —— /recharge 只有 [Done] 没 Cancel。wait_seconds 当 UX 信号
  4. 收入用 double3(paid_amount_cny),不是 double2 —— EPay 一般 6% 折扣(额度 50 实付 47)
  5. 延迟:client 实时 60-90s,truth 最多 5min + 60-90s
  6. CF AE token 不要暴露在浏览器 —— 用 server-side proxy 或定时拉 JSON
  7. trade_no 客户端从 2026-05-30 14:00 UTC 之后才发(PR #238 部署时间)。之前的 truth 行 blob15='';client 行也可能没有。Join SQL 用 WHERE blob15 != '' 过滤
  8. truth 是"首次见到状态" 快照 —— 5min cron 第一次看到一笔订单时状态可能是 pending,用户后来付款后 NewAPI 改成 success,但我们 cursor 已过不会重推。所以对于 pending 订单,status 是首次观察值,不是终态。要看终态走 user-level 聚合或加 rescan pass(暂未实现)
  9. 🚨 算转化率永远要 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)
  10. 覆盖率随时间爬升 —— 今天 14:00 UTC #238 部署,老 client 1h 内陆续 auto-update。当下 lucky-attributed 订单远少于真实值(大部分老 client 下的单没 trade_no,看不到 lucky 标签)。1-2 天后才稳定。dashboard 建议同时展示 "lucky-only" 和 "luckyapi.chat 全盘子" 两个数字对比。

全字段表(写新查询查这里)

Blobs

#含义取值
blob1event 名tengu_lucky_* / lucky_topup_paid
blob2sourceclient / truth
blob3routing_pathdirect / bridge / unknown
blob4auth_hostluckyapi.chat / bridge.annealing.cn / ...
blob5session_idUUID per CC process
blob6user_id (CC install)64-hex
blob7package_idcustom / pkg-50 / ...
blob8payment_channelalipay / wxpay / wechat / epay
blob9platformlinux / wsl / macos / windows / termux
blob10archx64 / arm64
blob11countrycf-ipcountry
blob12modelfirst_api_success 才用
blob13installed_versionsemver
blob14installed_git_sha短 sha
blob15trade_noUSR<int>NO<random><ts>
blob16statussuccess / pending / expired / waiting / paid / failed

Doubles

#含义
double1new_api_user_id(NewAPI int,用户级 join)
double2amount_cny(额度面值)
double3paid_amount_cny(实付)
double4balance_cny
double5used_cny
double6package_count
double7wait_seconds
double8duration_ms(首次推理耗时)
double9created_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(首次观察值即最终值)

Claude Code 中文教程站