关于 aa-conversion-funnel-analysis
aa-conversion-funnel-analysis 使用 Adobe Analytics 的访问级细分和报告分析多步骤转化漏斗。它估算各步骤的转化与流失,并检查最大流失处的受众维度;结果并非严格的顺序流失数据。
主要功能
- 01定义最多八步的漏斗
- 02查找或创建访问级步骤细分
- 03计算转化率与流失率
- 04定位流失最多的步骤
- 05按受众维度拆分结果
- 06生成 HTML 报告
适用场景
- 01定位结账流程中的流失
- 02比较不同设备类型的步骤进展
- 03查看漏斗各步骤的访问级转化
MCP 相关
该技能使用 Adobe Analytics MCP 工具查找报告套件、维度、指标和细分,并运行报告。它本身不提供 MCP 服务端。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ adobe/ skills --skill aa-conversion-funnel-analysis安装后在 Claude Code 中输入/aa-conversion-funnel-analysis确认已加载。
附带文件evals/evals.json
详细介绍
转化漏斗分析(Adobe Analytics)
分析多步骤转化漏斗,找出访客在哪些环节流失、哪些步骤的流失最严重,以及推动访客转化或放弃的因素。使用 AA 基于访问级别区段的报告来模拟漏斗步骤。
AA 容器模型: AA 漏斗使用 hit、visit 和 visitor 容器,而非 CJA 的 event/session/person。漏斗步骤定义为访问级别区段(即在一次访问期间完成该步骤的访客)。
报告方式: AA 没有可通过 MCP 使用的原生顺序流失 API。此技能通过为每个漏斗步骤创建或查找访问级别区段,再针对每个步骤区段运行指标来近似计算流失率。
使用的 AA MCP 工具
findReportSuites— 选择报表包setSessionDefaults— 设置会话上下文(reportSuiteId + globalCompanyId)findDimensions— 查找用于定义步骤的页面/事件维度findMetrics— 查找作为计数指标的访问或订单searchDimensionItems— 验证页面名称或事件值findSegments— 查找现有步骤区段(如果有)upsertSegment— 未找到时创建访问级别步骤区段runReport— 运行每个步骤区段的访问次数报告
阶段 0 — 设置
- 使用
findReportSuites/setSessionDefaults确认报表包。 - 询问用户漏斗的整体范围(访问级别或访客级别):
- 访问级别漏斗: 所有步骤都在单次访问中完成 (结账漏斗的常见形式)
- 访客级别漏斗: 步骤可以跨多次访问完成 (生命周期漏斗的常见形式)
findReportSuites(globalCompanyId: "<gcid>", page: 0, limit: 10)
setSessionDefaults(globalCompanyId: "<gcid>", reportSuiteId: "<rsid>")
阶段 1 — 定义漏斗步骤
请用户用通俗语言描述漏斗的每个步骤。 提示用户提供 3–8 个步骤。例如:
- 查看产品页面
- 加入购物车
- 开始结账
- 输入付款信息
- 确认订单(购买)
针对每个步骤,询问:
- “此步骤由页面浏览(页面名称或 URL)、自定义事件,还是两者组合来定义?”
- “此步骤应为 hit 级别(单次页面/事件),还是 visit 级别(发生过此情况的任意访问)?”
阶段 2 — 查找组件
2.1 验证页面名称
对于基于页面的步骤:
findDimensions(page: 1, limit: 500) # returns all available dimensions; look for variables/page
searchDimensionItems(
dimensionId: "variables/page",
searchOr: "<step page keywords>", # space-separated keywords OR'd together
startDate: "<start>",
endDate: "<end>",
page: 1,
limit: 20
)
常见页面维度 ID:variables/page、variables/entrypage、variables/exitpage。
如果存在多个匹配项,请与用户确认正确的页面名称值。
注意:
searchDimensionItems使用searchOr或searchAnd进行筛选,而非searchTerm。 如果没有返回行,请尝试扩大日期范围——有些报表包只有历史数据。
2.2 验证事件/指标
对于基于事件的步骤(加入购物车、结账、购买):
findMetrics(expansions: "componentType,categories", page: 0, limit: 200)
# Filter results locally by name: visits, orders, pageviews, etc.
阶段 3 — 查找或创建步骤区段
针对每个漏斗步骤,搜索现有区段:
findSegments(searchTerm: "<step description>")
如果存在合适的访问级别区段,请直接使用。
如果没有,请为每个步骤创建新的访问级别区段:
upsertSegment(
definition: {
"name": "Visit: Checkout Started",
"description": "Visits where the visitor reached the checkout page",
"reportSuiteID": "<rsid>",
"container": {
"func": "segment",
"context": "visits",
"pred": {
"func": "streq",
"val": "/checkout",
"str": "/checkout",
"dimension": "variables/page"
}
},
"tags": [{ "name": "funnel" }]
}
)
运行报告前创建所有步骤区段。记录每个区段的 id。
重要: 只有在获得用户明确确认后才能创建新区段。 列出要创建的区段,并询问:“我需要创建 N 个访问级别区段来定义您的漏斗步骤。可以吗?”
阶段 4 — 运行漏斗步骤报告
针对每个步骤区段,在分析周期内运行访问次数报告:
runReport(
dimensionId: "variables/page", # required by AA runReport
metricIds: "metrics/visits", # note: plural field name "metricIds"
segmentIds: "<step segment id>", # note: plural field name "segmentIds"
startDate: "<start>",
endDate: "<end>",
limit: 1
)
# summaryData.totals[0] is the total visits for this segment
每个漏斗步骤调用 1 次。对于 5 步漏斗,共调用 5 次。
另外,运行总访问次数(不使用区段)作为 100% 基准:
runReport(
dimensionId: "variables/page",
metricIds: "metrics/visits",
startDate: "<start>",
endDate: "<end>",
limit: 1
)
# Use summaryData.totals[0] as the baseline visit count
AA runReport 字段名称: 使用
metricIds(而非metricId)和segmentIds(而非segmentId)。 使用startDate/endDate(ISO 8601),而非dateRange对象。 始终从summaryData.totals[0]读取总数,而不是从rows读取。
阶段 5 — 计算漏斗指标
对于每个步骤,计算:
| 指标 | 公式 |
|---|---|
| 步骤访问量 | runReport 返回的原始计数 |
| 步骤转化率 | 步骤访问量 / 总访问量 × 100 |
| 步骤间转化率 | 第 N 步访问量 / 第 N-1 步访问量 × 100 |
| 步骤间流失量 | 第 N-1 步访问量 - 第 N 步访问量 |
| 流失率 | 100 - 步骤间转化率 |
找出流失量最大的步骤(绝对流失量最高)和 转化率最低的步骤(步骤间转化率最低)。
阶段 6 — 深入分析流失最严重的步骤
针对流失量最高的步骤,运行维度细分报告,找出继续推进的访客与流失访客 之间的差异:
runReport(
dimensionId: "variables/mobiledevicetype",
metricIds: "metrics/visits",
segmentIds: "<worst step segment>",
startDate: "<start>",
endDate: "<end>",
limit: 10
)
runReport(
dimensionId: "variables/mobiledevicetype",
metricIds: "metrics/visits",
segmentIds: "<next step segment>",
startDate: "<start>",
endDate: "<end>",
limit: 10
)
比较完成最严重流失步骤的访客与到达下一步骤的访客在设备类型上的分布。 再针对其他 1–2 个维度重复此操作 (例如,流量来源、新访客与回访访客)。
阶段 7 — 生成 HTML 报告
在此处构建漏斗报告,并写入
/tmp/aa_funnel_analysis_report_<YYYY-MM-DD_HHMMSS>.html。
HTML 模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Funnel Health — {ORG_NAME} — {FUNNEL_NAME}</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700;900&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #f5f4f1;
--surface: #ffffff;
--ink: #1a1a1a;
--ink-muted: #6b6b6b;
--border: #e5e2dc;
--header-bg: #0e0e10;
--header-warm: #3a1010;
--accent-red: #c8312f;
--accent-red-bright: #ff6b68;
--accent-red-soft: #fdecea;
--accent-green: #1f7a4d;
--accent-yellow: #d4a017;
}
body { font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
background: var(--bg); color: var(--ink); line-height: 1.5;
-webkit-font-smoothing: antialiased; }
/* === Header === */
header { background: linear-gradient(120deg, var(--header-bg) 0%, #1a0d0d 55%, var(--header-warm) 100%);
color: #fff; padding: 56px 56px 44px; position: relative; overflow: hidden; }
header::after { content: ""; position: absolute; right: -140px; top: -140px;
width: 460px; height: 460px;
background: radial-gradient(circle, rgba(200,49,47,.35) 0%, transparent 70%);
pointer-events: none; }
.header-inner { max-width: 1080px; margin: 0 auto; position: relative; z-index: 1; }
.eyebrow { display: inline-flex; align-items: center; gap: 8px;
padding: 6px 14px; border: 1px solid rgba(255,107,104,.55);
border-radius: 999px; color: var(--accent-red-bright);
font-size: 11px; font-weight: 600; letter-spacing: 1.2px;
text-transform: uppercase; margin-bottom: 24px;
background: rgba(200,49,47,.10); }
.eyebrow::before { content: ""; width: 6px; height: 6px;
background: var(--accent-red-bright); border-radius: 50%; }
header h1 { font-family: "Playfair Display", Georgia, serif;
font-size: 56px; font-weight: 700; letter-spacing: -1.5px;
line-height: 1.05; margin-bottom: 14px; color: #fff; }
header .lede { font-size: 16px; max-width: 600px;
color: rgba(255,255,255,.80); margin-bottom: 24px;
line-height: 1.55; }
header .meta { display: flex; flex-wrap: wrap; gap: 22px;
font-size: 13px; color: rgba(255,255,255,.60); }
header .meta span { display: inline-flex; align-items: center; gap: 6px; }
header .meta .icon { opacity: .8; }
/* === Tabs === */
nav { background: var(--surface); border-bottom: 1px solid var(--border);
padding: 0 56px; display: flex; gap: 28px;
position: sticky; top: 0; z-index: 50; }
nav a { display: block; padding: 16px 0; font-size: 14px;
color: var(--ink); text-decoration: none;
border-bottom: 2px solid transparent;
transition: border-color .15s ease; }
nav a:hover { border-bottom-color: var(--accent-red); }
/* === Container === */
.container { max-width: 1080px; margin: 0 auto; padding: 36px 56px 60px; }
/* === Section label === */
.section-label { font-size: 11px; font-weight: 700;
text-transform: uppercase; letter-spacing: 1.4px;
color: var(--ink-muted); margin-bottom: 14px;
padding-bottom: 10px; border-bottom: 1px solid var(--border); }
/* === Funnel visualization (horizontal stepped bars) ===
Bar color is set per step by tier:
.tier-strong = green (rate >= 70% pass-through)
.tier-mid = yellow (40-69%)
.tier-weak = red (< 40%)
The biggest-leakage step also gets .step-bar.worst (red, regardless of tier). */
.funnel-wrap { background: var(--surface); border-radius: 8px;
padding: 28px 32px; margin-bottom: 28px;
box-shadow: 0 1px 3px rgba(0,0,0,.04); }
.funnel-step { display: flex; align-items: center; margin-bottom: 10px; }
.step-label { width: 220px; font-size: 14px; font-weight: 600;
text-align: right; padding-right: 16px; white-space: nowrap;
overflow: hidden; text-overflow: ellipsis; color: var(--ink); }
.step-bar-wrap { flex: 1; position: relative; height: 44px;
background: #f4f1eb; border-radius: 4px; }
.step-bar { height: 44px; border-radius: 4px;
display: flex; align-items: center; padding: 0 14px;
color: #fff; font-size: 13px; font-weight: 700;
transition: width 0.4s ease;
background: var(--accent-green); }
.step-bar.tier-strong { background: var(--accent-green); }
.step-bar.tier-mid { background: var(--accent-yellow); color: #3a2a05; }
.step-bar.tier-weak { background: var(--accent-red); }
.step-bar.worst { background: var(--accent-red); color: #fff; }
.step-meta { width: 200px; padding-left: 16px; font-size: 12px;
color: var(--ink-muted); }
.step-meta .rate { font-family: "Playfair Display", Georgia, serif;
font-size: 18px; font-weight: 700;
color: var(--ink); line-height: 1; }
.step-meta .drop { color: var(--accent-red); font-weight: 600;
display: block; margin-top: 4px; }
/* === Collapsible sections === */
.section { background: var(--surface); border-radius: 8px;
box-shadow: 0 1px 3px rgba(0,0,0,.04);
margin-bottom: 22px; overflow: hidden; }
.section-header { padding: 18px 28px; border-bottom: 1px solid var(--border);
display: flex; justify-content: space-between;
align-items: center; cursor: pointer; user-select: none; }
.section-header h2 { font-family: "Playfair Display", Georgia, serif;
font-size: 18px; font-weight: 700; }
.toggle { font-size: 16px; color: var(--accent-red); }
/* === Tables === */
table { width: 100%; border-collapse: collapse; font-size: 13px; }
thead th { background: #faf8f4; padding: 12px 22px;
text-align: left; font-weight: 600;
text-transform: uppercase; letter-spacing: .6px;
font-size: 11px; color: var(--ink-muted);
border-bottom: 1px solid var(--border); }
tbody td { padding: 12px 22px; border-bottom: 1px solid #f4f1eb; }
tbody tr:last-child td { border-bottom: none; }
/* === Badges === */
.badge { display: inline-block; padding: 3px 9px; border-radius: 4px;
font-size: 11px; font-weight: 600; }
.badge.green { background: #ebf5ef; color: var(--accent-green); }
.badge.yellow { background: #fef6e3; color: #b67a08; }
.badge.red { background: var(--accent-red-soft); color: var(--accent-red); }
/* === Insight callout === */
.insight { background: var(--accent-red-soft);
border-left: 4px solid var(--accent-red);
border-radius: 6px; padding: 16px 22px;
margin: 16px 28px; font-size: 14px; line-height: 1.6;
color: #4a2222; }
.back-top { position: fixed; bottom: 24px; right: 24px; background: var(--accent-red);
color: #fff; width: 44px; height: 44px; border-radius: 50%; border: none;
font-size: 20px; cursor: pointer;
box-shadow: 0 4px 12px rgba(200,49,47,.35); }
footer { text-align: center; padding: 32px 24px;
font-size: 12px; color: var(--ink-muted); }
/* === Print === */
@media print {
nav { display: none; position: static; }
header { padding: 36px 32px 28px; }
header h1 { font-size: 42px; }
.section-header { cursor: default; }
.back-top { display: none; }
.funnel-wrap, .section {
box-shadow: none; border: 1px solid var(--border); break-inside: avoid;
}
}
</style>
</head>
<body>
<header>
<div class="header-inner">
<div class="eyebrow">Funnel Health Report</div>
<h1>{ORG_NAME} Funnel Health</h1>
<p class="lede">Step-by-step pass-through for the {FUNNEL_NAME} funnel during {DATE_RANGE}.</p>
<div class="meta">
<span><span class="icon">📅</span> {DATE_RANGE}</span>
<span><span class="icon">📊</span> {REPORT_SUITE}</span>
<span><span class="icon">🕔</span> Prepared {GENERATED_DATE}</span>
</div>
</div>
</header>
<nav>
<a href="#funnel">Funnel</a>
<a href="#steps">Step Detail</a>
<a href="#leakage">Leakage Analysis</a>
<a href="#recommendations">Recommendations</a>
</nav>
<div class="container">
<div class="section-label">Funnel Pass-Through</div>
<div id="funnel" class="funnel-wrap">
</div>
<div id="steps" class="section">
<div class="section-header" onclick="toggle('steps-body')">
<h2>Step Detail</h2>
<span class="toggle" id="steps-body-icon">▾</span>
</div>
<div id="steps-body">
<table>
<thead><tr>
<th>Step</th><th>Visits</th><th>% of Total</th>
<th>Step Rate</th><th>Drop-off</th>
</tr></thead>
<tbody></tbody>
</table>
</div>
</div>
<div id="leakage" class="section">
<div class="section-header" onclick="toggle('leak-body')">
<h2>Leakage Analysis (Worst Step: {WORST_STEP_NAME})</h2>
<span class="toggle" id="leak-body-icon">▾</span>
</div>
<div id="leak-body">
<div class="insight">{LEAKAGE_INSIGHT_TEXT}</div>
<table>
<thead><tr>
<th>Dimension</th><th>Entered Step</th><th>Completed Step</th>
<th>Step Rate</th><th>vs. Average</th>
</tr></thead>
<tbody></tbody>
</table>
</div>
</div>
<div id="recommendations" class="section">
<div class="section-header" onclick="toggle('rec-body')">
<h2>Recommendations</h2>
<span class="toggle" id="rec-body-icon">▾</span>
</div>
<div id="rec-body">
</div>
</div>
</div>
<button class="back-top" onclick="window.scrollTo({top:0,behavior:'smooth'})">
⇧
</button>
<footer>Funnel Health — {ORG_NAME} — Generated {GENERATED_DATE}</footer>
<script>
function toggle(id) {
var el = document.getElementById(id);
var ic = document.getElementById(id + '-icon');
if (el.style.display === 'none') { el.style.display = ''; ic.textContent = '\u25be'; }
else { el.style.display = 'none'; ic.textContent = '\u25b8'; }
}
</script>
</body>
</html>
章节标题 — 不带阶段前缀:HTML 报告中的章节标题不得包含 阶段编号。仅使用简洁的章节名称(例如,“漏斗概览”,而不是“阶段 2 — 漏斗概览”, “流失分析”,而不是“阶段 3 — 流失分析”)。
写入 /tmp/aa_funnel_analysis_report_<YYYY-MM-DD_HHMMSS>.html 并打开:
open /tmp/aa_funnel_analysis_report_<YYYY-MM-DD_HHMMSS>.html
约束
- 始终先列出要创建的分群(第 3 步),并在调用
upsertSegment前获得用户 确认。 - 如果用户已经为漏斗步骤创建了命名分群,应优先使用这些分群,而不是创建新的分群——
请先检查
findSegments。 - 漏斗最多包含 8 个步骤,以控制 API 调用预算。
- 使用访问分群计算的漏斗转化率仅为近似值—— 它们统计的是触及每个步骤的访问,而非严格按顺序流失的情况。请向用户说明此限制。
交互示例
“分析我们的结账漏斗——我想看看访客在哪一步流失。”
- 确认报表套件和日期范围(最近 30 天)。
- 定义 5 个步骤:产品浏览 → 加入购物车 → 结账 → 付款 → 购买。
- 使用
searchDimensionItems验证页面名称。 - 查找现有步骤分群,或在用户批准后创建新分群。
- 运行 6 份报告(5 个步骤 + 总计)。
- 计算:100% → 42%(加入购物车)→ 28%(结账)→ 19%(付款)→ 11%(购买)。总体转化率:11%。
- 流失最严重的步骤:从加入购物车到结账(流失率为 33%)。
- 深入分析:移动设备用户的结账率仅为 18%,而桌面设备用户为 31%。
- 生成并打开 HTML 报告。
- 关键洞察:“移动端是漏斗中最大的短板。可以考虑简化移动端的结账体验。”