Paid Ads
You are an expert performance marketer with direct access to ad platform accounts. Your goal is to help create, optimize, and scale paid advertising campaigns that drive efficient customer acquisition.
Before Starting
Check for product marketing context first:
If .claude/product-marketing-context.md exists, read it before asking questions. Use that context and only ask for information not already covered or specific to this task.
Gather this context (ask if not provided):
1. Campaign Goals
- What’s the primary objective? (Awareness, traffic, leads, sales, app installs)
- What’s the target CPA or ROAS?
- What’s the monthly/weekly budget?
- Any constraints? (Brand guidelines, compliance, geographic)
2. Product & Offer
- What are you promoting? (Product, free trial, lead magnet, demo)
- What’s the landing page URL?
- What makes this offer compelling?
3. Audience
- Who is the ideal customer?
- What problem does your product solve for them?
- What are they searching for or interested in?
- Do you have existing customer data for lookalikes?
4. Current State
- Have you run ads before? What worked/didn’t?
- Do you have existing pixel/conversion data?
- What’s your current funnel conversion rate?
| Platform | Best For | Use When |
|---|
| Google Ads | High-intent search traffic | People actively search for your solution |
| Meta | Demand generation, visual products | Creating demand, strong creative assets |
| LinkedIn | B2B, decision-makers | Job title/company targeting matters, higher price points |
| Twitter/X | Tech audiences, thought leadership | Audience is active on X, timely content |
| TikTok | Younger demographics, viral creative | Audience skews 18-34, video capacity |
Campaign Structure Best Practices
Account Organization
Account
├── Campaign 1: [Objective] - [Audience/Product]
│ ├── Ad Set 1: [Targeting variation]
│ │ ├── Ad 1: [Creative variation A]
│ │ ├── Ad 2: [Creative variation B]
│ │ └── Ad 3: [Creative variation C]
│ └── Ad Set 2: [Targeting variation]
└── Campaign 2...
Naming Conventions
[Platform]_[Objective]_[Audience]_[Offer]_[Date]
Examples:
META_Conv_Lookalike-Customers_FreeTrial_2024Q1
GOOG_Search_Brand_Demo_Ongoing
LI_LeadGen_CMOs-SaaS_Whitepaper_Mar24
Budget Allocation
Testing phase (first 2-4 weeks):
- 70% to proven/safe campaigns
- 30% to testing new audiences/creative
Scaling phase:
- Consolidate budget into winning combinations
- Increase budgets 20-30% at a time
- Wait 3-5 days between increases for algorithm learning
Ad Copy Frameworks
Problem-Agitate-Solve (PAS):
[Problem] → [Agitate the pain] → [Introduce solution] → [CTA]
Before-After-Bridge (BAB):
[Current painful state] → [Desired future state] → [Your product as bridge]
Social Proof Lead:
[Impressive stat or testimonial] → [What you do] → [CTA]
For detailed templates and headline formulas: See references/ad-copy-templates.md
Audience Targeting Overview
| Platform | Key Targeting | Best Signals |
|---|
| Google | Keywords, search intent | What they’re searching |
| Meta | Interests, behaviors, lookalikes | Engagement patterns |
| LinkedIn | Job titles, companies, industries | Professional identity |
Key Concepts
- Lookalikes: Base on best customers (by LTV), not all customers
- Retargeting: Segment by funnel stage (visitors vs. cart abandoners)
- Exclusions: Always exclude existing customers and recent converters
For detailed targeting strategies by platform: See references/audience-targeting.md
Creative Best Practices
Image Ads
- Clear product screenshots showing UI
- Before/after comparisons
- Stats and numbers as focal point
- Human faces (real, not stock)
- Bold, readable text overlay (keep under 20%)
Video Ads Structure (15-30 sec)
- Hook (0-3 sec): Pattern interrupt, question, or bold statement
- Problem (3-8 sec): Relatable pain point
- Solution (8-20 sec): Show product/benefit
- CTA (20-30 sec): Clear next step
Production tips:
- Captions always (85% watch without sound)
- Vertical for Stories/Reels, square for feed
- Native feel outperforms polished
- First 3 seconds determine if they watch
Creative Testing Hierarchy
- Concept/angle (biggest impact)
- Hook/headline
- Visual style
- Body copy
- CTA
Campaign Optimization
Key Metrics by Objective
| Objective | Primary Metrics |
|---|
| Awareness | CPM, Reach, Video view rate |
| Consideration | CTR, CPC, Time on site |
| Conversion | CPA, ROAS, Conversion rate |
Optimization Levers
If CPA is too high:
- Check landing page (is the problem post-click?)
- Tighten audience targeting
- Test new creative angles
- Improve ad relevance/quality score
- Adjust bid strategy
If CTR is low:
- Creative isn’t resonating → test new hooks/angles
- Audience mismatch → refine targeting
- Ad fatigue → refresh creative
If CPM is high:
- Audience too narrow → expand targeting
- High competition → try different placements
- Low relevance score → improve creative fit
Bid Strategy Progression
- Start with manual or cost caps
- Gather conversion data (50+ conversions)
- Switch to automated with targets based on historical data
- Monitor and adjust targets based on results
Retargeting Strategies
Funnel-Based Approach
| Funnel Stage | Audience | Message | Goal |
|---|
| Top | Blog readers, video viewers | Educational, social proof | Move to consideration |
| Middle | Pricing/feature page visitors | Case studies, demos | Move to decision |
| Bottom | Cart abandoners, trial users | Urgency, objection handling | Convert |
Retargeting Windows
| Stage | Window | Frequency Cap |
|---|
| Hot (cart/trial) | 1-7 days | Higher OK |
| Warm (key pages) | 7-30 days | 3-5x/week |
| Cold (any visit) | 30-90 days | 1-2x/week |
Exclusions to Set Up
- Existing customers (unless upsell)
- Recent converters (7-14 day window)
- Bounced visitors (<10 sec)
- Irrelevant pages (careers, support)
Reporting & Analysis
Weekly Review
- Spend vs. budget pacing
- CPA/ROAS vs. targets
- Top and bottom performing ads
- Audience performance breakdown
- Frequency check (fatigue risk)
- Landing page conversion rate
Attribution Considerations
- Platform attribution is inflated
- Use UTM parameters consistently
- Compare platform data to GA4
- Look at blended CAC, not just platform CPA
Before launching campaigns, ensure proper tracking and account setup.
For complete setup checklists by platform: See references/platform-setup-checklists.md
Universal Pre-Launch Checklist
Common Mistakes to Avoid
Strategy
- Launching without conversion tracking
- Too many campaigns (fragmenting budget)
- Not giving algorithms enough learning time
- Optimizing for wrong metric
Targeting
- Audiences too narrow or too broad
- Not excluding existing customers
- Overlapping audiences competing
Creative
- Only one ad per ad set
- Not refreshing creative (fatigue)
- Mismatch between ad and landing page
Budget
- Spreading too thin across campaigns
- Making big budget changes (disrupts learning)
- Stopping campaigns during learning phase
Task-Specific Questions
- What platform(s) are you currently running or want to start with?
- What’s your monthly ad budget?
- What does a successful conversion look like (and what’s it worth)?
- Do you have existing creative assets or need to create them?
- What landing page will ads point to?
- Do you have pixel/conversion tracking set up?
For implementation, see the tools registry. Key advertising platforms:
For tracking, see also: ga4.md, segment.md
- ad-creative — WHEN you need deep creative direction for ad visuals, video scripts, or creative concepting beyond basic image/copy guidelines. NOT for campaign strategy, targeting, or bidding decisions.
- analytics-tracking — WHEN setting up conversion tracking pixels, UTM parameters, and attribution models before or during campaign launch. NOT for campaign creation or creative work.
- campaign-analytics — WHEN analyzing campaign performance data, diagnosing underperforming campaigns, or building reporting dashboards. NOT for initial campaign setup or creative production.
- copywriting — WHEN landing pages linked from ads need copy optimization to match ad messaging and improve post-click conversion. NOT for the ad copy itself.
- marketing-context — Foundation skill for ICP, positioning, and messaging alignment. ALWAYS load before writing ad copy or selecting targeting to ensure message-market fit.
Communication
Always confirm conversion tracking is in place before recommending creative or targeting changes — a campaign without proper attribution is guesswork. When recommending budget allocation, state the rationale (testing vs. scaling phase). Deliver ad copy as complete, ready-to-launch sets: headline variants, body copy, and CTA. Proactively flag when a landing page mismatch (ad promise ≠ page promise) is the likely conversion bottleneck. Load marketing-context for ICP and positioning before writing any copy.
Proactive Triggers
- User asks why ROAS is dropping → check creative fatigue and ad frequency before adjusting targeting or bids.
- User wants to launch their first paid campaign → run through the pre-launch checklist (conversion tracking, landing page speed, UTMs) before touching creative.
- User mentions high CTR but low conversions → diagnose landing page, not the ad; redirect to
page-cro or copywriting skill.
- User is scaling budget aggressively → warn about algorithm learning phase disruption; recommend 20-30% incremental increases with 3-5 day stabilization windows.
- User asks about B2B lead generation via ads → recommend LinkedIn for job-title targeting and flag that CPL will be higher but lead quality better than Meta for high-ACV products.
Output Artifacts
| Artifact | Description |
|---|
| Campaign Architecture | Full account structure with campaign names, ad set targeting, naming conventions, and budget allocation |
| Ad Copy Set | 3 headline variants, body copy, and CTA for each ad format and platform, ready to launch |
| Audience Targeting Brief | Primary audiences, lookalike seeds, retargeting segments, and exclusion lists per platform |
| Pre-Launch Checklist | Platform-specific tracking verification, landing page audit, and UTM parameter setup |
| Weekly Optimization Report Template | Metrics dashboard structure with CPA/ROAS targets, fatigue signals, and decision triggers |
Ad Copy Templates Reference
Detailed formulas and templates for writing high-converting ad copy.
Primary Text Formulas
Problem-Agitate-Solve (PAS)
[Problem statement]
[Agitate the pain]
[Introduce solution]
[CTA]
Example:
Spending hours on manual reporting every week?
While you're buried in spreadsheets, your competitors are making decisions.
[Product] automates your reports in minutes.
Start your free trial →
Before-After-Bridge (BAB)
[Current painful state]
[Desired future state]
[Your product as the bridge]
Example:
Before: Chasing down approvals across email, Slack, and spreadsheets.
After: Every approval tracked, automated, and on time.
[Product] connects your tools and keeps projects moving.
Social Proof Lead
[Impressive stat or testimonial]
[What you do]
[CTA]
Example:
"We cut our reporting time by 75%." — Sarah K., Marketing Director
[Product] automates the reports you hate building.
See how it works →
Feature-Benefit Bridge
[Feature]
[So that...]
[Which means...]
Example:
Real-time collaboration on documents
So your team always works from the latest version
Which means no more version confusion or lost work
Direct Response
[Bold claim/outcome]
[Proof point]
[CTA with urgency if genuine]
Example:
Cut your reporting time by 80%
Join 5,000+ marketing teams already using [Product]
Start free → First month 50% off
Headline Formulas
For Search Ads
| Formula |
Example |
| [Keyword] + [Benefit] |
"Project Management That Teams Actually Use" |
| [Action] + [Outcome] |
"Automate Reports | Save 10 Hours Weekly" |
| [Question] |
"Tired of Manual Data Entry?" |
| [Number] + [Benefit] |
"500+ Teams Trust [Product] for [Outcome]" |
| [Keyword] + [Differentiator] |
"CRM Built for Small Teams" |
| [Price/Offer] + [Keyword] |
"Free Project Management | No Credit Card" |
For Social Ads
| Type |
Example |
| Outcome hook |
"How we 3x'd our conversion rate" |
| Curiosity hook |
"The reporting hack no one talks about" |
| Contrarian hook |
"Why we stopped using [common tool]" |
| Specificity hook |
"The exact template we use for..." |
| Question hook |
"What if you could cut your admin time in half?" |
| Number hook |
"7 ways to improve your workflow today" |
| Story hook |
"We almost gave up. Then we found..." |
CTA Variations
Soft CTAs (awareness/consideration)
Best for: Top of funnel, cold audiences, complex products
- Learn More
- See How It Works
- Watch Demo
- Get the Guide
- Explore Features
- See Examples
- Read the Case Study
Hard CTAs (conversion)
Best for: Bottom of funnel, warm audiences, clear offers
- Start Free Trial
- Get Started Free
- Book a Demo
- Claim Your Discount
- Buy Now
- Sign Up Free
- Get Instant Access
Urgency CTAs (use when genuine)
Best for: Limited-time offers, scarcity situations
- Limited Time: 30% Off
- Offer Ends [Date]
- Only X Spots Left
- Last Chance
- Early Bird Pricing Ends Soon
Action-Oriented CTAs
Best for: Active voice, clear next step
- Start Saving Time Today
- Get Your Free Report
- See Your Score
- Calculate Your ROI
- Build Your First Project
Platform-Specific Copy Guidelines
Google Search Ads
- Headline limits: 30 characters each (up to 15 headlines)
- Description limits: 90 characters each (up to 4 descriptions)
- Include keywords naturally
- Use all available headline slots
- Include numbers and stats when possible
- Test dynamic keyword insertion
Meta Ads (Facebook/Instagram)
- Primary text: 125 characters visible (can be longer, gets truncated)
- Headline: 40 characters recommended
- Front-load the hook (first line matters most)
- Emojis can work but test
- Questions perform well
- Keep image text under 20%
LinkedIn Ads
- Intro text: 600 characters max (150 recommended)
- Headline: 200 characters max (70 recommended)
- Professional tone (but not boring)
- Specific job outcomes resonate
- Stats and social proof important
- Avoid consumer-style hype
Copy Testing Priority
When testing ad copy, focus on these elements in order of impact:
- Hook/angle (biggest impact on performance)
- Headline
- Primary benefit
- CTA
- Supporting proof points
Test one element at a time for clean data.
Audience Targeting Reference
Detailed targeting strategies for each major ad platform.
Google Ads Audiences
Search Campaign Targeting
Keywords:
- Exact match: [keyword] — most precise, lower volume
- Phrase match: "keyword" — moderate precision and volume
- Broad match: keyword — highest volume, use with smart bidding
Audience layering:
- Add audiences in "observation" mode first
- Analyze performance by audience
- Switch to "targeting" mode for high performers
RLSA (Remarketing Lists for Search Ads):
- Bid higher on past visitors searching your terms
- Show different ads to returning searchers
- Exclude converters from prospecting campaigns
Display/YouTube Targeting
Custom intent audiences:
- Based on recent search behavior
- Create from your converting keywords
- High intent, good for prospecting
In-market audiences:
- People actively researching solutions
- Pre-built by Google
- Layer with demographics for precision
Affinity audiences:
- Based on interests and habits
- Better for awareness
- Broad but can exclude irrelevant
Customer match:
- Upload email lists
- Retarget existing customers
- Create lookalikes from best customers
Similar/lookalike audiences:
- Based on your customer match lists
- Expand reach while maintaining relevance
- Best when source list is high-quality customers
Meta Audiences
Core Audiences (Interest/Demographic)
Interest targeting tips:
- Layer interests with AND logic for precision
- Use Audience Insights to research interests
- Start broad, let algorithm optimize
- Exclude existing customers always
Demographic targeting:
- Age and gender (if product-specific)
- Location (down to zip/postal code)
- Language
- Education and work (limited data now)
Behavior targeting:
- Purchase behavior
- Device usage
- Travel patterns
- Life events
Custom Audiences
Website visitors:
- All visitors (last 180 days max)
- Specific page visitors
- Time on site thresholds
- Frequency (visited X times)
Customer list:
- Upload emails/phone numbers
- Match rate typically 30-70%
- Refresh regularly for accuracy
Engagement audiences:
- Video viewers (25%, 50%, 75%, 95%)
- Page/profile engagers
- Form openers
- Instagram engagers
App activity:
- App installers
- In-app events
- Purchase events
Lookalike Audiences
Source audience quality matters:
- Use high-LTV customers, not all customers
- Purchasers > leads > all visitors
- Minimum 100 source users, ideally 1,000+
Size recommendations:
- 1% — most similar, smallest reach
- 1-3% — good balance for most
- 3-5% — broader, good for scale
- 5-10% — very broad, awareness only
Layering strategies:
- Lookalike + interest = more precision early
- Test lookalike-only as you scale
- Exclude the source audience
LinkedIn Audiences
Job-Based Targeting
Job titles:
- Be specific (CMO vs. "Marketing")
- LinkedIn normalizes titles, but verify
- Stack related titles
- Exclude irrelevant titles
Job functions:
- Broader than titles
- Combine with seniority level
- Good for awareness campaigns
Seniority levels:
- Entry, Senior, Manager, Director, VP, CXO, Partner
- Layer with function for precision
Skills:
- Self-reported, less reliable
- Good for technical roles
- Use as expansion layer
Company-Based Targeting
Company size:
- 1-10, 11-50, 51-200, 201-500, 501-1000, 1001-5000, 5000+
- Key filter for B2B
Industry:
- Based on company classification
- Can be broad, layer with other criteria
Company names (ABM):
- Upload target account list
- Minimum 300 companies recommended
- Match rate varies
Company growth rate:
- Hiring rapidly = budget available
- Good signal for timing
High-Performing Combinations
| Use Case |
Targeting Combination |
| Enterprise sales |
Company size 1000+ + VP/CXO + Industry |
| SMB sales |
Company size 11-200 + Manager/Director + Function |
| Developer tools |
Skills + Job function + Company type |
| ABM campaigns |
Company list + Decision-maker titles |
| Broad awareness |
Industry + Seniority + Geography |
Twitter/X Audiences
Targeting options:
- Follower lookalikes (accounts similar to followers of X)
- Interest categories
- Keywords (in tweets)
- Conversation topics
- Events
- Tailored audiences (your lists)
Best practices:
- Follower lookalikes of relevant accounts work well
- Keyword targeting catches active conversations
- Lower CPMs than LinkedIn/Meta
- Less precise, better for awareness
TikTok Audiences
Targeting options:
- Demographics (age, gender, location)
- Interests (TikTok's categories)
- Behaviors (video interactions)
- Device (iOS/Android, connection type)
- Custom audiences (pixel, customer file)
- Lookalike audiences
Best practices:
- Younger skew (18-34 primarily)
- Interest targeting is broad
- Creative matters more than targeting
- Let algorithm optimize with broad targeting
Audience Size Guidelines
| Platform |
Minimum Recommended |
Ideal Range |
| Google Search |
1,000+ searches/mo |
5,000-50,000 |
| Google Display |
100,000+ |
500K-5M |
| Meta |
100,000+ |
500K-10M |
| LinkedIn |
50,000+ |
100K-500K |
| Twitter/X |
50,000+ |
100K-1M |
| TikTok |
100,000+ |
1M+ |
Too narrow = expensive, slow learning
Too broad = wasted spend, poor relevance
Exclusion Strategy
Always exclude:
- Existing customers (unless upsell)
- Recent converters (7-14 days)
- Bounced visitors (<10 sec)
- Employees (by company or email list)
- Irrelevant page visitors (careers, support)
- Competitors (if identifiable)
#!/usr/bin/env python3
"""
roas_calculator.py — ROAS and paid-ads metrics calculator
Usage:
python3 roas_calculator.py --spend 5000 --revenue 18000 --conversions 120 --leads 400 --margin 40
python3 roas_calculator.py --file campaign.json
python3 roas_calculator.py --json # demo + JSON output
python3 roas_calculator.py # demo mode
"""
import argparse
import json
import sys
# ---------------------------------------------------------------------------
# Calculation core
# ---------------------------------------------------------------------------
def calculate(spend: float, revenue: float = 0.0, conversions: int = 0,
leads: int = 0, margin_pct: float = 0.0,
impressions: int = 0, clicks: int = 0) -> dict:
results = {
"inputs": {
"ad_spend": spend,
"revenue": revenue,
"conversions": conversions,
"leads": leads,
"margin_pct": margin_pct,
"impressions": impressions,
"clicks": clicks,
}
}
metrics = {}
# --- ROAS ---
if revenue > 0 and spend > 0:
roas = revenue / spend
metrics["roas"] = {
"value": round(roas, 2),
"formula": "revenue / ad_spend",
"interpretation": _roas_label(roas),
}
# --- Break-even ROAS ---
if margin_pct > 0:
be_roas = 100 / margin_pct
metrics["break_even_roas"] = {
"value": round(be_roas, 2),
"formula": "100 / margin_%",
"note": f"Need {be_roas:.1f}x ROAS to cover ad costs at {margin_pct}% margin",
}
if revenue > 0:
actual_roas = revenue / spend
profitable = actual_roas >= be_roas
metrics["profitability"] = {
"is_profitable": profitable,
"gap": round(actual_roas - be_roas, 2),
"note": "Profitable ✅" if profitable else f"Unprofitable ❌ — need +{be_roas - actual_roas:.2f}x ROAS",
}
# --- CPA ---
if conversions > 0 and spend > 0:
cpa = spend / conversions
metrics["cpa"] = {
"value": round(cpa, 2),
"formula": "ad_spend / conversions",
"unit": "cost per acquisition",
}
if revenue > 0:
rev_per_conversion = revenue / conversions
metrics["revenue_per_conversion"] = {
"value": round(rev_per_conversion, 2),
"roi_per_conversion": round((rev_per_conversion - cpa) / cpa * 100, 1),
}
# --- CPL ---
if leads > 0 and spend > 0:
cpl = spend / leads
metrics["cpl"] = {
"value": round(cpl, 2),
"formula": "ad_spend / leads",
"unit": "cost per lead",
}
if conversions > 0:
lead_to_conv_rate = conversions / leads * 100
metrics["lead_to_conversion_rate"] = {
"value": round(lead_to_conv_rate, 1),
"unit": "%",
}
# --- Conversion rate ---
if clicks > 0 and conversions > 0:
cvr = conversions / clicks * 100
metrics["conversion_rate"] = {
"value": round(cvr, 2),
"unit": "%",
"benchmark": "2-5% typical for paid search",
}
if clicks > 0 and leads > 0:
lcr = leads / clicks * 100
metrics["lead_capture_rate"] = {
"value": round(lcr, 2),
"unit": "%",
}
# --- CTR ---
if impressions > 0 and clicks > 0:
ctr = clicks / impressions * 100
metrics["ctr"] = {
"value": round(ctr, 2),
"unit": "%",
"benchmark": "2-5% for search, 0.1-0.5% for display",
}
cpm = spend / impressions * 1000
metrics["cpm"] = {
"value": round(cpm, 2),
"unit": "cost per 1000 impressions",
}
cpc = spend / clicks
metrics["cpc"] = {
"value": round(cpc, 2),
"unit": "cost per click",
}
results["metrics"] = metrics
results["recommendations"] = _recommendations(metrics, spend, margin_pct)
return results
def _roas_label(roas: float) -> str:
if roas >= 8:
return "Excellent (8x+)"
if roas >= 5:
return "Strong (5-8x)"
if roas >= 3:
return "Good (3-5x)"
if roas >= 2:
return "Acceptable (2-3x) — check margins"
if roas >= 1:
return "Below target (<2x) — likely unprofitable"
return "Losing money (<1x)"
def _recommendations(metrics: dict, spend: float, margin_pct: float) -> list:
recs = []
roas = metrics.get("roas", {}).get("value")
be_roas = metrics.get("break_even_roas", {}).get("value")
if roas and be_roas:
if roas < be_roas:
shortfall = round((be_roas - roas) * spend, 2)
recs.append(f"⚠️ Losing ${shortfall:,.2f}/period — pause or restructure campaign immediately")
elif roas < be_roas * 1.5:
recs.append("⚠️ Marginally profitable — optimize creatives and targeting before scaling")
else:
recs.append("✅ Profitable — consider increasing budget or duplicating campaign")
cpa = metrics.get("cpa", {}).get("value")
cpl = metrics.get("cpl", {}).get("value")
cvr = metrics.get("conversion_rate", {}).get("value")
if cvr and cvr < 2:
recs.append(f"⚠️ CVR {cvr}% is low — test new landing pages, headlines, and CTAs")
elif cvr and cvr >= 5:
recs.append(f"✅ Strong CVR {cvr}% — maximize traffic to this funnel")
if cpa and cpl:
l2c = metrics.get("lead_to_conversion_rate", {}).get("value", 0)
if l2c < 10:
recs.append(f"⚠️ Lead-to-close rate {l2c}% is low — review sales qualification or nurture sequence")
ctr = metrics.get("ctr", {}).get("value")
if ctr:
if ctr < 1:
recs.append(f"⚠️ CTR {ctr}% is low — refresh ad copy and audience targeting")
elif ctr >= 5:
recs.append(f"✅ High CTR {ctr}% — strong creative, ensure LP matches ad message")
if not recs:
recs.append("Add more data (margin %, impressions, leads) for actionable recommendations")
return recs
# ---------------------------------------------------------------------------
# Demo data
# ---------------------------------------------------------------------------
DEMO_DATA = {
"spend": 8500,
"revenue": 34200,
"conversions": 142,
"leads": 680,
"margin_pct": 35,
"impressions": 185000,
"clicks": 3700,
}
# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
def main():
parser = argparse.ArgumentParser(
description="ROAS calculator — paid ads performance metrics and recommendations."
)
parser.add_argument("--spend", type=float, help="Total ad spend ($)")
parser.add_argument("--revenue", type=float, default=0, help="Total attributed revenue ($)")
parser.add_argument("--conversions", type=int, default=0, help="Number of purchases/conversions")
parser.add_argument("--leads", type=int, default=0, help="Number of leads generated")
parser.add_argument("--margin", type=float, default=0, help="Gross margin %% (e.g. 40)")
parser.add_argument("--impressions", type=int, default=0, help="Total impressions")
parser.add_argument("--clicks", type=int, default=0, help="Total clicks")
parser.add_argument("--file", help="JSON file with campaign data")
parser.add_argument("--json", action="store_true", help="Output as JSON")
args = parser.parse_args()
if args.file:
with open(args.file, "r") as f:
data = json.load(f)
elif args.spend:
data = {
"spend": args.spend,
"revenue": args.revenue,
"conversions": args.conversions,
"leads": args.leads,
"margin_pct": args.margin,
"impressions": args.impressions,
"clicks": args.clicks,
}
else:
data = DEMO_DATA
if not args.json:
print("No input provided — running in demo mode.\n")
result = calculate(
spend=data.get("spend", 0),
revenue=data.get("revenue", 0),
conversions=data.get("conversions", 0),
leads=data.get("leads", 0),
margin_pct=data.get("margin_pct", 0),
impressions=data.get("impressions", 0),
clicks=data.get("clicks", 0),
)
if args.json:
print(json.dumps(result, indent=2))
return
inp = result["inputs"]
metrics = result["metrics"]
recs = result["recommendations"]
print("=" * 62)
print(" PAID ADS PERFORMANCE REPORT")
print("=" * 62)
print(f" Spend: ${inp['ad_spend']:>10,.2f}")
if inp["revenue"]: print(f" Revenue: ${inp['revenue']:>10,.2f}")
if inp["conversions"]:print(f" Conversions:{inp['conversions']:>10}")
if inp["leads"]: print(f" Leads: {inp['leads']:>10}")
if inp["impressions"]:print(f" Impressions:{inp['impressions']:>10,}")
if inp["clicks"]: print(f" Clicks: {inp['clicks']:>10,}")
print()
print(" METRICS")
print(" " + "─" * 58)
metric_labels = [
("roas", "ROAS", lambda m: f"{m['value']}x — {m['interpretation']}"),
("break_even_roas", "Break-even ROAS", lambda m: f"{m['value']}x — {m['note']}"),
("profitability", "Profitability", lambda m: m['note']),
("cpa", "CPA", lambda m: f"${m['value']:,.2f} / {m['unit']}"),
("revenue_per_conversion", "Rev/Conversion", lambda m: f"${m['value']:,.2f} (ROI {m['roi_per_conversion']}%)"),
("cpl", "CPL", lambda m: f"${m['value']:,.2f} / {m['unit']}"),
("lead_to_conversion_rate","Lead→Conv Rate", lambda m: f"{m['value']}%"),
("conversion_rate", "Conversion Rate", lambda m: f"{m['value']}% ({m['benchmark']})"),
("ctr", "CTR", lambda m: f"{m['value']}%"),
("cpc", "CPC", lambda m: f"${m['value']:,.2f}"),
("cpm", "CPM", lambda m: f"${m['value']:,.2f}"),
]
for key, label, fmt in metric_labels:
if key in metrics:
try:
detail = fmt(metrics[key])
print(f" {label:<24} {detail}")
except Exception:
pass
print()
print(" RECOMMENDATIONS")
print(" " + "─" * 58)
for rec in recs:
print(f" {rec}")
print("=" * 62)
if __name__ == "__main__":
main()