Skip to main content
The built-in reports (daily check, bleeders, winners, fatigue) cover 90% of ad management. But when you need to dig deeper — audience demographics, device performance, placement analysis — you need custom reports.

Basic Structure

Every custom report has three components:
  1. Level — Campaign, adset, or ad
  2. Fields — Metrics to include (spend, CTR, CPC, etc.)
  3. Breakdowns — How to slice the data (age, gender, device, etc.)

Command Syntax

./scripts/meta-ads.sh custom \
  --level [campaign|adset|ad] \
  --fields "field1,field2,field3" \
  --breakdowns "breakdown1,breakdown2" \
  --preset [date_range]

The Level Parameter

Controls which object type you’re analyzing.
Use when: You want account-level or campaign-level performance.
./scripts/meta-ads.sh custom \
  --level campaign \
  --fields "campaign_name,spend,impressions,ctr,cpc" \
  --preset last_30d
Example Output:
Campaign Name               | Spend    | Impressions | CTR   | CPC
----------------------------+----------+-------------+-------+------
Spring Launch 2026          | $4,234   | 892,441     | 2.1%  | $1.24
Retargeting — Site Visitors | $1,856   | 234,892     | 3.4%  | $0.89
Prospecting — Lookalikes    | $2,991   | 678,234     | 1.8%  | $1.45

Available Fields

Specify which metrics to include in your report.

Performance Metrics

FieldDescription
spendTotal amount spent
impressionsNumber of times ad was shown
clicksNumber of clicks
ctrClick-through rate (clicks/impressions)
cpcCost per click
cpmCost per 1,000 impressions
frequencyAverage times each person saw the ad
reachNumber of unique people who saw the ad

Conversion Metrics

FieldDescription
conversionsTotal conversions (based on optimization goal)
cost_per_conversionSpend / conversions
conversion_rateConversions / clicks
purchasesPurchase events (if tracking)
purchase_valueTotal purchase value
roasReturn on ad spend (purchase_value / spend)

Engagement Metrics

FieldDescription
post_engagementReactions, comments, shares
video_views3-second video views
video_avg_watch_timeAverage watch time
link_clicksClicks to destination URL

Identity Fields

FieldDescription
campaign_nameCampaign name
adset_nameAd set name
ad_nameAd name
campaign_idCampaign ID
adset_idAd set ID
ad_idAd ID
Not all fields are available at all levels. For example, ad_name only works with --level ad.

Breakdowns

Slice your data by demographic, placement, or device.

Demographic Breakdowns

Performance by age range.
./scripts/meta-ads.sh custom \
  --level ad \
  --fields "ad_name,spend,ctr,conversions" \
  --breakdowns "age" \
  --preset last_7d
Example Output:
Ad Name              | Age   | Spend  | CTR   | Conversions
---------------------+-------+--------+-------+-------------
Before/After Grid    | 18-24 | $45    | 1.8%  | 2
Before/After Grid    | 25-34 | $189   | 3.4%  | 14
Before/After Grid    | 35-44 | $142   | 3.1%  | 10
Before/After Grid    | 45-54 | $47    | 2.2%  | 2
Insights:
  • 25-34 is the highest performing age range (3.4% CTR, 14 conversions)
  • Consider shifting budget to 25-44 age range

Placement Breakdowns

Facebook vs Instagram performance.
./scripts/meta-ads.sh custom \
  --level ad \
  --fields "ad_name,spend,ctr,cpc" \
  --breakdowns "platform_position" \
  --preset last_7d
Example Output:
Ad Name              | Platform        | Spend  | CTR   | CPC
---------------------+-----------------+--------+-------+------
Before/After Grid    | FB Feed         | $234   | 2.8%  | $1.12
Before/After Grid    | FB Stories      | $67    | 1.9%  | $1.45
Before/After Grid    | IG Feed         | $189   | 3.4%  | $0.89
Before/After Grid    | IG Stories      | $112   | 3.1%  | $0.95
Insights:
  • Instagram placements outperform Facebook (3.4% vs 2.8% CTR)
  • Instagram has lower CPC (0.89vs0.89 vs 1.12)
  • Consider shifting budget to IG placements

Time Breakdowns

# Daily performance
./scripts/meta-ads.sh custom \
  --level campaign \
  --fields "campaign_name,spend,ctr" \
  --time-increment 1 \
  --preset last_7d
Example Output:
Campaign Name         | Date       | Spend  | CTR
----------------------+------------+--------+------
Spring Launch 2026    | 2026-02-26 | $423   | 2.8%
Spring Launch 2026    | 2026-02-27 | $456   | 2.6%
Spring Launch 2026    | 2026-02-28 | $489   | 2.3%
Spring Launch 2026    | 2026-03-01 | $512   | 2.0%  ⬇️ Declining
Use --time-increment 1 for daily breakdowns. This is how the fatigue check works under the hood.

Real-World Examples

Example 1: Find Best Performing Demographics

Goal: Identify which age/gender combo drives the most conversions.
./scripts/meta-ads.sh custom \
  --level ad \
  --fields "ad_name,spend,conversions,cost_per_conversion" \
  --breakdowns "age,gender" \
  --preset last_30d
How to use the output:
  1. Sort by cost_per_conversion (lowest = best)
  2. Identify winning segments (e.g., Women 25-34)
  3. Create dedicated ad sets targeting those segments
  4. Exclude poor performers from broad targeting

Example 2: Instagram vs Facebook Performance

Goal: Decide where to allocate budget.
./scripts/meta-ads.sh custom \
  --level campaign \
  --fields "campaign_name,spend,ctr,cpc,roas" \
  --breakdowns "platform_position" \
  --preset last_30d
How to use the output:
  1. Compare CTR, CPC, and ROAS across platforms
  2. If Instagram outperforms, shift budget there
  3. Or create platform-specific creatives optimized for each

Example 3: Track Creative Fatigue Over Time

Goal: See day-by-day CTR decline for a specific ad.
./scripts/meta-ads.sh custom \
  --level ad \
  --fields "ad_name,spend,ctr,frequency,cpc" \
  --time-increment 1 \
  --preset last_14d
How to use the output:
  1. Plot CTR over time
  2. Identify when decline started
  3. Correlate with frequency — does fatigue start at frequency > 3?
  4. Use this to predict when future creatives will fatigue

Example 4: Audience Comparison

Goal: Which audience (adset) is most efficient?
./scripts/meta-ads.sh custom \
  --level adset \
  --fields "adset_name,spend,conversions,cost_per_conversion,frequency" \
  --preset last_7d
How to use the output:
  1. Sort by cost_per_conversion
  2. Check frequency — audiences with frequency > 3 are saturated
  3. Scale winners (low CPA, frequency < 2.5)
  4. Pause or refresh fatigued audiences (high frequency, rising CPA)

Advanced: Combining Reports

Chain multiple custom reports to build a full analysis.

Workflow: Optimize an Underperforming Campaign

1

Campaign-level overview

./scripts/meta-ads.sh custom \
  --level campaign \
  --fields "campaign_name,spend,ctr,cpc,roas" \
  --preset last_30d
Identify the underperforming campaign (low ROAS, high CPC).
2

Ad-level breakdown

./scripts/meta-ads.sh custom \
  --level ad \
  --fields "ad_name,spend,ctr,conversions" \
  --preset last_7d
Find which specific ads are dragging performance down.
3

Demographic breakdown

./scripts/meta-ads.sh custom \
  --level ad \
  --fields "ad_name,spend,cost_per_conversion" \
  --breakdowns "age,gender" \
  --preset last_7d
Identify if certain demographics are causing the high CPA.
4

Placement breakdown

./scripts/meta-ads.sh custom \
  --level ad \
  --fields "ad_name,spend,cpc" \
  --breakdowns "platform_position" \
  --preset last_7d
Check if specific placements (e.g., Audience Network) are inefficient.
5

Take action

Based on findings:
  • Pause underperforming demographics
  • Exclude inefficient placements
  • Pause bleeders
  • Scale winners

Tips for Custom Reports

Requesting too many fields slows down the API and makes output hard to read.Good:
--fields "ad_name,spend,ctr,conversions"
Too much:
--fields "ad_name,spend,impressions,clicks,ctr,cpc,cpm,frequency,reach,conversions,cost_per_conversion,roas"
Request only the metrics you need for the specific analysis.
Each breakdown multiplies the number of rows in the output. Combining 3+ breakdowns can create overwhelming data.Good for exploration:
--breakdowns "age,gender"
Too granular (hard to interpret):
--breakdowns "age,gender,platform_position,device_platform"
Analysis TypeRecommended Preset
Daily checkslast_7d
Fatigue detectionlast_14d with --time-increment 1
Monthly reportinglast_30d
Audience testinglast_7d (enough signal without noise)
Pipe output to a CSV for analysis in Excel/Sheets:
./scripts/meta-ads.sh custom \
  --level ad \
  --fields "ad_name,spend,ctr,conversions" \
  --breakdowns "age,gender" \
  --format csv > performance.csv

Common Questions

Built-in reports (bleeders, winners, fatigue) are pre-configured for specific use cases and include analysis + recommendations.Custom reports are raw data queries — you get the metrics you ask for, but no interpretation.Use built-in reports for daily workflow. Use custom reports for deep dives and one-off analysis.
Not directly in the command. Instead:
  1. Run the full report
  2. Export to CSV
  3. Filter in Excel/Sheets/Python
Or use the raw social-cli command with filtering:
social marketing insights ad --fields "ad_name,spend" --filtering "[{'field':'spend','operator':'GREATER_THAN','value':100}]"
Possible reasons:
  1. Metric not available at that level: E.g., ad_name only works with --level ad
  2. Insufficient data: If the time range is too short, some metrics won’t populate
  3. Conversion tracking not set up: Metrics like purchases require proper event tracking

Next Steps

Reports Overview

See all available reports and when to use each

Fatigue Detection

Learn how to use time-increment reports to catch fatigue

Build docs developers (and LLMs) love