revenue-audit — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited revenue-audit (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
The "email growth consultant in a box." Scans your connected ESP for the revenue sitting on the table and ranks every finding by estimated dollar impact, so you know exactly what to fix first.
Requires: Cogny MCP + a connected ESP. Sign up
This is the skill to run once per quarter, or whenever you inherit an email program and need to know where to start.
/revenue-audit — full audit of the connected ESP
If no mcp__cogny__* tools exist (no list_integrations, no cogny_status), print this:
Revenue Audit needs your marketing data through Cogny's MCP gateway.
1. Sign up at https://cogny.com and connect your ESP (Klaviyo, Mailchimp, Rule, Get a Newsletter, Brevo, MailerLite, Drip, Salesforce Marketing Cloud, Symplify or Braze), plus your store (Shopify, WooCommerce, Abicart, Litium) or Stripe for revenue.
2. Add Cogny to .mcp.json in your project:
{"mcpServers": {"cogny": {"type": "http", "url": "https://app.cogny.com/mcp"}}}
3. Restart Claude Code; it opens a browser for the OAuth login on first use.
Without Cogny you can still: paste your last 90 days of email revenue (total and per campaign/flow) plus your campaign stats export, and get a provisional audit from that.With pasted revenue, run only the checks the pasted data supports (typically 1, 3, 4, 5 and 9), label every $ figure "pasted by user", mark the rest "skipped — needs a connected ESP", skip steps 5–6 (no findings, no context tree) and stop after the output. When Cogny is connected but no ESP is, say "connect your ESP in Cogny".
Detect connected ESP (check both mcp__cogny__<svc>__* and mcp__<svc>__* namespaces). If the user has multiple connected, run against each and produce separate reports.
On Cloud, mcp__cogny__list_integrations shows what's connected; name any unhealthy integration as broken.
Health check: health_status misses revoked tokens, so make one cheap read per integration before relying on it (e.g. Mailchimp tool_get_account_info, Get a Newsletter tool_list_senders, Klaviyo get_account, Shopify tool_list_orders with a 1-day filter, Stripe stripe_api_read GetSubscriptions with limit: 1, GA4 tool_run_report for one day). A 401, Forbidden or scope error means 🔴 "reconnect <integration> in Cogny": name it, don't retry, and audit with what remains.
Missing tool: if a tool named here isn't exposed by the workspace, call mcp__cogny__refresh_mcp_discovery once, use the fallback named next to the tool for this run, mark that source ⚠ "needs reconnect", and tell the user to reconnect the Cogny MCP. Never loop on refresh. Get a Newsletter fallbacks: tool_get_report_have_not_opened → that report's list contacts minus the openers from tool_get_report_opens; tool_get_report_link_clicks → tool_get_report_opens (per-contact click counts) or tool_get_report_clicks (per-link totals); tool_get_report_opens_aggregated → the totals in tool_get_report. Mailchimp tool_get_campaign_content → tool_get_campaign for the headers, and ask the user for the body.
ESP connected but 0 sends in the window: skip the send-based checks (3, 4, 5, 9) for that ESP with a one-line note ("Get a Newsletter: connected, 0 sends in the last 90 days — send checks skipped") and still run the list checks (6, 8 and the never-mailed lists in Check 4).
Revenue data availability (cogny-mcp-proxy as of this writing):
| ESP | Has flows/automations? | Has purchase/revenue data? |
|---|---|---|
| Klaviyo | ✓ (list_flows) | ✓ (via list_events with metric="Placed Order", value field) |
| Mailchimp | ✓ (tool_list_automations) | ✗ — engagement only |
| Rule | ✓ (tool_list_journeys) | ✗ — engagement only |
| Get a Newsletter | ✗ — no flow concept exists | ✗ — engagement only |
| Brevo | ✗ — automations not exposed | ✗ — engagement only |
| MailerLite | ✗ — automations not exposed | ✗ — engagement only |
| Drip | ✓ (list_workflows, get_workflow) | Partial — subscriber lifetime_value; event names via list_event_actions |
| Salesforce Marketing Cloud | ✓ (list_journeys, get_journey, get_journey_email_performance) | Conversions count only |
| Symplify | ✓ names only (list_journeys) | ✓ conversion amount per delivery (get_campaign_overview) |
| Braze | ✓ (braze_list_canvases, braze_get_canvas_details, braze_get_canvas_summary) | ✓ Braze-attributed revenue in campaign/Canvas analytics |
Real revenue beats ESP-attributed revenue. If a store is connected, use it as the denominator for every ESP:
| Store (Prefix) | Revenue (90d) | AOV, repeat rate | Abandoned carts |
|---|---|---|---|
Shopify (Shopify) | tool_list_orders (query_filter: "created_at:>=YYYY-MM-DD financial_status:paid") | tool_list_customers (numberOfOrders, amount_spent) | tool_list_abandoned_checkouts |
WooCommerce (WooCommerce) | get_sales_report (date_min, date_max) | list_orders (after, status: "completed") | not exposed |
Abicart (Abicart) | get_sales_summary (start_date, end_date, group_by: "month") | avg_order_value_inc_vat in the summary | not exposed |
Litium (Litium) | get_sales_summary (start_date, end_date, group_by: "month") | same | not exposed |
Stripe (Stripe, SaaS) | stripe_api_read GetInvoices (status: "paid", created in the 90 days) minus GetRefunds | GetSubscriptions (status: "all"): active count, MRR, cancellations in the window | not applicable |
Stripe list calls: use limit 20–25 and page with starting_after (a 100-row page is ~370KB). GetSubscriptions has no canceled_at filter, so for cancellations in the window list status: "canceled" and filter canceled_at client-side.
For SaaS businesses Stripe is the revenue source: use it wherever this skill says store revenue, and read "AOV" as average invoice / ARPA and "repeat rate" as renewal rate.
Email's share of that revenue comes from, in order: the ESP's own attribution (Klaviyo, Braze, Symplify), GA4 tool_run_report (purchaseRevenue with sessionDefaultChannelGroup = Email), or the user. Name the source on every $ figure and use the store's currency. Without any of these, revenue estimates must be either (a) supplied by the user (paste historical email revenue), or (b) flagged as "engagement uplift only" with no dollar figures.
Pull once and reference throughout:
list_events with metric="Placed Order", summed value field, filtered to events attributed to email campaigns. This is the denominator for every % impact claim.If the ESP has no revenue data and no store or GA4 is connected: prompt the user for their approximate 90-day email revenue (or let them skip it). If they skip, use estimated value per subscriber per month = (industry benchmark $0.10–$2.00 depending on vertical) as a rough denominator, and clearly label every revenue estimate as "based on industry benchmark, not your actual data."
For each check, output: finding title + estimated $ lift + evidence + recommended fix.
#### Check 1 — Missing core flows / automations / journeys
Map "flow" to the right concept per ESP:
| ESP | Object | Tool |
|---|---|---|
| Klaviyo | Flow | list_flows + get_flow |
| Mailchimp | Automation / Customer Journey | tool_list_automations + tool_get_automation |
| Rule | Journey | tool_list_journeys |
| Get a Newsletter | No equivalent — skip this check and note the limitation | |
| Drip | Workflow | list_workflows + get_workflow |
| Salesforce Marketing Cloud | Journey | list_journeys + get_journey (entry source, goals) + get_journey_email_performance |
| Symplify | Journey | list_journeys (names only; judge coverage by name and say so) |
| Braze | Canvas | braze_list_canvases + braze_get_canvas_details + braze_get_canvas_summary |
| Brevo, MailerLite | Not exposed by the MCP — ask the user which automations run, or skip and note it |
Abandoned cart sizing with real data: if Shopify is connected, count tool_list_abandoned_checkouts for the last 30 days and their total value (total_price). Use that instead of "cart sessions × conv rate" in the evidence line.
The highest-ROI flows and their typical revenue contribution in healthy ecom programs (Klaviyo benchmarks):
| Flow | Typical % of email revenue | Trigger |
|---|---|---|
| Welcome series | 3–7% | New subscriber |
| Abandoned cart | 5–12% | Cart created, not checked out |
| Browse abandonment | 1–3% | Product viewed, no cart |
| Post-purchase | 2–5% | Order placed |
| Winback | 1–4% | No engagement in 60-120d |
| Replenishment | 2–6% (consumables only) | Predicted reorder date |
| Birthday / anniversary | 0.5–2% | Date token match |
| VIP / thank-you | 1–3% | Top-tier LTV crossed |
For each missing or disabled flow, estimate lift: total_email_revenue × benchmark_% as the annualized $ left on the table (Klaviyo). For Mailchimp/Rule/Get a Newsletter without revenue data, frame the impact as engagement uplift (e.g., "typically adds X–Y% to total email engagement volume") and skip the dollar estimate unless the user provided a revenue baseline.
#### Check 2 — Dormant high-value subscribers (Klaviyo only)
Segment current active list by:
Pull purchase history via list_events with metric="Placed Order". Group by profile_id, take max value sum per profile as LTV. Cross-reference against list_profiles last-engaged date.
Count subscribers who have purchased at least once but haven't opened/clicked in 60+ days. Estimate: count × avg_AOV × 3% reactivation rate × 2 orders/year = annualized recoverable revenue
Purchase data from the store: for any ESP, join Shopify tool_list_customers (numberOfOrders > 0, amount_spent), WooCommerce list_orders, or (SaaS) Stripe GetSubscriptions customers with a cancelled or past-due subscription to the ESP's subscribers on lowercased email. If Stripe's email/customer_email comes back [REDACTED] (a restricted key), skip the Stripe join and say so ("Stripe emails redacted by the restricted key: no subscriber match"); Stripe totals still work as context. Drip's subscriber lifetime_value works directly.
For Mailchimp / Rule / Get a Newsletter / Brevo / MailerLite with no store connected: purchase data is not exposed. Degrade this check to "dormant deeply-engaged subscribers" — pull subscribers with high historical open+click counts who haven't engaged in 60+ days, present as engagement-uplift opportunity without a dollar figure.
#### Check 3 — Under-segmented broadcasts Scan last 90 days of campaign sends. For each campaign, check if it was sent to:
Flag any campaign sent to >80% of list where segmentation would plausibly apply. Estimate lift: (segment_ctr - broadcast_ctr) / broadcast_ctr × revenue_of_that_campaign × number_of_similar_sends_per_year.
#### Check 4 — Promo calendar gaps Build a 90-day send calendar from actual sends. Look for:
tool_list_audiences, Get a Newsletter tool_list_lists + tool_get_list, Rule tool_list_tags, Brevo list_contact_lists, MailerLite list_groups) with the lists the sends targeted (Mailchimp tool_get_campaign recipients.list_id; Get a Newsletter tool_get_sent). A list with contacts that has never received a send is a finding on its own (e.g. "191-contact list never mailed"): those people opted in and heard nothing. Route them to /welcome-series; estimate value only from the store or Stripe base, otherwise "engagement uplift only".For dead zones during peak windows, estimate: avg revenue per send × N missing sends.
#### Check 5 — Flow decay For every active flow, check:
Recommend: refresh subject lines, update product references, re-evaluate offer.
#### Check 6 — Suppression leaks Count subscribers who have:
Sending to these hurts deliverability. Quantify the deliverability drag: "Removing these X subscribers typically lifts overall open rate by 1-3pp on remaining list, which compounds to ~Y% revenue lift across all future sends."
#### Check 7 — Post-purchase upsell / cross-sell gap (Klaviyo only)
Purchase-data-dependent — runs for Klaviyo (list_events with metric="Placed Order"), or any ESP when Shopify / WooCommerce orders are connected (repurchase cadence from tool_list_orders / list_orders grouped by customer email).
For brands with purchase data:
Estimate: customers_per_month × current_repurchase_rate_gap × avg_AOV.
Without Klaviyo or a connected store: skip this check with a one-line note ("skipped — no purchase data exposed by this ESP's MCP; connect Shopify/WooCommerce or paste purchase data manually").
#### Check 8 — List capture inference Compare list growth rate to benchmarks:
If growth is weak, flag: "Your site traffic vs. your list growth implies a capture rate of X%. Industry benchmark is 2-5%." Recommend: exit-intent popup, post-purchase capture, content offer gate.
Traffic (enhanced when connected): GA4 tool_run_report (metrics: ["totalUsers"], 90 days, no dimensions: summing channel or source rows double-counts users who arrived through several channels) or Plausible aggregate (metrics: ["visitors"]). New subscribers: Drip list_subscribers (subscribed_after), MailerLite list_subscribers (subscribed_at), or the ESP's list counts. Name both sources in the evidence line.
#### Check 9 — Over-reliance on discounting Scan subject lines and body content of broadcasts for % off / $ off / "sale" / "discount" / promo codes. (Mailchimp body: tool_get_campaign_content; if it's missing, fall back to tool_get_campaign settings.subject_line + preview_text and scan those only, marked ⚠.) If >60% of broadcasts lead with a discount:
Estimate: margin recovery = current_margin × (promo_share_reduction × conversion_retention).
Bucket into 🔴 High (>5% of annual email revenue or >$10k/yr), 🟡 Medium ($1k–$10k/yr), 🟢 Optimization (<$1k/yr or hard to quantify).
Revenue Audit: <brand> via <ESP>
Period analyzed: <date range>
Total email revenue (90d): $<X> Implied annualized: $<Y>
Estimated annual revenue left on the table: $<Z> (<Z/Y>% of current)
────────────────────────────────────────────────────
🔴 HIGH IMPACT — start here
────────────────────────────────────────────────────
1. Missing abandoned cart flow
Est. lift: $<X>/yr (7% of email revenue benchmark)
Evidence: No flow with trigger "cart created, not converted" in <ESP>.
Current cart sessions on connected store = <N>/month at
<conv rate>%. Industry abandoned-cart flow recovery ≈ 10–15%.
Fix: Build 3-email cart flow (1h / 24h / 48h). I can draft this now — run
/welcome-series and tell it "abandoned cart" or ask me to generate.
2. <N> dormant high-value subscribers (LTV > $<X>)
Est. lift: $<X>/yr
Evidence: <N> past purchasers with avg LTV $<Y>, no engagement in 60+ days.
At 3% reactivation × 2 orders/year × $<AOV> AOV.
Fix: Run /winback-engine for a tiered winback series.
3. ...
────────────────────────────────────────────────────
🟡 MEDIUM IMPACT
────────────────────────────────────────────────────
4. ...
────────────────────────────────────────────────────
🟢 OPTIMIZATION
────────────────────────────────────────────────────
7. ...
────────────────────────────────────────────────────
Suggested 90-day plan
────────────────────────────────────────────────────
Month 1: <high-impact items 1-2>. Est revenue unlock: $<X>.
Month 2: <high-impact item 3 + medium 1>. Est: $<Y>.
Month 3: <remaining>. Est: $<Z>.
Total 90-day estimated unlock: $<X+Y+Z>.Every finding in the output is also recorded in Cogny, so the dashboard has the same ranked list the user just saw. On Cloud call create_ticket first (fields mapped per section 2 of the routing guide); on Solo call create_finding:
{
"title": "Missing abandoned cart flow (est. +$<X>/yr)",
"body": "<evidence + fix>",
"action_type": "flow_build",
"expected_outcome": "Recover 10-15% of abandoned carts",
"estimated_impact_usd": <annualized impact>,
"priority": "high"
}Persist to context tree under insights/email/revenue-audit/<date> so the next audit can show progress:
Next steps I can help with right now:
/welcome-series — draft any missing flow
/winback-engine — execute #2 (dormant high-value)
/subject-line-lab — lift open rates on existing broadcasts
/email-report weekly — start tracking progress against this audit
Or: ask me to draft a specific flow by name.get_email_campaign / get_campaign.lifetime_value), 6, 8 run; Checks 3, 4, 9 have no broadcast history in the MCP; Check 5 has no per-email rates.list_email_sends, journeys). Journey numbers are lifetime, so Check 5 compares emails within a journey, not over time.get_campaign_overview; Check 1 by journey name only.Use create_ticket when the workspace has it (Cloud) and create_finding otherwise (Solo). The fields differ; see section 2 of ../marketing-engineer/references/mcp-routing.md.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.