ds@mcpanalytics.aiEmail your data and your question and get an answer about your own data, with the method shown.Email your data and question. Get an answer.

Campaign Performance Reporting for Agencies

By MCP Analytics Team | Published , updated

Pulling data, formatting spreadsheets and calculating metrics by hand takes time that could go to judgment. This analysis takes a single CSV export from an ad platform and produces a campaign scorecard with ROAS rankings, funnel diagnostics, and budget recommendations.

Worked Example: Which Campaigns Meet a Spend and Return Rule?

Question: Which of three made-up campaigns meet a spend and return rule?

Inputs: Made-up rows typed by hand. Each row has a campaign name, ad spend, revenue and a count of conversions. Nothing is simulated or random, so every run gives the same result.

Method: ROAS (return on ad spend) is revenue divided by spend. CPA (cost per acquisition) is spend divided by conversions. The rule is: Scale at a ROAS of 2.0 or more, Monitor from 1.0 up to below 2.0, and Pause below 1.0. The 2.0 and 1.0 cut points are this example's rule, not a standard.

Result: North (2.50x) meets the Scale rule, East (1.25x) meets the Monitor rule, and West (0.80x) meets the Pause rule. The rows were typed so that one campaign lands in each band, which is why the output shows one of each. It is a demonstration of the rule, not a finding about real campaigns.

Limit: ROAS sets revenue against ad spend. It does not show profit, because the rows have no margin, fees or other costs.

import csv
import io

# Made-up rows typed by hand. Nothing is random, so every run is the same.
source = """campaign,spend,revenue,conversions
North,1000,2500,25
West,800,640,16
East,1200,1500,10
"""
rows = list(csv.DictReader(io.StringIO(source)))
for row in rows:
    row["spend"] = float(row["spend"])
    row["revenue"] = float(row["revenue"])
    row["conversions"] = int(row["conversions"])
    row["roas"] = row["revenue"] / row["spend"]
    row["cpa"] = row["spend"] / row["conversions"]
    if row["roas"] >= 2:
        row["recommendation"] = "Scale"
    elif row["roas"] >= 1:
        row["recommendation"] = "Monitor"
    else:
        row["recommendation"] = "Pause"

print("Made-up rows typed by hand")
print("Input rows: 3; fields: campaign, spend, revenue, conversions")
print("Method: ROAS = revenue / spend; CPA = spend / conversions")
print("Rule: ROAS >= 2.0 Scale; >= 1.0 and < 2.0 Monitor; < 1.0 Pause")
print("campaign | spend | revenue | conversions | ROAS | CPA | recommendation")
for row in sorted(rows, key=lambda item: item["roas"], reverse=True):
    print(
        f"{row['campaign']} | ${row['spend']:.2f} | ${row['revenue']:.2f} | "
        f"{row['conversions']} | {row['roas']:.2f}x | ${row['cpa']:.2f} | "
        f"{row['recommendation']}"
    )

Printed output of that script:

Made-up rows typed by hand
Input rows: 3; fields: campaign, spend, revenue, conversions
Method: ROAS = revenue / spend; CPA = spend / conversions
Rule: ROAS >= 2.0 Scale; >= 1.0 and < 2.0 Monitor; < 1.0 Pause
campaign | spend | revenue | conversions | ROAS | CPA | recommendation
North | $1000.00 | $2500.00 | 25 | 2.50x | $40.00 | Scale
East | $1200.00 | $1500.00 | 10 | 1.25x | $120.00 | Monitor
West | $800.00 | $640.00 | 16 | 0.80x | $50.00 | Pause

The Reporting Problem Agencies Know Too Well

Every month, the same cycle repeats. Export CSV from Google Ads. Export from Meta Ads Manager. Maybe another from TikTok or LinkedIn. Open Excel. Calculate ROAS manually (revenue divided by spend). Build charts. Copy into a Google Slides deck. Repeat for every client. Some agencies use tools to automate the data pull, but the analysis and visualization are still manual. And the output is mostly descriptive: it states a ROAS for each campaign. That tells the client what happened. It does not tell them what to do.

To test whether your own outcome differs between groups, and which groups differ, try the free group comparison tool.

Reports that include prescriptive recommendations ("pause Campaign D, reallocate budget to Campaign A") give clients something to act on, instead of only descriptive metrics.

What This Analysis Produces

The report may show the parts below, each answering a specific question:

From Numbers to Recommendations

A scorecard that ends in a recommendation gives the client something to act on, as the worked example does: a rule turns each campaign's ROAS into Scale, Monitor or Pause. Time not spent on manual reporting could go to deeper analysis, such as a stats test to see whether a gap between search and social could be due to chance. That test needs a sound study plan and like-for-like outcome data.

What Data You Need

A CSV export of campaign performance data from any ad platform. Required columns:

Optional columns for richer analysis:

Export this from Facebook Ads Manager, Google Ads, your analytics platform, or even a spreadsheet where you track spend manually. Each row should represent one campaign's performance for a time period. More campaigns and more time periods give the comparison more to work with.

Common Pitfalls the Report Helps You Avoid

Optimizing for ROAS Without Considering Scale

Campaign A has 8x ROAS on $5,000 spend ($40,000 revenue). Campaign B has 3x ROAS on $100,000 spend ($300,000 revenue). Killing Campaign B because its ROAS is "only" 3x would cost $300,000 in revenue. A rule based on ROAS alone would miss this, so look at revenue contribution as well.

Ignoring Funnel Position

Brand search campaigns often show high ROAS. Those customers were already looking for you. Upper-funnel campaigns like display or awareness often show low ROAS on a last-click basis because they introduce new customers who convert through a different channel later. The funnel efficiency chart makes this visible.

Over-Scaling Winners

The spend vs. revenue scatter plot reveals diminishing returns. If a campaign's ROAS drops as spend increases, there is an inflection point beyond which additional budget yields diminishing returns. The chart can help you avoid the mistake of "this campaign has great ROAS, let's 5x the budget" only to watch efficiency collapse as the audience saturates.

The Monthly Workflow

Here is one way a paid media agency could fit this into a monthly cycle. At month-end, the account manager exports campaign performance from each platform (Google Ads, Meta, TikTok) and combines them into a single CSV per client. They upload to MCP Analytics and run the ROAS efficiency analysis. They get a campaign scorecard with tier recommendations.

The account manager reviews the automated recommendations and adds strategic commentary: context the analysis cannot know, like "Campaign B is a brand awareness campaign so low ROAS is expected and acceptable" or "Client is launching a new product line in Q2, so prospecting spend will increase." They share the interactive report with the client or download the PDF for the monthly retainer deliverable. The client can drill into individual campaigns in the interactive view. The prescriptive recommendations (scale this, pause that, reallocate here) give the client meeting a clear agenda instead of a walkthrough of flat metrics.

When to Use Something Else

Your turn

Bring your own data and the question you actually need answered.

MCP AnalyticsData science by email Send us your data and your question, and we will reply. ds@mcpanalytics.ai

Running an agency? See client reporting & analysis for agencies, commission once, re-run per client.

Working on this for your business? See the marketing analytics tools.