Revenue Audit logo

Revenue Audit

Organization
cognyai
revenue-audit

Audit an email marketing program for revenue leaks — missing flows, dormant high-value subscribers, under-segmentation, promo gaps, stale automations — ranked by estimated $ impact

Overview

Publishercognyai
Repositoryclaude-code-marketing-skills
Skill namerevenue-audit
Stars
111
Forks
15
Bundled files
Instructions only
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by cognyai on GitHub. Read the source before you install it.

Installation

Install the Revenue Audit AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/cognyai/claude-code-marketing-skills/tree/main/skills/revenue-audit
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/cognyai/claude-code-marketing-skills.git /tmp/claude-code-marketing-skills
mkdir -p .claude/skills
cp -r /tmp/claude-code-marketing-skills/skills/revenue-audit .claude/skills/revenue-audit
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Revenue Audit in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Revenue Audit on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Revenue Audit is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Revenue Audit

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.

Usage

/revenue-audit — full audit of the connected ESP

Step 0: Is Cogny connected?

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".

Prerequisites Check

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.

Works with

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 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):

ESPHas 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 rateAbandoned 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 summarynot exposed
Litium (Litium)get_sales_summary (start_date, end_date, group_by: "month")samenot exposed
Stripe (Stripe, SaaS)stripe_api_read GetInvoices (status: "paid", created in the 90 days) minus GetRefundsGetSubscriptions (status: "all"): active count, MRR, cancellations in the windownot 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.

Steps

1. Establish baseline context

Pull once and reference throughout:

  • Total active subscribers
  • Average open rate + CTR (last 90 days)
  • Klaviyo only: Total email revenue (last 90 days) via list_events with metric="Placed Order", summed value field, filtered to events attributed to email campaigns. This is the denominator for every % impact claim.
  • Klaviyo only: Average AOV (total revenue / order count in period)
  • Store or Stripe connected (any ESP): total store revenue, order count and AOV for the same 90 days (Shopify / WooCommerce / Abicart / Litium, or Stripe for SaaS, see Works with), plus GA4 email-channel revenue if connected. Show ESP-attributed, GA4 and store figures as separate lines.
  • List growth rate (last 90 days)
  • Active flows / automations / journeys and their performance (Klaviyo / Mailchimp / Rule only — Get a Newsletter has no equivalent)
  • Last 90 days of campaign sends

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."

2. Run the nine checks

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:

ESPObjectTool
KlaviyoFlowlist_flows + get_flow
MailchimpAutomation / Customer Journeytool_list_automations + tool_get_automation
RuleJourneytool_list_journeys
Get a NewsletterNo equivalent — skip this check and note the limitation
DripWorkflowlist_workflows + get_workflow
Salesforce Marketing CloudJourneylist_journeys + get_journey (entry source, goals) + get_journey_email_performance
SymplifyJourneylist_journeys (names only; judge coverage by name and say so)
BrazeCanvasbraze_list_canvases + braze_get_canvas_details + braze_get_canvas_summary
Brevo, MailerLiteNot 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):

FlowTypical % of email revenueTrigger
Welcome series3–7%New subscriber
Abandoned cart5–12%Cart created, not checked out
Browse abandonment1–3%Product viewed, no cart
Post-purchase2–5%Order placed
Winback1–4%No engagement in 60-120d
Replenishment2–6% (consumables only)Predicted reorder date
Birthday / anniversary0.5–2%Date token match
VIP / thank-you1–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:

  • Ever purchased × engaged in last 60 days

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:

  • "All subscribers" / full list (bad default)
  • A meaningful segment (engaged, purchased, category-preference, geography)

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:

  • Weeks with zero broadcasts (dead zones)
  • Dead zones around proven peak buying windows (BFCM, Mother's Day, back-to-school — vertical-specific)
  • Over-send weeks (>4 broadcasts to the same segment in 7 days — fatigue risk)
  • Never-mailed lists: compare every list/audience/group (Mailchimp 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:

  • Last modified date — flag if >6 months
  • Open/CTR trend — flag if the flow's rolling 30-day rate is >20% below the flow's historical rate

Recommend: refresh subject lines, update product references, re-evaluate offer.

Check 6 — Suppression leaks

Count subscribers who have:

  • No open in 180+ days
  • No click in 180+ days
  • No purchase in 365+ days (if ecom)

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:

  • Does a post-purchase flow exist? (Check 1)
  • Does it include category-appropriate upsell or accessory recommendations?
  • What's the 30-day repurchase rate? If <15%, post-purchase is underbuilt.

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:

  • Ecom site with steady traffic: 2–5% monthly list growth is healthy
  • <1% monthly growth = under-capturing

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:

  • Flag as margin leak + audience training (they wait for sales)
  • Recommend: content-led sends, product drops, exclusivity, early access

Estimate: margin recovery = current_margin × (promo_share_reduction × conversion_retention).

3. Rank every finding by estimated $ impact

Bucket into 🔴 High (>5% of annual email revenue or >$10k/yr), 🟡 Medium ($1k–$10k/yr), 🟢 Optimization (<$1k/yr or hard to quantify).

4. Output

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>.

5. Record every item

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:

json
{
  "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"
}

6. Save the audit summary

Persist to context tree under insights/email/revenue-audit/<date> so the next audit can show progress:

  • "Last audit: 2026-01-15 — identified $120k/yr unlock; 2 items now implemented."

7. Offer next steps

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.

Notes

  • Benchmarks are rough. Real uplift depends on list quality, brand, vertical, and offer. Always frame estimates as "reasonable industry range" not "guaranteed."
  • Don't double-count. If "missing abandoned cart" and "post-purchase gap" both hit, check that the benchmark assumptions aren't overlapping.
  • ESP-specific check coverage (cogny-mcp-proxy):
    • Klaviyo: all 9 checks run with dollar estimates.
    • Mailchimp: Checks 1, 3, 4, 5, 6, 8, 9 run normally. Checks 2 and 7 degrade to "engagement-only" framing.
    • Rule: same as Mailchimp.
    • Get a Newsletter: Check 1 is skipped (no flow concept). Checks 2 and 7 are skipped (no purchase data). The remaining checks (3, 4, 5, 6, 8, 9) run on engagement data only.
    • Brevo, MailerLite: like Get a Newsletter (automations not exposed, so Checks 1 and 5 need the user's input); campaign stats come from get_email_campaign / get_campaign.
    • Drip: Checks 1, 2 (via lifetime_value), 6, 8 run; Checks 3, 4, 9 have no broadcast history in the MCP; Check 5 has no per-email rates.
    • Salesforce Marketing Cloud: Checks 1, 3, 4, 5, 9 run (list_email_sends, journeys). Journey numbers are lifetime, so Check 5 compares emails within a journey, not over time.
    • Symplify: Checks 3, 4, 9 run from get_campaign_overview; Check 1 by journey name only.
    • Braze: Checks 1, 4, 5 run (Canvases + campaign analytics, max 100 days per call); Checks 2 and 6 use segment sizes only.
    • Any ESP + Shopify/WooCommerce (or Stripe for SaaS): Checks 2 and 7 run with real purchase data, and every $ estimate uses store (or Stripe) revenue as the base.
  • Several ESPs connected: separate reports, as above. Store revenue is shared, so attribute it once — don't claim the same store revenue as each ESP's base.

Recording findings

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.

Frequently asked questions

What does the Revenue Audit AI skill do?

Audit an email marketing program for revenue leaks — missing flows, dormant high-value subscribers, under-segmentation, promo gaps, stale automations — ranked by estimated $ impact

Why use Revenue Audit on TypingMind?

Because you install it once and use it with any model. Revenue Audit is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Revenue Audit in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/cognyai/claude-code-marketing-skills/tree/main/skills/revenue-audit. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Revenue Audit?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Revenue Audit?

As many as you like. As long as a model supports skills, you can use Revenue Audit with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Revenue Audit AI skill free?

It is published on GitHub by cognyai. Check the repository for licensing terms. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇