01Run it
Replace the <placeholders> with your own values, or use the builder below.
p202 report losers02What you get
Captured from the real binary, run against a demo store with 30 days of traffic. Switch tabs to see the same run as JSON, the shape scripts and agents parse.
$ p202 report losers --breakdown country --period last30 id name Clicks Conversions Cost Profit Avg CPC bucket reason assisted_conversions first_touch_roi -- ------- ------ ----------- ------ ------- ------- ------ ---------------------------- -------------------- --------------- 5 Germany 84 0 111.60 -111.60 1.3286 CUT spent $111.60, 0 conversions 0 -100
$ p202 report losers --breakdown country --period last30 --json { "data": [ { "assisted_conversions": 0, "avg_cpc": 1.3286, "bucket": "CUT", "first_touch_roi": -100, "id": 5, "name": "Germany", "reason": "spent $111.60, 0 conversions", "total_clicks": 84, "total_cost": 111.6, "total_leads": 0, "total_net": -111.6 } ] }
03Build your command
Pick values and the command line writes itself, quoted and ready to paste.
p202 report losersSet flags below; the command updates as you type.
04Flags
27 flags, plus the global flags every command takes.
| Flag | What it does |
|---|---|
| --aff-campaign-idstring | Filter by INTERNAL campaign id (from campaign list), not the public id in tracking URLs |
| --aff-network-idstring | Filter by affiliate network ID |
| --breakdown, -bstring · default keyword | Dimension to triage: campaign, aff_network, ppc_account, ppc_network, landing_page, keyword, country, city, region, browser, platform, device, isp, text_ad, ip, referer, referer_url, device_type, c1, c2, c3, c4, utm_source, utm_medium, utm_campaign, utm_term, utm_content, rotator, rotator_rule (aliases: geo=country, lp=landing_page, network=aff_network, offer=campaign, referrer=referer, referrer_url=referer_url, rule=rotator_rule, source=ppc_account)campaignaff_networkppc_accountppc_networklanding_pagekeywordcountrycityregionbrowserplatformdeviceisptext_adiprefererreferer_urldevice_typec1c2c3c4utm_sourceutm_mediumutm_campaignutm_termutm_contentrotatorrotator_rulegeo → countrylp → landing_pagenetwork → aff_networkoffer → campaignreferrer → refererreferrer_url → referer_urlrule → rotator_rulesource → ppc_account |
| --browser-idstring | Filter by browser ID (the id of a --breakdown browser row) |
| --country-idstring | Filter by country ID |
| --device-typestring | Filter by device type ID: 1 Desktop, 2 Mobile, 3 Tablet, 4 Bot (the ids of --breakdown device_type rows) |
| --first-touch-modelstring | Attribution model id for the starter check (default: the first active First touch model) |
| --ipstring | Only clicks from this one IP address, IPv4 or IPv6 |
| --isp-idstring | Filter by ISP/carrier ID (the id of a --breakdown isp row) |
| --keywordstring | Only clicks whose keyword contains this text (case-insensitive) |
| --landing-page-idstring | Filter by landing page ID |
| --max-cpcfloat64 | Break-even CPC target (else payout × each row's CVR, from --payout or the campaign) |
| --method-of-promotionstring | Only direct-link clicks or only landing-page clicks: directlink, landingpagedirectlinklandingpage |
| --min-assistsint64 · default 1 | A CUT row with at least this many assisted sales comes back as TEST (0 turns the assists rule off) |
| --min-clicksfloat64 · default 1 | Ignore rows with fewer than N clicks (significance floor) |
| --no-attribution-checkbool | List classic last-click losers only, without the first-touch starter check |
| --payoutfloat64 | Revenue per conversion, e.g. your average order value: each row's break-even CPC is this × its conversion rate, and its profit (total_net) and first-touch ROI value each sale at this. Unlike --aff-campaign-id it doesn't filter the report, so the attribution check still runs |
| --period, -pstring | Period: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltimetodayyesterdaylast7last14last30last90thismonthlastmonththisyearlastyearalltime |
| --platform-idstring | Filter by platform (OS) ID (the id of a --breakdown platform row) |
| --ppc-account-idstring | Filter by PPC account ID |
| --ppc-network-idstring | Filter by PPC network ID, or none for the clicks with no traffic source |
| --refererstring | Only clicks whose referring URL contains this text (case-insensitive) |
| --region-idstring | Filter by region ID (the id of a --breakdown region row) |
| --showstring | Which clicks count (default all): all, real, filtered, filtered_bot, leads; real = not filtered, filtered_bot = filtered as bots, leads = convertedallrealfilteredfiltered_botleads |
| --text-ad-idstring | Filter by text ad ID |
| --time-fromstring | Start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z) |
| --time-tostring | End, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset |
05How it works
Rows to CUT from the classic (last-click) report: zero conversions with spend, or CPC above break-even. Break-even is --max-cpc, or a payout × the row's own conversion rate: --payout (your revenue per conversion) or the payout of --aff-campaign-id. Without one, only zero-conversion spend is CUT: a row that sells at a loss is WATCH and isn't listed. --payout doesn't filter the report, so the attribution check below still runs, and it values every sale the command reports at that payout: total_net, and the first-touch ROI below. The classic report counts a converted click once however many sales it had, so the check also reads the Last touch model, whose credits count each row's sales, and values the rows it reads per sale (a stderr note says when it can't).
Each CUT row is then checked against the attribution report for the same dimension and range. A row that starts sales comes back as TEST, with its first-touch ROI and assists: it pays for itself as a first click (first-touch ROI 0% or better), or it had a click in at least --min-assists sales (default 1) that another row closed. Cutting it on last-click numbers would likely lose those sales, so test a cut on part of its traffic first.
The check runs for campaign, ppc_account (traffic source), landing_page, keyword and country. ROI comes from the first active First touch model (or --first-touch-model); without one, rows are checked on assists only. It needs an attribution:read key; when it can't run, the command still lists the classic losers and says why on stderr. A filter other than the breakdown itself (an entity id, --keyword, --show, --ip, ...) turns the check off: the attribution report is account-wide. On a server that can't page the attribution report, rows past the first page are marked attribution_checked: false. --no-attribution-check turns it off.
06For agents
Running this from an agent
- Read the same facts as JSON:
p202 commands report losers --json. - With
AI_AGENT,CLAUDECODEor another agent variable set, output is compact JSON and errors arrive on stderr as a JSON envelope with ahint. - Exit codes: 0 ok, 1 bad input, 2 auth, 3 network, 4 server error, 5 partial failure.
{
"path": "p202 report losers",
"use": "losers",
"short": "Rows to CUT: over-bid keywords/geos and zero-conversion spend; rows that start sales come back as TEST",
"long": "Rows to CUT from the classic (last-click) report: zero conversions with spend, or CPC above break-even.\nBreak-even is --max-cpc, or a payout × the row's own conversion rate: --payout (your revenue per conversion) or\nthe payout of --aff-campaign-id. Without one, only zero-conversion spend is CUT: a row that sells at a loss is\nWATCH and isn't listed. --payout doesn't filter the report, so the attribution check below still runs, and it\nvalues every sale the command reports at that payout: total_net, and the first-touch ROI below. The classic report\ncounts a converted click once however many sales it had, so the check also reads the Last touch model, whose\ncredits count each row's sales, and values the rows it reads per sale (a stderr note says when it can't).\n\nEach CUT row is then checked against the attribution report for the same dimension and range. A row that\nstarts sales comes back as TEST, with its first-touch ROI and assists: it pays for itself as a first click\n(first-touch ROI 0% or better), or it had a click in at least --min-assists sales (default 1) that another row\nclosed. Cutting it on last-click numbers would likely lose those sales, so test a cut on part of its traffic first.\n\nThe check runs for campaign, ppc_account (traffic source), landing_page, keyword and country. ROI comes from the\nfirst active First touch model (or --first-touch-model); without one, rows are checked on assists only. It needs\nan attribution:read key; when it can't run, the command still lists the classic losers and says why on stderr.\nA filter other than the breakdown itself (an entity id, --keyword, --show, --ip, ...) turns the check off: the\nattribution report is account-wide.\nOn a server that can't page the attribution report, rows past the first page are marked attribution_checked:\nfalse. --no-attribution-check turns it off.",
"runnable": true,
"flags": [
{
"name": "aff-campaign-id",
"type": "string",
"default": "",
"usage": "Filter by INTERNAL campaign id (from `campaign list`), not the public id in tracking URLs",
"required": false
},
{
"name": "aff-network-id",
"type": "string",
"default": "",
"usage": "Filter by affiliate network ID",
"required": false
},
{
"name": "breakdown",
"shorthand": "b",
"type": "string",
"default": "keyword",
"usage": "Dimension to triage: campaign, aff_network, ppc_account, ppc_network, landing_page, keyword, country, city, region, browser, platform, device, isp, text_ad, ip, referer, referer_url, device_type, c1, c2, c3, c4, utm_source, utm_medium, utm_campaign, utm_term, utm_content, rotator, rotator_rule (aliases: geo=country, lp=landing_page, network=aff_network, offer=campaign, referrer=referer, referrer_url=referer_url, rule=rotator_rule, source=ppc_account)",
"allowed_values": [
"campaign",
"aff_network",
"ppc_account",
"ppc_network",
"landing_page",
"keyword",
"country",
"city",
"region",
"browser",
"platform",
"device",
"isp",
"text_ad",
"ip",
"referer",
"referer_url",
"device_type",
"c1",
"c2",
"c3",
"c4",
"utm_source",
"utm_medium",
"utm_campaign",
"utm_term",
"utm_content",
"rotator",
"rotator_rule"
],
"value_aliases": {
"geo": "country",
"lp": "landing_page",
"network": "aff_network",
"offer": "campaign",
"referrer": "referer",
"referrer_url": "referer_url",
"rule": "rotator_rule",
"source": "ppc_account"
},
"required": false
},
{
"name": "browser-id",
"type": "string",
"default": "",
"usage": "Filter by browser ID (the id of a `--breakdown browser` row)",
"required": false
},
{
"name": "country-id",
"type": "string",
"default": "",
"usage": "Filter by country ID",
"required": false
},
{
"name": "device-type",
"type": "string",
"default": "",
"usage": "Filter by device type ID: 1 Desktop, 2 Mobile, 3 Tablet, 4 Bot (the ids of `--breakdown device_type` rows)",
"required": false
},
{
"name": "first-touch-model",
"type": "string",
"default": "",
"usage": "Attribution model id for the starter check (default: the first active First touch model)",
"required": false
},
{
"name": "ip",
"type": "string",
"default": "",
"usage": "Only clicks from this one IP address, IPv4 or IPv6",
"required": false
},
{
"name": "isp-id",
"type": "string",
"default": "",
"usage": "Filter by ISP/carrier ID (the id of a `--breakdown isp` row)",
"required": false
},
{
"name": "keyword",
"type": "string",
"default": "",
"usage": "Only clicks whose keyword contains this text (case-insensitive)",
"required": false
},
{
"name": "landing-page-id",
"type": "string",
"default": "",
"usage": "Filter by landing page ID",
"required": false
},
{
"name": "max-cpc",
"type": "float64",
"default": "0",
"usage": "Break-even CPC target (else payout × each row's CVR, from --payout or the campaign)",
"required": false
},
{
"name": "method-of-promotion",
"type": "string",
"default": "",
"usage": "Only direct-link clicks or only landing-page clicks: directlink, landingpage",
"allowed_values": [
"directlink",
"landingpage"
],
"required": false
},
{
"name": "min-assists",
"type": "int64",
"default": "1",
"usage": "A CUT row with at least this many assisted sales comes back as TEST (0 turns the assists rule off)",
"required": false
},
{
"name": "min-clicks",
"type": "float64",
"default": "1",
"usage": "Ignore rows with fewer than N clicks (significance floor)",
"required": false
},
{
"name": "no-attribution-check",
"type": "bool",
"default": "false",
"usage": "List classic last-click losers only, without the first-touch starter check",
"required": false
},
{
"name": "payout",
"type": "float64",
"default": "0",
"usage": "Revenue per conversion, e.g. your average order value: each row's break-even CPC is this × its conversion rate, and its profit (total_net) and first-touch ROI value each sale at this. Unlike --aff-campaign-id it doesn't filter the report, so the attribution check still runs",
"required": false
},
{
"name": "period",
"shorthand": "p",
"type": "string",
"default": "",
"usage": "Period: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
"allowed_values": [
"today",
"yesterday",
"last7",
"last14",
"last30",
"last90",
"thismonth",
"lastmonth",
"thisyear",
"lastyear",
"alltime"
],
"required": false
},
{
"name": "platform-id",
"type": "string",
"default": "",
"usage": "Filter by platform (OS) ID (the id of a `--breakdown platform` row)",
"required": false
},
{
"name": "ppc-account-id",
"type": "string",
"default": "",
"usage": "Filter by PPC account ID",
"required": false
},
{
"name": "ppc-network-id",
"type": "string",
"default": "",
"usage": "Filter by PPC network ID, or none for the clicks with no traffic source",
"required": false
},
{
"name": "referer",
"type": "string",
"default": "",
"usage": "Only clicks whose referring URL contains this text (case-insensitive)",
"required": false
},
{
"name": "region-id",
"type": "string",
"default": "",
"usage": "Filter by region ID (the id of a `--breakdown region` row)",
"required": false
},
{
"name": "show",
"type": "string",
"default": "",
"usage": "Which clicks count (default all): all, real, filtered, filtered_bot, leads; real = not filtered, filtered_bot = filtered as bots, leads = converted",
"allowed_values": [
"all",
"real",
"filtered",
"filtered_bot",
"leads"
],
"required": false
},
{
"name": "text-ad-id",
"type": "string",
"default": "",
"usage": "Filter by text ad ID",
"required": false
},
{
"name": "time-from",
"type": "string",
"default": "",
"usage": "Start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
"required": false
},
{
"name": "time-to",
"type": "string",
"default": "",
"usage": "End, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
"required": false
}
]
}