p202 report losers

Rows to CUT: over-bid keywords/geos and zero-conversion spend; rows that start sales come back as TEST

All commands

01Run it

Replace the <placeholders> with your own values, or use the builder below.

p202 report losers

02What 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
$ 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
Real output · p202 1.9.77 · demo dataexit 0

03Build your command

Pick values and the command line writes itself, quoted and ready to paste.

p202 report losers

Set flags below; the command updates as you type.

04Flags

27 flags, plus the global flags every command takes.

FlagWhat it does
--aff-campaign-idstringFilter by INTERNAL campaign id (from campaign list), not the public id in tracking URLs
--aff-network-idstringFilter by affiliate network ID
--breakdown, -bstring · default keywordDimension 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-idstringFilter by browser ID (the id of a --breakdown browser row)
--country-idstringFilter by country ID
--device-typestringFilter by device type ID: 1 Desktop, 2 Mobile, 3 Tablet, 4 Bot (the ids of --breakdown device_type rows)
--first-touch-modelstringAttribution model id for the starter check (default: the first active First touch model)
--ipstringOnly clicks from this one IP address, IPv4 or IPv6
--isp-idstringFilter by ISP/carrier ID (the id of a --breakdown isp row)
--keywordstringOnly clicks whose keyword contains this text (case-insensitive)
--landing-page-idstringFilter by landing page ID
--max-cpcfloat64Break-even CPC target (else payout × each row's CVR, from --payout or the campaign)
--method-of-promotionstringOnly direct-link clicks or only landing-page clicks: directlink, landingpage
directlinklandingpage
--min-assistsint64 · default 1A CUT row with at least this many assisted sales comes back as TEST (0 turns the assists rule off)
--min-clicksfloat64 · default 1Ignore rows with fewer than N clicks (significance floor)
--no-attribution-checkboolList classic last-click losers only, without the first-touch starter check
--payoutfloat64Revenue 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, -pstringPeriod: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime
todayyesterdaylast7last14last30last90thismonthlastmonththisyearlastyearalltime
--platform-idstringFilter by platform (OS) ID (the id of a --breakdown platform row)
--ppc-account-idstringFilter by PPC account ID
--ppc-network-idstringFilter by PPC network ID, or none for the clicks with no traffic source
--refererstringOnly clicks whose referring URL contains this text (case-insensitive)
--region-idstringFilter by region ID (the id of a --breakdown region row)
--showstringWhich clicks count (default all): all, real, filtered, filtered_bot, leads; real = not filtered, filtered_bot = filtered as bots, leads = converted
allrealfilteredfiltered_botleads
--text-ad-idstringFilter by text ad ID
--time-fromstringStart: 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-tostringEnd, 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, CLAUDECODE or another agent variable set, output is compact JSON and errors arrive on stderr as a JSON envelope with a hint.
  • Exit codes: 0 ok, 1 bad input, 2 auth, 3 network, 4 server error, 5 partial failure.
p202 commands report losers --json
{
  "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
    }
  ]
}