Report weekly Google Ads return on ad spend for every campaign

Every Monday: last week's Google Ads conversion value against cost for the whole account and each campaign, set against your target ROAS.

Runs
Mondays at 9:00
Posts
Stat tile

From your apps to your board

How the skill works: your agent reads value and cost from Google Ads; google ads customer id, target roas from What you tell it, mondays at 9:00, and gives you roas and the report in the chat.

Reads

  • Google AdsValue and cost
  • What you tell itGoogle Ads customer ID, Target ROAS
reads
Your agentClaude Code, Codex, Cursor or GeminiMondays at 9:00
posts

You get

  • ROASA stat tile on your board, with its trend
  • The report in the chatEvery run, with or without Briefkin

What you get

  • Account ROAS last week as a multiple, with an 8-week trend.
  • Conversion value and cost, with the change on the week before.
  • By campaign: cost, value, ROAS and target.
  • Below target and under 1x campaigns, with the spend at stake.
  • With a margin, the break-even ROAS (1 divided by the margin).

The card on the right is a sample. Yours shows your own numbers and updates in place every run.

What lands on your board

Acme StoreROAS4.2x+8% vs previous period, bettervs last report
Conv. value$41,412+9.0% vs previous period
Cost$9,860+1.0% vs previous period, worse
Below target2 campaigns
An example with made-up numbers. Your agent posts your real ones.

What it does

For a store, cost per conversion is half the picture. A $40 conversion is great on a $300 order and a loss on a $25 one. Return on ad spend puts the value back in, and it is usually the first number a founder asks about. Google Ads shows it as "Conv. value / cost", a column many accounts never add to their view.

The agent works it out every Monday for the account and each campaign, against the target ROAS you bid to. You see which campaigns pay back, which only look busy, and whether the account is moving the right way.

How it works

  1. 1Pull value and cost

    Run GAQL on campaign with campaign.name, metrics.cost_micros, metrics.conversions_value and metrics.conversions, WHERE segments.date DURING LAST_7_DAYS. ROAS is conversions_value divided by cost in currency units.

  2. 2Get each target

    Read campaign.maximize_conversion_value.target_roas or campaign.target_roas.target_roas, a ratio where 4.0 means 400%. Campaigns without a target use your account target.

  3. 3

    3Compare with the week before

    Repeat for the previous 7 days. Flag campaigns more than 20% under target, and any campaign that spent over $500 at a ROAS under 1, which loses money before margins.

  4. 4

    4Post the tile

    Account ROAS is the headline as a multiple (4.2x) with 8 weeks of history. The glance shows value, cost and the campaigns under target; the card opens to the campaign table and the break-even line when you gave a margin.

  5. Post it to the board

    With BRIEFKIN_TOKEN set, the agent sends the result as one card that updates in place every run. Without it, you get the report in the chat.

Install and run it

Pick your agent, where the data comes from and how to schedule it; the commands below follow.

Agent
Data
Schedule
  1. Install the skill

    One command. It puts the SKILL.md in ~/.claude/skills and in ~/.agents/skills, which Codex, Cursor, Gemini CLI, Copilot CLI and OpenCode read too.

    shellcurl -fsSL https://briefkin.dev/skills/google-ads-roas-report/install | sh
  2. Run it

    Ask Claude Code:

    promptRun the google-ads-roas-report skill

    Or paste the prompt instead of installing:

    promptFrom my Google Ads account (Google Ads API, GAQL on campaign), give me return on ad spend for the last 7 days: metrics.conversions_value divided by metrics.cost_micros / 1,000,000, for the account and each enabled campaign, with the change against the 7 days before. Read each campaign's target ROAS from campaign.maximize_conversion_value.target_roas or campaign.target_roas.target_roas, and use [target]x where none is set. Flag campaigns more than 20% under target, and any that spent over $500 below 1x. My gross margin is [margin]%, so also show the break-even ROAS.
  3. Put it on a schedule

    Mondays at 9:00, from cron on any machine where Claude Code is signed in:

    crontab0 9 * * 1 claude -p "Run the google-ads-roas-report skill"

    Add it with crontab -e. A laptop asleep at that time runs it when it wakes if you use launchd or Task Scheduler instead; GitHub Actions works for the API route.

  4. Send it to your board

    Connect Briefkin once with curl -fsSL https://briefkin.dev/install | sh and every run lands on your board as a stat tile. How setup works

View the SKILL.mdRaw file
SKILL.md---
name: google-ads-roas-report
description: "Every Monday: last week's Google Ads conversion value against cost for the whole account and each campaign, set against your target ROAS. Use when the user asks for this, or when it runs on a schedule."
---

# Google Ads ROAS report

Every Monday: last week's Google Ads conversion value against cost for the whole account and each campaign, set against your target ROAS.

For a store, cost per conversion is half the picture. A $40 conversion is great on a $300 order and a loss on a $25 one. Return on ad spend puts the value back in, and it is usually the first number a founder asks about. Google Ads shows it as "Conv. value / cost", a column many accounts never add to their view.

The agent works it out every Monday for the account and each campaign, against the target ROAS you bid to. You see which campaigns pay back, which only look busy, and whether the account is moving the right way.

## Two ways to get the data

Use the API or MCP route when you have an MCP server, a CLI or an API token for the app. Otherwise, if you can drive a browser the user is signed in to (Claude in Chrome, a Playwright or Chrome DevTools MCP server), use the browser route. Say which one you used.

## Route A: API or MCP server

### What you need

- Read access to the Google Ads account, with conversion actions that carry a value (purchases with order value, or leads with a set value).
- Google Ads API access through a Google Cloud project with API access and OAuth credentials (developer tokens were retired in September 2026), or the official Google Ads MCP server, which is read-only.
- Your target ROAS, and your gross margin if you want the break-even ROAS in the report.

If something is missing, say what and stop; do not invent numbers.

### Steps

1. **Pull value and cost** (Google Ads): Run GAQL on `campaign` with `campaign.name`, `metrics.cost_micros`, `metrics.conversions_value` and `metrics.conversions`, `WHERE segments.date DURING LAST_7_DAYS`. ROAS is `conversions_value` divided by cost in currency units.
2. **Get each target** (Google Ads): Read `campaign.maximize_conversion_value.target_roas` or `campaign.target_roas.target_roas`, a ratio where 4.0 means 400%. Campaigns without a target use your account target.
3. **Compare with the week before**: Repeat for the previous 7 days. Flag campaigns more than 20% under target, and any campaign that spent over $500 at a ROAS under 1, which loses money before margins.
4. **Post the tile**: Account ROAS is the headline as a multiple (4.2x) with 8 weeks of history. The glance shows value, cost and the campaigns under target; the card opens to the campaign table and the break-even line when you gave a margin.

## Route B: the browser

### What you need

- Signed in to Google Ads with at least Read-only access to an account whose conversion actions carry a value.

If something is missing, say what and stop; do not invent numbers.

### Steps

Start at https://ads.google.com/aw/campaigns. The user is signed in already; never type passwords or codes, and ask if a sign-in page appears.

1. **Set the last 7 days with a comparison**: Open `https://ads.google.com/aw/campaigns`, pick the client account if asked, choose `Last 7 days` in the date picker and turn on `Compare` with `Previous period`.
2. **Add the value columns**: Under Columns, Modify columns, add `Cost`, `Conv. value`, `Conv. value / cost` and `Target ROAS` (Attributes), and filter to enabled campaigns. `Conv. value / cost` is ROAS as a ratio: 4.2 means 4.2x.
3. **Read the account and each campaign**: Account ROAS comes from the Total row. For each campaign note cost, conversion value, the ratio, its target ROAS and the change in the comparison row; campaigns with no target use your account target.
4. **Flag the losers**: Flag campaigns more than 20% under target, and any that spent over $500 at a ratio under 1. If you know the gross margin, break-even ROAS is 1 divided by the margin.

Note: The Conv. value / cost column uses primary conversion actions and the account's attribution model, so it will not match store revenue. Google Ads reports value in the account currency, converted at the time of the conversion.

## The report

- **Account ROAS** last week as a multiple, with an 8-week trend.
- **Conversion value and cost**, with the change on the week before.
- **By campaign**: cost, value, ROAS and target.
- **Below target** and **under 1x** campaigns, with the spend at stake.
- With a margin, the break-even ROAS (1 divided by the margin).

## Post it to Briefkin

When `BRIEFKIN_TOKEN` is set, or `~/.config/briefkin/env` exists (the installer from https://briefkin.dev/docs writes it), also send the result to the user's Briefkin board as one card. Keep the `item_key` the same on every run so the card updates in place, use a new `event_id` per run, and put today's real numbers in place of the example ones. If the request fails, say so once and carry on.

```bash
[ -n "${BRIEFKIN_TOKEN:-}" ] || . ~/.config/briefkin/env
curl -sS -X POST "${BRIEFKIN_URL:-https://briefkin.dev}/v1/events" \
  -H "authorization: Bearer $BRIEFKIN_TOKEN" \
  -H "content-type: application/json" \
  -d @- <<'JSON'
{
  "v": 1,
  "event_id": "google-ads-roas-report/<date of this run, e.g. 2026-10-16>",
  "item_key": "google-ads-roas-report",
  "project": "Acme Store",
  "source": "Google Ads ROAS report skill",
  "kind": "metric",
  "title": "ROAS at 4.2x, the best in 8 weeks",
  "metric": {
    "label": "ROAS",
    "value": 4.2,
    "unit": "x",
    "better": "higher",
    "period_start": "<start of the period, ISO 8601>",
    "period_end": "<end of the period, ISO 8601>"
  },
  "glance": {
    "type": "Grid",
    "props": {
      "columns": 3
    },
    "children": [
      {
        "type": "Stat",
        "props": {
          "label": "Conv. value",
          "value": 41412,
          "prefix": "$",
          "delta": 9
        }
      },
      {
        "type": "Stat",
        "props": {
          "label": "Cost",
          "value": 9860,
          "prefix": "$",
          "delta": 1
        }
      },
      {
        "type": "Stat",
        "props": {
          "label": "Below target",
          "value": "2 campaigns",
          "tone": "warn"
        }
      }
    ]
  },
  "widget": [
    {
      "type": "Table",
      "props": {
        "columns": [
          "Campaign",
          "Cost",
          "Conv. value",
          "ROAS",
          "Target"
        ],
        "align": [
          "left",
          "right",
          "right",
          "right",
          "right"
        ],
        "rows": [
          [
            "Brand Search",
            "$1,240",
            "$11,780",
            "9.5x",
            "6.0x"
          ],
          [
            "Performance Max",
            "$4,980",
            "$21,912",
            "4.4x",
            "4.0x"
          ],
          [
            "Non-brand Search",
            "$2,860",
            "$6,292",
            "2.2x",
            "3.5x"
          ],
          [
            "Display Remarketing",
            "$780",
            "$1,428",
            "1.8x",
            "3.0x"
          ],
          [
            "Account",
            "$9,860",
            "$41,412",
            "4.2x",
            "4.0x"
          ]
        ]
      }
    },
    {
      "type": "Callout",
      "props": {
        "text": "Non-brand Search spent $2,860 at 2.2x against a 3.5x target. At a 40% margin break-even is 2.5x, so it is losing money.",
        "tone": "bad"
      }
    }
  ],
  "size": "md"
}
JSON
```

Widgets come from the Briefkin catalog (https://briefkin.dev/v1/catalog). Without a token, just give the user the report.

Set `period_start` and `period_end` to the window the number covers: the tile names it from them ("Last 7 days", "Today", "This month"). For a count right now (open items, a balance), send `"period_label": ""` so no period shows; for another name, send it as `period_label` (at most 24 characters).

## Run it on a schedule

Suggested: Mondays at 9:00 (`0 9 * * 1`). From cron, with the agent signed in on that machine:

```bash
0 9 * * 1 claude -p "Run the google-ads-roas-report skill"
# Codex: codex exec, Gemini CLI: gemini -p, Copilot CLI: copilot -p, OpenCode: opencode run
```

Or use the agent's own scheduler (Claude Code routines, Codex automations, Claude or ChatGPT scheduled tasks): https://briefkin.dev/skills/google-ads-roas-report#schedule

Source: https://briefkin.dev/skills/google-ads-roas-report

What your agent needs

  • Read access to the Google Ads account, with conversion actions that carry a value (purchases with order value, or leads with a set value).

  • Google Ads API access through a Google Cloud project with API access and OAuth credentials (developer tokens were retired in September 2026), or the official Google Ads MCP server, which is read-only.

  • Your target ROAS, and your gross margin if you want the break-even ROAS in the report.

Connecting Google Ads

  1. Google Ads MCP server, Google's open-source, read-only server (google-ads-mcp, source). Run it locally with pipx run --spec git+https://github.com/googleads/google-ads-mcp.git google-ads-mcp, or deploy it to Cloud Run for remote clients. Its tools are list_accessible_customers, search for GAQL and get_resource_metadata (docs).
  2. Google Ads API with OAuth. Enable the Google Ads API in a Google Cloud project, sign in with Application Default Credentials (gcloud auth application-default login with the adwords scope) or an OAuth client, and set GOOGLE_PROJECT_ID. Add GOOGLE_ADS_LOGIN_CUSTOMER_ID when you reach client accounts through a manager account, and write customer IDs without dashes.

The adwords scope can't be narrowed, so sign in as a Google Ads user with Read only access; the MCP server has no write tools either way.

Questions

Why does this differ from revenue in Shopify or GA4?

Google Ads credits a sale to the ad click within its own attribution window and model, on the date of the click. Your store counts orders on the day they were placed, and GA4 splits credit its own way. The three rarely agree: use this report to compare campaigns, and your store for revenue.

Which conversions count toward the value?

metrics.conversions_value includes only primary conversion actions, the ones in the Conversions column. Secondary actions such as add-to-cart sit in metrics.all_conversions_value and are left out, so ROAS is not inflated.

Do I need Briefkin to use the Google Ads ROAS report skill?

No. The skill runs with your own agent and gives you the report in the chat. With a Briefkin token set, each run also posts it to your board as a stat tile, so you can glance at it instead of asking again.

Which agents can run it?

Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot CLI, OpenCode, Windsurf and Amp all read SKILL.md files. The install command puts it in ~/.claude/skills and ~/.agents/skills, where they look. ChatGPT, the Claude app and Grok take the prompt instead. Pick your agent under "Install and run it" and the commands change to match.

Can it work without an API or MCP server, from my browser?

Yes. Switch the data source to "Your browser" and the steps change to the Google Ads pages themselves: the agent opens ads.google.com/aw/campaigns in a browser you are signed in to and reads the numbers off the page. Claude Code, Codex, Cursor, Claude app and ChatGPT can drive a browser out of the box; Gemini CLI, Copilot CLI and OpenCode need a Playwright or Chrome DevTools MCP server first. It is slower than the API and needs you signed in, so it suits a report you run by hand or from a scheduler on your own computer.

Watch roas on your board, run after run

Skills are free to use with any agent. Briefkin is where their results land: one board for every report, number and question your agents send, with a ping when something needs you.

Free during the open beta. No card.