The 14 Oct video paid: 212 subscribers, $380
The 14 October video brought 212 newsletter subscribers and $380 of Gumroad sales over 10 days. 3 of 5 posts brought nothing, including the reel with the second-most views.
Every Monday: each video and post whose 10 days are up, its views, and the newsletter subscribers and sales that came from its link in those 10 days.
Reads
You get
The card on the right is a sample. Yours shows your own numbers and updates in place every run.
What lands on your board
The 14 October video brought 212 newsletter subscribers and $380 of Gumroad sales over 10 days. 3 of 5 posts brought nothing, including the reel with the second-most views.
For creators, views are the number every platform shows first and the one that pays least. The video that brings 200 newsletter subscribers and a handful of template sales often looks average on the views chart, and the viral reel can bring nothing at all.
Every Monday the agent takes each post whose 10 days are over, follows its link (a UTM per post in the YouTube description or the link-in-bio entry) into beehiiv or Mailchimp subscribers and Gumroad or Stripe sales, and puts the views next to it. The card says which post paid and how many posts brought nothing.
YouTube: playlistItems.list on the uploads playlist for videos with contentDetails.videoPublishedAt 10 to 17 days ago, then Analytics reports.query with ids=channel==MINE, dimensions=video, metrics=views,subscribersGained and filters=video==<ids>. Instagram: GET /{ig-user-id}/media?fields=id,caption,media_product_type,permalink,timestamp, then GET /{media-id}/insights?metric=views,reach,saved,shares for each.
beehiiv: GET /publications/{publicationId}/subscriptions with order_by=created, direction=desc, reading created, utm_source, utm_campaign and referring_site. Mailchimp (whichever you use): GET /lists/{list_id}/members?since_timestamp_opt=... with the merge field your form fills with the campaign value.
Gumroad: GET /v2/sales with after, keeping price, buyer email and referrer. Stripe: Checkout Sessions with status=complete and metadata.utm_campaign. Also match buyer emails (lowercased) to the subscriber list, so a sale from someone who joined through a post counts for that post.
Each post has its own utm_campaign (for example yt-2026-10-14, ig-2026-10-12). Match subscribers and sales whose normalized value (lowercase, trimmed) equals it and whose time falls between the publish time and 10 days after. Records with only a referrer (youtube.com, instagram.com) go to that platform's unattributed row rather than to the nearest post; a post with no link of its own is marked "no link".
Rank posts by revenue, then subscribers, with views beside them and subscribers per 1,000 views. Count the posts that brought nothing and say which of them had no link, since those could not show anything.
With BRIEFKIN_TOKEN set, the agent sends the result as one card that updates in place every run. Without it, you get the report in the chat.
Pick your agent, where the data comes from and how to schedule it; the commands below follow.
One command. It puts the SKILL.md in ~/.claude/skills and in ~/.agents/skills, which Codex, Cursor, Gemini CLI, Copilot CLI and OpenCode read too.
shellcurl -fsSL https://briefkin.dev/skills/youtube-posts-that-paid/install | shAsk Claude Code:
promptRun the youtube-posts-that-paid skillOr paste the prompt instead of installing:
promptTake my YouTube videos and Instagram posts published 10 to 17 days ago. Get views (YouTube Analytics by video; Instagram media insights views). Each post has its own utm_campaign on its link. From beehiiv subscriptions (utm_campaign, utm_source, created) or Mailchimp members, count new subscribers per post in the 10 days after it went out; from Gumroad sales or Stripe Checkout Sessions (metadata.utm_campaign), total the sales per post in the same window, also crediting buyers whose email joined through that post. Records with only a youtube.com or instagram.com referrer go to an unattributed row per platform. Give me a table of posts with views, subscribers, sales and subscribers per 1,000 views, how many posts brought nothing and which had no link, and the one thing to repeat.Mondays at 10:00, from cron on any machine where Claude Code is signed in:
crontab0 10 * * 1 claude -p "Run the youtube-posts-that-paid skill"Add it with crontab -e. A laptop asleep at that time runs it when it wakes if you use launchd or Task Scheduler instead; GitHub Actions works for the API route.
Connect Briefkin once with curl -fsSL https://briefkin.dev/install | sh and every run lands on your board as a report card. How setup works
SKILL.md---
name: youtube-posts-that-paid
description: "Every Monday: each video and post whose 10 days are up, its views, and the newsletter subscribers and sales that came from its link in those 10 days. Use when the user asks for this, or when it runs on a schedule."
---
# Posts that paid: YouTube and Instagram to subscribers and sales
Every Monday: each video and post whose 10 days are up, its views, and the newsletter subscribers and sales that came from its link in those 10 days.
For creators, views are the number every platform shows first and the one that pays least. The video that brings 200 newsletter subscribers and a handful of template sales often looks average on the views chart, and the viral reel can bring nothing at all.
Every Monday the agent takes each post whose 10 days are over, follows its link (a UTM per post in the YouTube description or the link-in-bio entry) into beehiiv or Mailchimp subscribers and Gumroad or Stripe sales, and puts the views next to it. The card says which post paid and how many posts brought nothing.
## 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
- A link with its own UTM on every post: in the YouTube description, and on the link-in-bio page or story link sticker for Instagram, since captions are not clickable. The newsletter signup must keep the UTM (beehiiv does; Mailchimp needs a hidden merge field).
- YouTube OAuth with `yt-analytics.readonly` and `youtube.readonly`, an Instagram token with insights permission, and read access to beehiiv or Mailchimp and to Gumroad (`view_sales`) or Stripe.
If something is missing, say what and stop; do not invent numbers.
### Steps
1. **List posts whose 10 days just ended** (YouTube): YouTube: `playlistItems.list` on the uploads playlist for videos with `contentDetails.videoPublishedAt` 10 to 17 days ago, then Analytics `reports.query` with `ids=channel==MINE`, `dimensions=video`, `metrics=views,subscribersGained` and `filters=video==<ids>`. Instagram: `GET /{ig-user-id}/media?fields=id,caption,media_product_type,permalink,timestamp`, then `GET /{media-id}/insights?metric=views,reach,saved,shares` for each.
2. **Collect subscribers with their source** (beehiiv): beehiiv: `GET /publications/{publicationId}/subscriptions` with `order_by=created`, `direction=desc`, reading `created`, `utm_source`, `utm_campaign` and `referring_site`. Mailchimp (whichever you use): `GET /lists/{list_id}/members?since_timestamp_opt=...` with the merge field your form fills with the campaign value.
3. **Collect sales with their source** (Gumroad): Gumroad: `GET /v2/sales` with `after`, keeping price, buyer email and `referrer`. Stripe: Checkout Sessions with `status=complete` and `metadata.utm_campaign`. Also match buyer emails (lowercased) to the subscriber list, so a sale from someone who joined through a post counts for that post.
4. **Join on the post's campaign, inside its 10 days**: Each post has its own `utm_campaign` (for example `yt-2026-10-14`, `ig-2026-10-12`). Match subscribers and sales whose normalized value (lowercase, trimmed) equals it and whose time falls between the publish time and 10 days after. Records with only a referrer (`youtube.com`, `instagram.com`) go to that platform's unattributed row rather than to the nearest post; a post with no link of its own is marked "no link".
5. **Rank and post**: Rank posts by revenue, then subscribers, with views beside them and subscribers per 1,000 views. Count the posts that brought nothing and say which of them had no link, since those could not show anything.
## Route B: the browser
### What you need
- Signed in to YouTube Studio as the channel owner or a manager, to Meta Business Suite with access to the Instagram account, to beehiiv or Mailchimp, and to Gumroad or Stripe.
If something is missing, say what and stop; do not invent numbers.
### Steps
Start at https://studio.youtube.com/. The user is signed in already; never type passwords or codes, and ask if a sign-in page appears.
1. **Read views per post**: In YouTube Studio open **Analytics > Content**, set the dates to cover the last few weeks, and note views for videos published 10 to 17 days ago. For Instagram, open `https://business.facebook.com/latest/insights/` (or the professional dashboard in the app) and read views for each post in the same dates.
2. **Read new subscribers by campaign**: In beehiiv open **Audience > Subscribers**, filter by date added, and export the list so the UTM campaign and source columns come with it. In Mailchimp, export the audience with the merge field that holds the campaign value.
3. **Read sales**: On Gumroad open **Sales** and export the CSV for the period, which includes buyer email and referrer. In Stripe open **Payments**, filter by date and read the `utm_campaign` metadata your checkout sets on each payment.
4. **Join and rank**: For each post, count subscribers and sales whose campaign value is the post's own, in the 10 days after it went out, and buyers whose email joined through it. Put youtube.com or instagram.com referrers with no campaign in an unattributed row. Rank posts by sales, then subscribers.
Note: Exports are the honest way here: the subscriber and sales tables in the UI show a page at a time. YouTube Studio numbers settle a day or two after the fact. Meta Business Suite and the Instagram app can show slightly different view counts for the same post.
## The report
- **Post that paid best**: subscribers and sales in its 10 days.
- **Every post**: views, subscribers, sales, subscribers per 1,000 views.
- **Brought nothing**: how many posts, and which had no link.
- **Unattributed**: subscribers and sales from each platform that no post can claim.
- One thing to repeat, for example "The 14 Oct video pinned the template link first; do that on every video".
## 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": "youtube-posts-that-paid/<date of this run, e.g. 2026-10-16>",
"item_key": "youtube-posts-that-paid",
"project": "Acme",
"source": "Posts that paid: YouTube and Instagram to subscribers and sales skill",
"kind": "update",
"title": "The 14 Oct video paid: 212 subscribers, $380",
"summary": "The 14 October video brought **212 newsletter subscribers** and **$380** of Gumroad sales over 10 days. **3 of 5 posts brought nothing**, including the reel with the second-most views.",
"widget": [
{
"type": "Table",
"props": {
"columns": [
"Post",
"Views",
"Subscribers",
"Sales",
"Per 1k views"
],
"align": [
"left",
"right",
"right",
"right",
"right"
],
"rows": [
[
"YouTube, 14 Oct: Pricing my first template",
18400,
212,
"$380",
11.5
],
[
"Instagram reel, 12 Oct",
9800,
31,
"$40",
3.2
],
[
"Instagram reel, 15 Oct (no link)",
12100,
0,
"$0",
0
],
[
"YouTube, 10 Oct: Notion setup tour",
6200,
0,
"$0",
0
],
[
"Instagram carousel, 16 Oct",
3400,
0,
"$0",
0
],
[
"All five",
49900,
243,
"$420",
4.9
]
]
}
},
{
"type": "Callout",
"props": {
"text": "The 15 Oct reel had no link of its own. 46 subscribers came from instagram.com with no campaign in its 10 days, so some of them are probably its.",
"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 10:00 (`0 10 * * 1`). From cron, with the agent signed in on that machine:
```bash
0 10 * * 1 claude -p "Run the youtube-posts-that-paid 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/youtube-posts-that-paid#schedule
Source: https://briefkin.dev/skills/youtube-posts-that-paid
A link with its own UTM on every post: in the YouTube description, and on the link-in-bio page or story link sticker for Instagram, since captions are not clickable. The newsletter signup must keep the UTM (beehiiv does; Mailchimp needs a hidden merge field).
YouTube OAuth with yt-analytics.readonly and youtube.readonly, an Instagram token with insights permission, and read access to beehiiv or Mailchimp and to Gumroad (view_sales) or Stripe.
youtube access before you sign in.YOUTUBE_API_KEY.yt-analytics.readonly and youtube.readonly (Analytics API requests now need both), and store YOUTUBE_CLIENT_ID, YOUTUBE_CLIENT_SECRET and YOUTUBE_REFRESH_TOKEN. Publish the OAuth app: refresh tokens from an app left in Testing expire after seven days.Those read-only scopes can't upload, edit or delete anything; add yt-analytics-monetary.readonly only if the report shows revenue.
instagram_business_basic and instagram_business_manage_insights. Calls go to https://graph.instagram.com, and the skill reads INSTAGRAM_ACCESS_TOKEN and INSTAGRAM_USER_ID. Long-lived tokens last 60 days and can be refreshed before they expire.instagram_basic, instagram_manage_insights and pages_read_engagement, and call https://graph.facebook.com.Request only the basic and insights permissions; without instagram_business_content_publish or instagram_business_manage_comments, the token can read numbers but can't post or reply.
https://mcp.beehiiv.com/mcp. In beehiiv, open Settings > MCP, pick your client (beehiiv has guides for Claude, Claude Code, Cursor and Codex) and grant access when asked. It is available on every plan: free plans are read-only, and paid plans add write tools for content, segments and automations, though it can't publish, schedule or send posts. To connect a second workspace, add a parameter such as ?account=2 to the URL (docs).BEEHIIV_API_KEY with BEEHIIV_PUBLICATION_ID (it starts with pub_), and send it as a Bearer token.The endpoints this report reads need only posts:read, subscriptions:read and publications:read. On a paid plan the MCP connection can edit drafts and segments, so keep it for interactive work and use a read-only key for scheduled runs.
https://ai-inc.mailchimp.com/claude/mcp/v2) is in Claude's connector directory. It plans, edits and saves campaigns as drafts and uses your past performance for its suggestions, but Mailchimp describes it as focused on campaign planning, not on pulling reports, and connecting it takes an Owner or Admin role (help).MAILCHIMP_API_KEY, and read the data center from its suffix (...-us6 means https://us6.api.mailchimp.com/3.0). Send it with HTTP Basic auth (any username, the key as the password) or as a Bearer token. The API allows 10 simultaneous connections, so page through reports one request at a time.API keys can't be limited to read-only: a key acts with the role of the user who created it, so keep it in a secret store, use it only for GET requests, and revoke it when the report is retired.
https://gumroad.com/claude/v1/mcp as a custom connector (Gumroad isn't in Claude's directory yet) and sign in to Gumroad; other clients that support OAuth with PKCE can use the same URL. Its tools list products, sales and payouts, and can create, publish and unpublish product drafts (details).GUMROAD_ACCESS_TOKEN and pass it as the access_token parameter. An OAuth app can ask for just the view_sales scope.If your client lets you choose OAuth scopes for the MCP server, keep view_sales and view_payouts and leave out edit_products unless you want drafts made from chat. Disconnecting in the chat app doesn't revoke the token: do that under Authorized Applications in Gumroad's settings.
https://mcp.stripe.com. Add Stripe from Claude's connector directory, or run claude mcp add --transport http stripe https://mcp.stripe.com/, and sign in with OAuth; clients without OAuth can send a restricted key as a Bearer token.stripe login once, then stripe subscriptions list --status active --limit 100 or stripe invoices list --status open. The CLI defaults to test mode, so add --live for real data.rk_live_...) in the Dashboard under Developers > API keys, store it in STRIPE_API_KEY, and give it Read on the resources the report touches: Subscriptions, Invoices, Charges, Customers, PaymentIntents, Balance and Disputes.Never hand an agent the secret key (sk_live_...); a restricted key with Read where needed and None everywhere else can't refund, cancel or charge anything.
Most of a video's or post's clicks come in its first week, and a newsletter subscriber who buys usually does so soon after joining. Ten days gives each post the same window so they can be compared. A video that keeps getting found in search will earn after that; the agent can add a 90-day column for YouTube if you ask, kept apart from the 10-day ranking.
Only through a link the post points to: a link-in-bio entry with that post's UTM, a story link sticker, or a code word in the caption that people type at checkout. Without one, anything a post brings arrives with an instagram.com referrer or none at all, and the agent leaves it in the unattributed row instead of guessing which post it was.
No. The skill runs with your own agent and gives you the report in the chat. With a Briefkin token set, each run also posts it to your board as a report card, so you can glance at it instead of asking again.
Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot CLI, OpenCode, Windsurf and Amp all read SKILL.md files. The install command puts it in ~/.claude/skills and ~/.agents/skills, where they look. ChatGPT, the Claude app and Grok take the prompt instead. Pick your agent under "Install and run it" and the commands change to match.
Yes. Switch the data source to "Your browser" and the steps change to the YouTube, Instagram, beehiiv, Mailchimp, Gumroad and Stripe pages themselves: the agent opens studio.youtube.com in a browser you are signed in to and reads the numbers off the page. Claude Code, Codex, Cursor, Claude app and ChatGPT can drive a browser out of the box; Gemini CLI, Copilot CLI and OpenCode need a Playwright or Chrome DevTools MCP server first. It is slower than the API and needs you signed in, so it suits a report you run by hand or from a scheduler on your own computer.
Skills are free to use with any agent. Briefkin is where their results land: one board for every report, number and question your agents send, with a ping when something needs you.
Free during the open beta. No card.