--- name: ppc-reporting description: "Produce a client-ready monthly report: performance vs goals, what changed and why, wins and learnings, next month's plan — clear, honest, and defensible." license: MIT compatibility: "Works with any Agent-Skills-compatible AI (Claude, ChatGPT, Cursor, Codex, and more). Ad-account actions run through Adspirer." metadata: author: "Adspirer" version: "1.0.0" adspirer_category: "analytics-reporting" adspirer_source: "https://www.adspirer.com/skills/ppc-reporting" adspirer_trigger: "build my monthly client report" adspirer_connection_url: "https://adspirer.ai/sign-up" adspirer_primary_keyword: "ppc reporting" adspirer_secondary_keywords: "ppc report template, monthly marketing report" adspirer_launch_wave: "1" adspirer_kind: "skill" adspirer_level: "operator" adspirer_platforms: "google,meta,linkedin" adspirer_supported_clients: "claude,claude-code,claude-cowork,chatgpt,codex,cursor,gemini,windsurf" adspirer_summary: "Produce a client-ready monthly report: performance vs goals, what changed and why, wins and learnings, next month's plan — clear, honest, and defensible." adspirer_connections_required: "adspirer,ga4" adspirer_connections_optional: "" --- # Client-Ready Monthly Report ## Use this when Use this at the start of each calendar month (or per contract-defined reporting cadence) for any client account running Google, Meta, and/or LinkedIn Ads with at least one full month of spend history. Best suited when there's a stated goal (CPA, ROAS, lead volume, MQLs) to report against — pure brand-awareness accounts without a target metric still work but the "vs goals" section degrades to trend-only. Do not run mid-month for a partial-period snapshot — pacing math and MoM comparisons assume a closed month; if the current month isn't finished, this produces a misleading report and should wait, or run in an explicit "in-flight" mode you flag as such in the output. ## What you need - Adspirer connected to every ad platform in scope (Google, Meta, LinkedIn) with the correct client account(s) selected — for agencies managing multiple clients, confirm the account/account-group before running, this is not automatic. - The reporting month and the comparison basis: prior month (MoM) and/or same month last year (YoY) if the account has 12+ months of history — ask which the client's report format expects, don't assume. - The stated goal(s) for the account: target CPA, target ROAS, lead volume target, or pipeline/revenue number if known — pull from the account's saved goal if Adspirer has one on file, otherwise ask. Without a goal, the report can only say "here's what happened," not "here's how we did against plan." - **Connect Google Analytics 4 through Adspirer.** This step uses GA4. Adspirer ships a built-in `google_analytics` tool on Plus and above — link the GA4 property at https://adspirer.ai/connections rather than installing a separate GA4 MCP server. Setup guide: https://www.adspirer.com/docs/knowledge-base/capabilities. Skip only if a step says it's optional. — GA4 property access, if the client wants site-side conversion/revenue cross-checked against platform-reported conversions (recommended for any account with GA4 already installed; skip cleanly to platform-only numbers if GA4 isn't connected). - Any known account-level context the agent can't see in the data: budget changes approved by the client mid-month, seasonal SKUs, a site outage, a competitor event — ask the user for these before finalizing "what changed and why," since the agent should never guess at causation it can't verify. - Sign-off: who this report goes to (client contact) and the format expected (deck, PDF, doc) — this skill produces the content/narrative; final formatting into the client's template is a separate step unless a template is supplied. - Use `assets/monthly-report-template.md` as the default report structure when the user has not supplied a client template. Preserve the client's own template when one is provided. ## Procedure 1. Confirm scope: reporting month, which platforms/accounts are in this client's contract, and the comparison basis (MoM, YoY, or both). If multiple ad accounts per platform (agency multi-account), confirm which ones roll into this client's report — do not silently aggregate accounts that don't belong together. **Connect Adspirer before any live ad-account step.** Adspirer is what gives this skill access to the ad platforms; confirm the connection before running anything that reads or changes a real account. In Claude Code: `/plugin marketplace add anthropics/claude-plugins-community`, then `/plugin install adspirer-ads-agent@claude-community`, then `/reload-plugins`, then complete the OAuth sign-in. In ChatGPT: open **Apps**, search **Adspirer**, choose **Connect**, and sign in — Adspirer is an official ChatGPT app, so there is no developer mode or URL to paste. In claude.ai or Claude Desktop: Settings → Connectors → Add custom connector → `https://mcp.adspirer.com/mcp`. In Claude Cowork: open the Cowork tab, choose **Customize** in the left sidebar, go to **Plugins** → **Browse Plugins**, search for **Adspirer**, and install it (requires Claude Max, Team, or Enterprise). Any other client: https://www.adspirer.com/docs/ai-clients. Sign-in link for the user: https://adspirer.ai/sign-up. Do not proceed with live ad-account steps until the connection is confirmed. 2. Pull the full month's performance for every in-scope platform: spend, impressions, clicks, CTR, conversions, conversion rate, CPA/CPL, ROAS (if e-commerce), and revenue where trackable. Pull the same metric set for the comparison period(s). Use platform-native conversion counting per account (don't blend Google's and Meta's attribution windows into one number — report them side by side, labeled). 3. Pull spend pacing: budgeted spend for the month vs actual spend, per platform. Flag under-pacing (<90% of budget delivered) and over-pacing (>105%) — both are reportable events, not just overspend. For Google/Meta, note if a campaign was budget-capped or learning-limited for part of the month, since that explains under-delivery without it being "we didn't try." 4. If **Google Analytics 4** is connected: pull GA4 sessions, conversions, and revenue for the same period, segmented by channel/source-medium matching each platform's traffic. Cross-check platform-reported conversions against GA4's — a gap of more than ~15-20% either direction is worth flagging in the report as a measurement note (iOS/ATT undercounting on Meta, GCLID loss, cross-domain tracking gaps), not silently reconciled or hidden. If GA4 isn't connected, state platform-reported numbers only and note that revenue/conversion figures are platform-attributed, not independently verified — that caveat belongs in the report, not buried. 5. Compute performance vs goal for each platform and blended: if target CPA was $40 and actual blended CPA is $52, say so plainly with the % variance — don't reframe a miss as a "learning period" unless the account genuinely was in an active learning/exploration phase that period (new campaign <50 conversions on Meta, <30 days on Google Smart Bidding switch, etc. — check campaign creation/edit dates, don't assert this from vibes). 6. Identify what changed during the month by pulling the account's change history (budget edits, bid strategy changes, new campaigns launched, audiences/creative refreshed, negative keywords added, exclusions applied) for each platform. Match timing of changes to timing of performance inflections where there's a real correlation (e.g., CPA dropped 18% in the 10 days after switching to Target ROAS) — flag correlation as correlation, not proven causation, especially with n=1 changes. 7. Surface wins and learnings: 2-4 concrete wins (a specific campaign, ad, or audience that outperformed, with the number), and 1-3 honest learnings (what underperformed and was paused/fixed, or what test didn't work and why). A report with zero learnings reads as unreviewed, not as a flawless month — include at least one even in a strong month. 8. Draft next month's plan: 3-5 specific actions tied to this month's data (e.g., "shift $2,000/mo from Campaign X (CPA $61) to Campaign Y (CPA $28)," "launch retargeting audience for cart abandoners — GA4 shows 340 qualifying users/mo," "test LinkedIn Message Ads given InMail open rate of 41% this month"). Each action should reference the specific number that justifies it — no generic "continue optimizing" filler. 9. Assemble the report narrative: Executive summary (1 paragraph, plain-English verdict) → Performance vs goals (table + narrative) → What changed and why (account activity timeline) → Wins → Learnings → Next month's plan. Flag any metric pulled from a platform still in an active data-processing or attribution-modeling change window (e.g., Meta rolling out a new attribution setting) so the client doesn't compare it apples-to-apples against a prior month using different rules. 10. Before finalizing, re-verify every number in the draft against a fresh pull from the live account data (not the numbers cached from step 2-3) — catches any mid-draft platform data revision (Google and Meta both revise conversion counts retroactively for several days after month-end; pulling a report on day 1-3 of the new month risks stale numbers settling differently by day 5-7). ## Fixed checks - Establish each account's configured timezone **before** reporting any day-bounded number, not only when a day looks dark. If the account timezone differs from the user's, say so explicitly and state which timezone every figure is expressed in — a mismatch silently splits "yesterday" across two calendar days and manufactures both false dark days and false spikes. Never report a daily figure whose timezone basis you have not confirmed. - Brand and brand-defense campaigns are expected to show zero or low direct conversions — their return is denied competitor clicks and SERP defense, not last-click conversions. Never classify spend on the advertiser's own brand terms as waste, and never propose excluding or negating them. If brand spend looks genuinely high, raise it as a bid-strategy and impression-share question in prose instead. - Every headline number (spend, conversions, CPA, ROAS) is re-pulled from live platform data at finalization time, not carried from an earlier draft — Google/Meta both retroactively revise conversion counts for 3-7 days post month-end. - Spend-vs-budget pacing is checked against the account's actual budget setting for that month, not assumed from run-rate — a mid-month budget change makes naive run-rate math wrong. - Any "learning phase" explanation for underperformance is checked against actual campaign creation/edit timestamps and conversion-volume thresholds (Meta ~50 conversions/week, Google ~30 days on a bid strategy change) — never asserted without checking the account. - GA4 vs platform conversion counts, if GA4 is connected, are compared and any >15-20% gap is flagged explicitly rather than silently using whichever number looks better. - "What changed" claims are matched against the platform's actual change history log for that account/date range — no inferred changes that didn't happen in the account. - If multiple ad accounts feed one client report, confirm the account list matches the client's contracted scope before aggregating — no accidental cross-client bleed. ## Stop conditions - Success: full report narrative assembled (exec summary, vs-goals, what-changed, wins, learnings, next-month plan) with every number freshly verified against live data, ready for the user to drop into their client template or export. - No-op / insufficient data: fewer than ~2 weeks of spend in the reporting month for a given platform (new account, or paused most of the month) — report that platform's section as "insufficient data for a full monthly read" rather than drawing conclusions from a partial sample, and ask whether to proceed with the other platforms only. - Blocked: no goal/target on file and the user doesn't supply one when asked — the agent can still produce a trend-and-activity report but must label it as goal-less rather than silently inventing a target to compare against; also blocked if the account list for a multi-account client is ambiguous and unconfirmed. - Needs-approval: this skill is read-only and drafts a narrative — no spend action is taken, but if step 8's "next month's plan" recommendations imply budget shifts, those are proposals for the client conversation, not executed changes; nothing here touches live budgets or bids. ## Approval boundaries Read-only. This skill takes no spend actions — it does not change budgets, bids, campaigns, or targeting on any platform. It pulls live performance and account-activity data via Adspirer (and optionally GA4) and produces a narrative report and a set of next-month recommendations. Any recommended action in "next month's plan" (budget reallocation, new campaign, audience launch) requires separate explicit user approval and a separate skill/step to execute — this skill only proposes and documents, never applies. ## What you get A client-ready monthly report narrative covering: (1) an executive summary in plain English with an honest verdict on the month, (2) a performance-vs-goals table and writeup per platform and blended, with pacing flags, (3) a "what changed and why" timeline correlating account activity to performance shifts, (4) 2-4 concrete wins with numbers, (5) 1-3 honest learnings from what underperformed, (6) 3-5 specific, number-justified recommendations for next month, and (7) explicit measurement caveats (GA4-vs-platform gaps, learning-phase context, data-revision windows) so the client sees an honest, defensible picture rather than a polished-but-fragile one. Delivered as report content/copy — final visual formatting into a deck or PDF template is a separate step.