skills/tt4b-account-benchmark/SKILL.md
Platform-neutral TikTok account benchmark workflow. Use whenever the user asks whether a Campaign, Ad Group, Ad/Creative, or account result is good, strong, weak, worth scaling, better/worse than their account, above/below account baseline, or needs same-account relative performance context — even if they do not say "benchmark". Triggers: account baseline, relative performance, is this good, small sample noise, which one is stronger, 同账户对比, 账户基准, 表现好不好, 还行吗, 值不值得继续投, 哪个更靠谱, 是不是小样本假象, 高 CVR 是否可信. This read-only skill fetches TikTok reports through tt-ads MCP and computes deterministic same-advertiser, same-objective, same-grain benchmark statistics locally. Do NOT use for raw report pulls only (route to tt4b-get-performance-report), delivery/root-cause diagnosis such as no spend or rejection (route to tt4b-diagnose-campaign-health), or budget reallocation/execution (route to tt4b-optimize-budget).
npx skillsauth add chatandbuild/chatchat-skills tt4b-account-benchmarkInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill compares the performance currently being analyzed with a same-account benchmark computed from the same advertiser's own reporting data.
This is a standard skill folder following the SKILL.md plus optional bundled resources pattern.
Keep host-specific setup outside the runtime skill instructions, and do not add local testbench
assumptions to this skill.
Use this skill for:
Plain-language triggers / 非术语触发:
If the user is asking whether a result is good, reliable, scalable, or strong versus their own account, treat it as a benchmark request even when they never use the word "benchmark".
Object display rule:
[Summer Prospecting](https://ads.tiktok.com/...).{name} ({id})
style in tables, bullets, verdicts, or scope text. IDs belong in the URL or in explicit
blocked/partial-link diagnostics for Campaign / AdGroup; for Ad grain, keep IDs out of the
default display.Campaign, AdGroup, or
Creative, not generic Object / 对象. If one answer needs multiple grains, split them into
separate tables./manage/campaign with campaign_ids; AdGroup uses
/manage/adgroup with ad_ids but the filter value must come from the AdGroup identity
(adgroup_id, falling back only when the MCP names that same value ad_id). Ad / Creative
output does not build Ads Manager links, regardless of ordinary or Smart+ type. creative_id,
virtual_creative_id, smart_plus_ad_id, and material IDs are asset/linkage context only; do
not use them as the benchmark grain or user-visible link filter value.filters[0][field]=campaign_ids and filters[0][in_field_values][0]=<campaign_id>.
Do not shorten links to top-level campaign_ids=..., ad_ids=..., or creative_ids=...;
those links may open but will not filter the table correctly.[Unknown name](url) for linked
Campaign / AdGroup rows when a link can be built. For Ad grain, render Unknown name as plain
text and say the name field was unavailable.Benchmark visibility and readability rule:
结论先说, 核心对比,
基准结论, 下一步建议, and 附录:基准范围. For English
output, use Bottom line, Benchmark table, Benchmark verdict, Next steps, and
Appendix: Benchmark scope.Benchmark scope is useful, but for most
readers it is metadata; move it to a compact appendix or one-line scope note near the end.结论先说 should contain only one qualitative judgment plus one key
number. Put other metrics in short bullets or tables instead of stacking them into one sentence.Account benchmark.Benchmark blocked(Benchmark 受阻) or
Partial benchmark(部分 Benchmark) and explain the blocker.Route elsewhere:
tt4b-get-performance-reporttt4b-diagnose-campaign-healthtt4b-optimize-budgetNo-kit fallback:
tt-ads report needed for a
limited performance readout or benchmark, but state that full table export/report workflow is
owned by the reporting skill when available.Language policy:
summary.md artifact.adg, benchmark, CVR,
or creative, answer in Chinese. If the user writes in English, answer in English.result.json and manifest.json remain structured machine-readable artifacts and do not need
natural-language translation.When installed inside a broader tt4b-skill-kit, this skill is the read-only relative-performance
judge. It should be easy to enter from report, diagnosis, or optimization conversations whenever
the user moves from "show me the numbers" to "are these numbers actually good versus my account?"
| Out-of-scope intent | Route to |
|---|---|
| Raw performance table, export, dayparting, or multi-dimensional report without a relative account verdict | tt4b-get-performance-report |
| Delivery health, no spend, no impressions, review rejection, budget exhaustion, bid competitiveness, or creative fatigue root cause | tt4b-diagnose-campaign-health |
| Budget reallocation, pause/resume, budget edits, or executing recommendations that affect spend | tt4b-optimize-budget or tt4b-manage-campaign |
| Creating, duplicating, or editing campaigns, ad groups, ads, creatives, audiences, or catalogs | The matching tt4b-launch-*, tt4b-duplicate-campaign, or tt4b-manage-* skill |
If a neighboring skill already pulled report rows and the user asks a follow-up like "is that good?", "which one is really strong?", "比账户其他 campaign 好吗?", or "高 CVR 可信吗?", switch into benchmark logic using the existing advertiser, window, grain, and objective context when available. Do not reframe that follow-up as another raw report.
In kit environments that expose the tt-ads-mcp dispatcher, follow the kit dispatcher convention:
use direct L0 tools when available, otherwise call tool_get for schemas and then
tool_execute(tool_name="<Tool>", params={...}). The benchmark report logical call maps to the
host's reporting tool, commonly Run_a_synchronous_report in dispatcher kits or
report_integrated_get in direct tt-ads hosts. In environments that expose direct tt-ads MCP
tools, use the direct tool names in references/mcp-report-contract.md.
This compatibility note changes only how tools are invoked. It does not add a new MCP dependency, does not permit direct network access from scripts, and does not allow synthetic or substituted data.
If the user does not specify otherwise:
analysis_window: last 7 complete account-local daysbenchmark_window: same length as analysis_window; default is last 7 complete account-local
days ending on the same date as the analysis windowanalysis_level: Campaignbenchmark_level: same as analysis_levelcost_active_rule: spend > 0metrics: resolve from objective_type; if objective is unknown, default to CPC, CPA, CTR,
CVR, CPM, conversions, and spend with a caveatstatistics: median plus relative position; keep percentile fields internally,
but translate them into advertiser-facing language such as "better than 75% of comparable
Campaigns" or "higher than 75% of comparable Campaigns"default_readout: include both Winners and Draggers whenever the user asks for account
performance, hot objects, best/worst objects, worth scaling, or whether performance is good.
Do not wait for the user to ask separately for underperformers.relative_waterline: every Winner and Dragger shown to the user must carry a benchmark waterline
statement for its own grain, such as "CPA better than 92% of comparable Campaigns" or
"CPA worse than 88% of comparable Campaigns." Do not only say "better than account average" or
"dragging CPA" when percentile/rank evidence is available.single_grain_display: show one entity grain per winner/dragger table. Campaign winners and
AdGroup draggers must not share one table. If multiple grains are relevant, render separate
Campaign / AdGroup / Creative sections.Hard rule: benchmark comparisons must use one analysis target and a like-for-like benchmark pool. The target is a single Campaign, Ad Group, or Ad. Do not merge a 7-day list of entities into one aggregate and compare that aggregate to a 30-day pool.
Benchmark pools must match objective, grain, and window. A REACH Campaign should be compared
with other cost-active REACH Campaigns in the same window, not with WEB_CONVERSIONS Campaigns
or Ad-level rows. When an account contains multiple objectives, render account benchmark by
objective bucket instead of mixing CPA/CVR/CPM conclusions across objectives.
Account overview requests are mandatory benchmark requests. If the user asks how the account performed without naming one object, first pull an account-level same-grain list for the analysis window, summarize account totals and objective buckets, then run a benchmark in the same response. Default to Campaign grain and split mixed objectives into objective buckets. If the user did not choose a target object, auto-select the highest-spend cost-active Campaign within the dominant objective bucket as the primary benchmark target and clearly state the selected linked Campaign name before the benchmark blocks. Do not ask whether to benchmark before producing at least one benchmark result. Only offer additional target choices after the mandatory benchmark is shown. For prompts like "看看我账号表现如何最近" or "账号最近一周表现怎么样", do not output a standalone account recap first and wait for the user to ask "你怎么没说 benchmark". The same response must include the literal benchmark labels above.
Benchmark comparisons must also be like-for-like by entity grain. Campaign analysis compares against cost-active Campaigns, Ad Group analysis compares against cost-active Ad Groups, and Ad analysis compares against cost-active Ads. Do not compare Campaign performance to an Ad-level benchmark.
Candidate discovery requests, such as "find high CVR creatives", are allowed only when they stay
connected to benchmark logic. Treat sorting as candidate generation, not the final conclusion.
After finding top candidates, run same-objective, same-grain account benchmark for each candidate
or for the shortlisted set. Creative/material requests use Ad grain for the main benchmark and use
ad_id as the benchmark and aggregation key. Do not aggregate by ad_name; names can repeat and
are not stable identifiers. If Smart+ material reporting is available, use it only as optional
enrichment to explain material-level contribution, not as a fourth user-facing benchmark grain.
Default candidate discovery should surface both
Winners and Draggers from the same benchmark pool: who looks meaningfully above account waterline,
and who is spending or receiving traffic while dragging the objective-specific efficiency below
account waterline.
Read references/account-benchmark-design.md when modifying definitions, explaining
methodology, or resolving ambiguity.
Read references/mcp-report-contract.md before changing report parameters, supported metrics,
pagination, or raw-response handling.
Read references/interactive-intake.md when the user request is vague, missing account/object
context, or phrased as a general "is my ad doing well?" question.
Read references/metric-catalog.md before translating user-facing metric names into API metrics.
Read references/objective-metric-profiles.md before selecting metrics, comparison pools, or
conclusion language.
Read references/analysis-output.md before writing narrative conclusions, insights, or
recommendations.
Read references/candidate-discovery.md before ranking or recommending high-CVR, low-CPA,
high-scale, or "good creative" candidates.
Read references/smart-plus-material-benchmark.md before using optional Smart+ material
enrichment.
Run execution preflight.
tt-ads MCP server and required tools are available in the current host before
promising a real data run. If they are not available, say the environment is blocked and do
not fabricate report data.invalid_token, unauthorized, or
AuthRequired, ask the user to reauthenticate (codex mcp login tt-ads in Codex) and stop
before pulling reports.start_date > end_date,
and avoid current-day data by default because it may be incomplete.references/metric-catalog.md and the selected objective
profile. Do not request unsupported commerce or revenue metrics on the BASIC report path;
explain the limitation and continue with supported metrics if that still answers the user's
question.Run interactive intake.
references/interactive-intake.md.Resolve advertiser context.
advertiser_id if the user provides one.tt4b-skill-kit, prefer the shared semantics in
../shared/stage0-bc-advertiser.md for listing BCs, listing advertiser assets, and reusing
the selected bc_id / advertiser_id.auth_advertiser_get returns empty, do not fail immediately. Ask for or use a
user-provided advertiser_id and continue to the report path.advertiser_id, try that advertiser directly.Resolve objective and metric profile.
objective_type before choosing benchmark metrics and conclusion language.objective_type directly when available.REACH rows into conversion CPA/CVR benchmark or conversion rows into awareness CPM
benchmark.Pull the analysis report.
report_integrated_get.references/mcp-report-contract.md.report_type=BASICservice_type=AUCTIONdata_level=AUCTION_CAMPAIGN unless user asks for Ad Group or Ad.dimensions=["campaign_id"] or ["campaign_id","stat_time_day"] depending the user view.references/objective-metric-profiles.md and translated through
references/metric-catalog.md.Pull the benchmark report.
report_integrated_get.page starting at 1; some responses may include total_number
and total_metrics while returning an empty list when pagination is omitted.objective_type, data_level, dimensions, and window to the analysis report:
data_level=AUCTION_CAMPAIGN, dimensions=["campaign_id"]data_level=AUCTION_ADGROUP, dimensions=["adgroup_id"]data_level=AUCTION_AD, dimensions=["ad_id"]page_size is at most 1000.E201_NO_BENCHMARK_SAMPLE.
Do not finish with only WoW trend or account summary.If doing creative/ad candidate discovery, classify candidates before concluding.
UPGRADED_SMART_PLUS and
smart_plus_material_report_overview_run is available, optionally use it as enrichment:
aggregate by main_material_id, derive CPA/CVR/CTR locally from summed numerators, and use
that only to explain material contribution behind the Ad-level result.Update_* tools or any status mutation tool
from this benchmark skill.6a. Build Ads Manager object links when rendering user-visible object names.
campaign_id as campaign_ids in /i18n/manage/campaign.ad_ids in
/i18n/manage/adgroup: prefer adgroup_id, and fall back to ad_id only when the MCP
exposes the AdGroup identity under that field name. Do not substitute a child Ad ID from an
Ad-level row.creative_id,
virtual_creative_id, smart_plus_ad_id, main_material_id, and material IDs are context
only, not user-visible link filter values.Persist raw responses.
advertiser_info_get, analysis report_integrated_get, and benchmark
report_integrated_get responses as soon as they succeed when the host supports files or run
artifacts.Compute locally.
scripts/compute-account-benchmark.mjs when report JSON is available and Node.js is
available. If Node.js is unavailable, use scripts/compute-account-benchmark.py with the
same raw analysis JSON, benchmark JSON, CLI flags, output language, object-link flags, and
metric list. The two scripts are the same deterministic compute contract.summary.md, pass --language zh for Chinese or mostly Chinese
prompts and --language en for English prompts. If the host writes summary.md without the
script, follow the same language policy manually.--advertiser-id, --link-kind,
--start-date, and --end-date. Ads Manager links use the bundled script's stable
navigate_from=campaignList template with columns, explicit st/et, and filters[0]
parameters; do not hand-build a shortened URL with top-level campaign_ids, ad_ids, or
creative_ids. Do not add relative_time, sort_state, or sort_order. For Creative / Ad
output, the compute scripts must keep object names as plain text even when --advertiser-id
and --link-kind creative / smart_plus_creative are passed.--analysis-id when the analysis report contains multiple rows.spend, impressions, clicks,
conversion, video view counts, and engagement counts.report_ad_benchmark_get as the primary path; it is optional only.references/account-benchmark-design.md; do not ask an LLM to invent percentile math.Render the result.
summary.md artifact.summary.md is saved, verify its heading and main narrative language
before final response. For Chinese or Chinese-dominant prompts, rewrite the file if it still
uses English-only headings such as Hot Ad Group Benchmark or Key Reads.广告主, 窗口, 粒度, 目标, 基准池, 样本, and 主基准对象; do not use English labels
such as Advertiser, Window, Grain, Objective, Pool, or Primary benchmark target.summary.md: include winners, draggers, scale leader, efficiency
candidate, key risk/caveat, a compact benchmark table, and scope appendix.结论先说, then show same-grain Winners and Draggers
as tables, then the metric table and next steps, then benchmark scope. The intro for Winners
should state that these objects sit in a strong/high account tier; the intro for Draggers
should state that these objects sit in a weak/low account tier or materially pull the
objective bucket down.ID column, no legacy
{name} ({id}) object labels, no generic Object / 对象 table header, Campaign / AdGroup
object names are Markdown links when their link fields are available, and Ad / Creative grain
object names are plain text. Campaign / AdGroup link URLs must include columns= and the
encoded or raw filters[0][field] / filters[0][in_field_values][0] parameters; reject
top-level campaign_ids=..., ad_ids=..., or creative_ids=.... AdGroup links must use the
AdGroup identity even though the URL parameter is named ad_ids. Ad-grain output must not
include /manage/creative, creative_ids, or virtual_creative_id links.$2,222.13. Label median values
with the statistic used, usually 中位数 / Median.references/analysis-output.md; repeat it in the narrative if it affects the conclusion.下一步建议 / Next steps,
following references/analysis-output.md. Under next steps, use positive decision-support
wording such as "以下建议基于报表数据,执行前请结合实时投放状态确认。"tt-ads is unavailable in the current host and list the
expected tools: advertiser_info_get and report_integrated_get.codex mcp login tt-ads.advertiser_id and continue if the user provides one.advertiser_id is known, try report pulls directly before declaring the
workflow blocked.code, message, and request id, then ask for
an accessible advertiser or account identity.E201_NO_BENCHMARK_SAMPLE and offer a longer benchmark window or
coarser entity grain.code, message, and request id.The skill can start from rough natural language, but it must resolve these before pulling reports:
| Field | Required? | How to get it |
|---|---|---|
| Advertiser/account | Required | Use explicit advertiser_id, resolved account context, or ask the user |
| Target grain | Required | Campaign, Ad Group, or Ad. Infer only when user explicitly says the type |
| Target object | Required | Object ID, object name/selection criteria, or user approval to pick one cost-active object |
| Analysis window | Optional | Default to last 7 complete account-local days |
| Benchmark window | Optional | Default to the same number of complete days as the analysis window |
| Metrics | Optional | Default to the resolved objective profile; use CPC, CPA, CTR, CVR, CPM, conversions, and spend only when objective is unknown |
If the user provides only an object ID without its type, ask whether it is Campaign, Ad Group, or Ad. Do not infer type from numeric ID shape.
The account benchmark calculation is local, not an MCP/API-side benchmark and not LLM reasoning. The MCP server supplies raw report rows. The skill or host then runs deterministic local logic to:
In the local web testbench, this happens in the Node server through
scripts/compute-account-benchmark.mjs. In a pure Claude/Codex skill invocation, use the bundled
Node script when Node.js is available, or scripts/compute-account-benchmark.py when Python is the
available local runtime. Both scripts must accept the same report JSON and produce the same
benchmark semantics. Only fall back to the reference rules manually if neither local runtime can run.
The MCP server is the shared execution substrate. Claude, Codex, or another host may expose the
same MCP tool names differently, but the skill should continue to describe the desired tt-ads
tool contract rather than a host-specific function name.
Host adapters may handle:
~/.claude/skills vs ~/.codex/skills)Host adapters must not change:
tools
Use only when the user explicitly asks to stage, commit, push, and open a GitHub pull request in one flow using the GitHub CLI (`gh`).
development
Use this skill any time a spreadsheet file is the primary input or output. This means any task where the user wants to: open, read, edit, or fix an existing .xlsx, .xlsm, .csv, or .tsv file (e.g., adding columns, computing formulas, formatting, charting, cleaning messy data); create a new spreadsheet from scratch or from other data sources; or convert between tabular file formats. Trigger especially when the user references a spreadsheet file by name or path — even casually (like "the xlsx in my downloads") — and wants something done to it or produced from it. Also trigger for cleaning or restructuring messy tabular data files (malformed rows, misplaced headers, junk data) into proper spreadsheets. The deliverable must be a spreadsheet file. Do NOT trigger when the primary deliverable is a Word document, HTML report, standalone Python script, database pipeline, or Google Sheets API integration, even if tabular data is involved.
development
Use this skill when turning messy workout information into clear logs, comparing user-provided sessions, surfacing trends or likely PRs, and suggesting realistic next-session steps.
tools
Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.