---
name: mailchimp-email-to-revenue
description: "Every Monday: each recent email's sessions, sign-ups and sales in the 7 days after it went out, joined on its utm_campaign, next to the open rate. Use when the user asks for this, or when it runs on a schedule."
---

# Which emails made money: Mailchimp, Klaviyo or Beehiiv, analytics and sales

Every Monday: each recent email's sessions, sign-ups and sales in the 7 days after it went out, joined on its utm_campaign, next to the open rate.

Email tools rank sends by open rate, and open rate is mostly Apple Mail opening everything on arrival. What a creator or a marketer actually wants to know is which issue brought people to the site who then signed up or bought, and the email tool cannot see that.

Every Monday the agent takes each send whose 7-day window has closed, follows its `utm_campaign` into GA4 for sessions and sign-ups, and into Stripe or Gumroad for sales, with a buyer-email match against the people who clicked as a fallback. The card ranks sends by what they earned and shows how little the open rate had to do with it.

## Two ways to get the data

Use the API or MCP route when you have an MCP server, a CLI or an API token for the app. Otherwise, if you can drive a browser the user is signed in to (Claude in Chrome, a Playwright or Chrome DevTools MCP server), use the browser route. Say which one you used.

## Route A: API or MCP server

### What you need

- UTM tagging on in the email tool (Mailchimp Google Analytics link tracking, Klaviyo UTM tracking, beehiiv Automatic UTM Tagging), and a checkout that stores the UTM in Stripe Checkout Session metadata if you sell through Stripe.
- A GA4 sign-up event (marked as a key event helps), Viewer on the GA4 property, and read access to the email tool and to Stripe or Gumroad (a restricted key, or `view_sales` on Gumroad).

If something is missing, say what and stop; do not invent numbers.

### Steps

1. **List the sends and their UTM value** (Mailchimp): From whichever email tool you use, take sends from the last 5 weeks whose 7-day window has closed. Mailchimp: `GET /campaigns?status=sent&since_send_time=...`, with `tracking.google_analytics` as the utm_campaign and `GET /reports/{campaign_id}` for open and click rate. Klaviyo: `GET /api/campaigns` (filter on `messages.channel` = email) and read the UTM values from the campaign's tracking settings. beehiiv: `GET /publications/{publicationId}/posts?expand[]=stats`; its automatic tagging uses a URL-friendly post title as utm_campaign.
2. **Get sessions and sign-ups per campaign** (Google Analytics): Call `runReport` with `dimensions: ["sessionCampaignName", "sessionMedium"]`, metrics `sessions` and `engagedSessions`, a filter `sessionMedium` matching `email` (case-insensitive), and the 5-week range; run it again with `eventCount` and a filter `eventName == "sign_up"` (or your sign-up key event). Read each send's 7 days only by adding the `date` dimension.
3. **Collect sales in each window** (Stripe): Stripe: Checkout Sessions with `status=complete` in the range, with `metadata.utm_campaign`, `amount_total` and `customer_details.email`. Gumroad: `GET /v2/sales` with `after` and `before`, keeping each sale's price, buyer email and `referrer`.
4. **Join on utm_campaign, then on the clicker's email**: Normalize campaign values (lowercase, URL-decode, trim) and match sessions and sales to the send whose value equals them, only within 7 days of the send. Sales with no UTM fall back to buyer email: match it, lowercased, against who clicked that send (Mailchimp `GET /reports/{campaign_id}/email-activity`, Klaviyo `Clicked Email` events), and give the sale to the latest send they clicked. Every sale counts once; the rest stay "not from email".
5. **Rank and post**: Rank sends by revenue, then sign-ups. Put open rate beside each so the card shows whether it predicted anything, and name the send that earned most and what was different about it (subject, offer, link position).

## Route B: the browser

### What you need

- Signed in to the email tool, to GA4 with Viewer access on the property, and to Stripe or Gumroad with access to sales.

If something is missing, say what and stop; do not invent numbers.

### Steps

Start at https://login.mailchimp.com/. The user is signed in already; never type passwords or codes, and ask if a sign-in page appears.

1. **List the sends**: In Mailchimp open **Analytics > Reports** (in Klaviyo, **Campaigns**; in beehiiv, **Posts**) and note each send from the last 5 weeks whose 7 days are over: name, send date and open rate. Open one report and click a tracked link to read the `utm_campaign` value the tool adds.
2. **Read sessions and sign-ups in GA4**: Open `https://analytics.google.com/`, then **Explore > Free form**. Add the dimensions **Session campaign** and **Session medium**, the metric **Sessions**, a filter Session medium contains `email`, and each send's 7 days as the date range. Read sessions, then add the metric **Event count** and a filter Event name exactly `sign_up` and read sign-ups (the event filter changes what Sessions counts).
3. **Read sales in each window**: In Stripe open **Payments**, filter by date and read the `utm_campaign` metadata your checkout puts on each payment. On Gumroad open **Sales**, filter by date, and export the CSV to see each buyer's email and referrer.
4. **Join and rank**: Match each send's UTM value to the GA4 rows and sales (lowercased), only in the 7 days after the send. For sales without a UTM, check whether the buyer appears in the send's click report. Rank the sends by revenue and put the open rate next to each.

Note: GA4 explorations sample large date ranges on standard properties, so keep each range to one send's 7 days. The clicker-email fallback is slow by hand: a few sales are fine, dozens are a job for the API route. beehiiv shows clicks per link but not who clicked through the UI on every plan.

## The report

- **Best send** in the last 5 weeks: sessions, sign-ups and revenue in its 7 days.
- **Every send**: open rate, sessions, sign-ups, revenue, ranked by revenue.
- **How the sales were matched**: by UTM or by clicker email.
- **Not from email**: sales in the period that no send can claim.
- The one thing to repeat, for example "Put the offer link first, as Issue 41 did".

## Post it to Briefkin

When `BRIEFKIN_TOKEN` is set, or `~/.config/briefkin/env` exists (the installer from https://briefkin.dev/docs writes it), also send the result to the user's Briefkin board as one card. Keep the `item_key` the same on every run so the card updates in place, use a new `event_id` per run, and put today's real numbers in place of the example ones. If the request fails, say so once and carry on.

```bash
[ -n "${BRIEFKIN_TOKEN:-}" ] || . ~/.config/briefkin/env
curl -sS -X POST "${BRIEFKIN_URL:-https://briefkin.dev}/v1/events" \
  -H "authorization: Bearer $BRIEFKIN_TOKEN" \
  -H "content-type: application/json" \
  -d @- <<'JSON'
{
  "v": 1,
  "event_id": "mailchimp-email-to-revenue/<date of this run, e.g. 2026-10-16>",
  "item_key": "mailchimp-email-to-revenue",
  "project": "example.com",
  "source": "Which emails made money: Mailchimp, Klaviyo or Beehiiv, analytics and sales skill",
  "kind": "update",
  "title": "Issue 41 brought 38 sign-ups and $412",
  "summary": "Issue 41 brought **38 sign-ups** and **$412** in its 7 days, more than the other four sends together (31 and $261). It had the lowest open rate of the five, so open rate predicted neither.",
  "widget": [
    {
      "type": "Table",
      "props": {
        "columns": [
          "Send",
          "Open rate",
          "Sessions",
          "Sign-ups",
          "Revenue"
        ],
        "align": [
          "left",
          "right",
          "right",
          "right",
          "right"
        ],
        "rows": [
          [
            "Issue 41 (Oct 14)",
            "31%",
            540,
            38,
            "$412"
          ],
          [
            "Issue 39 (Sep 30)",
            "44%",
            290,
            11,
            "$116"
          ],
          [
            "Issue 38 (Sep 23)",
            "46%",
            270,
            9,
            "$87"
          ],
          [
            "Issue 40 (Oct 7)",
            "49%",
            310,
            7,
            "$58"
          ],
          [
            "Pricing update (Oct 9)",
            "52%",
            260,
            4,
            "$0"
          ],
          [
            "All five",
            "",
            1670,
            69,
            "$673"
          ]
        ]
      }
    },
    {
      "type": "Callout",
      "props": {
        "text": "Issue 41 opened with the template link instead of an essay. 6 of its 11 sales matched by UTM, 5 by a buyer who had clicked it. $1,940 of sales in the period came from no send.",
        "tone": "info"
      }
    }
  ]
}
JSON
```

Widgets come from the Briefkin catalog (https://briefkin.dev/v1/catalog). Without a token, just give the user the report.

## Run it on a schedule

Suggested: Mondays at 9:30 (`30 9 * * 1`). From cron, with the agent signed in on that machine:

```bash
30 9 * * 1 claude -p "Run the mailchimp-email-to-revenue skill"
# Codex: codex exec, Gemini CLI: gemini -p, Copilot CLI: copilot -p, OpenCode: opencode run
```

Or use the agent's own scheduler (Claude Code routines, Codex automations, Claude or ChatGPT scheduled tasks): https://briefkin.dev/skills/mailchimp-email-to-revenue#schedule

Source: https://briefkin.dev/skills/mailchimp-email-to-revenue
