agentleFS
creatop-gtmcreatop-gtm/apollo-operator/skills/campaign-reporting/SKILL.md

campaign-reporting

Skill8 starsChanged 46 days agoMITView on GitHub

Report a campaign's real results from Apollo's own analytics: per sequence, step, variant, and mailbox, plus meetings booked and opportunities, read-only. Use weekly, at the end of an experiment, or before deciding to scale, change, or stop a campaign.

1 other project uses a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

3 rules. About 0 are common, 3 are distinctive, and 0 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Before deciding to scale, change, or stop a campaign.

    line 16
  2. Distinctive:

    All verified live on 2026-09-14.

    line 21
  3. Distinctive:

    Keep it to what a decision needs:

    line 69

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Campaign Reporting (Iterate)

Which sequence, which step, which variant, and which mailbox is actually producing replies and meetings. This skill reads it straight from the operator's own Apollo account and lays it out so a decision can be made: scale it, fix it, or stop it.

It is read-only. It counts meetings booked and opportunities created, and it never creates, moves, or edits anything. Managing the pipeline stays out of scope, per operator-context.

When to use

  • Weekly, as the Friday retrospective in weekly-rhythm.
  • At the end of an experiment, to read the result experiment-design set up.
  • Before deciding to scale, change, or stop a campaign.
  • Monthly, to see the whole account at once.

Where the numbers come from

All verified live on 2026-09-14.

SourceWhat it givesUse it for
apollo_analytics_sync_report70 metrics across 55 dimensions, filtered by sequence, user, or team, over a preset or custom date rangeThe report itself
apollo_emailer_messages_search with emailer_campaign_id and display_mode: "metadata_mode"The status counts the Apollo UI shows for one sequenceCross-checking the analytics totals
apollo emails search --stats replied (CLI)Every replied message, each with Apollo's reply_classReply quality, before positive-reply-scoring
apollo_emailer_campaigns_activity_feedOne contact's timeline in a sequenceExplaining a single odd result

The analytics call takes metrics, group_by, optional pivot_group_by, filters (emailer_campaign_ids, user_ids, team_ids), date_range (a preset such as last_30_days, or range_start and range_end), and sort.

Build the report

1. Start from analytics, not from the sequence list

Group by emailer_campaign_id over the reporting window. Do not build the list of campaigns from sequence search. On a real account, search (MCP and CLI alike) returned 9 sequences while analytics reported 14, including one with 40 sends. Archived sequences keep their history in analytics and vanish from search (confirmed in the Apollo UI 2026-09-14), so a report that starts from search silently loses every archived campaign.

Useful metrics: num_emails_sent, num_emails_delivered, num_emails_replied, num_emails_bounced, num_emails_unsubscribed, num_contacts_emailed, num_contacts_replied.

2. Break each live campaign down by step and variant

Filter to one sequence with emailer_campaign_ids, then:

  • By step: group_by: ["emailer_step_id"]. Shows where the thread goes quiet.
  • By variant: group_by: ["emailer_template_id"]. Returns readable labels such as "Step 1a" and "Step 1b". Grouping by emailer_touch_id gives the same split but only as ids, so use templates for anything a person reads.

3. Check the mailboxes

group_by: ["email_account_id"] with num_emails_sent and num_emails_bounced. Read each mailbox's allowed limit from apollo email-accounts list (email_daily_threshold), not from the analytics metric email_daily_limit, which reported 775 for a mailbox set to 25. A mailbox carrying the bounces is a deliverability problem wearing a copy problem's clothes; hand it to apollo-deliverability.

4. See who responds

person_seniority or person_title_unanalyzed show which roles reply. Always filter these to the campaign's sequence ids (see the traps below), or one-off emails get counted.

5. Count outcomes, read-only

num_all_meetings_scheduled_via_email and num_opportunities, grouped by month or user, not by sequence. Opportunities cannot be grouped by sequence at all: the request returns only a warning and no data.

6. Cross-check before anyone sees a number

Pick the busiest sequence and compare its analytics totals with apollo_emailer_messages_search in metadata_mode. They should match. On a real account they did exactly (2 sent, 2 delivered, 2 opened, 1 replied), and the Apollo UI agreed. If they do not, say so in the report rather than picking one.

7. Read reply quality

Pull apollo emails search --stats replied and count reply_class. Classes seen on a real account: willing_to_meet, follow_up_question, person_referral, not_interested, unsubscribe, and none at all (the largest group). Use it to sort, then run positive-reply-scoring for the metric that matters.

The report

Keep it to what a decision needs:

CampaignSentBounce %Reply %Positive reply %Meetings (month)Call

Then, per live campaign: the step where replies stop, the variant ahead (with its send count next to it), the mailbox bouncing most, and one recommended action. End with anything that did not reconcile in step 6.

Traps, all verified 2026-09-14

  • The analytics result is a markdown table, not structured data. It comes back in a summary string. Parse the table rows; do not look for a JSON array.
  • An incompatible metric wipes the report. Asking for num_opportunities grouped by sequence returned a warning and no table at all, not a table with one column missing. Request outcome metrics in a separate call.
  • One-off emails inflate replies in time and people groupings. Grouped by month, one account showed 30 sent and 19 replied, because replies to individual emails sent outside any sequence are counted. Grouped by sequence, they drop out. Filter by sequence ids whenever the question is about campaigns.
  • Analytics "bounced" is not the UI's bounced count. On one archived sequence analytics reported 40 sent, 34 delivered, and 6 bounced, while the Apollo UI showed 34 delivered and 0 bounced contacts. The 6 is exactly sent minus delivered. Report delivered and sent from analytics, and take bounces from the sequence's contact statuses (contact_statuses.bounced, hard_bounced) or the UI, and say which you used.
  • Opens are not a signal here. Cold campaigns in this library run with tracking pixels off, so num_emails_opened is either empty or meaningless. Do not report it as a result.
  • Small numbers are not results. A variant that "won" one reply to zero on one send each has told you nothing. Put the send count next to every rate, and use the sizing rule in experiment-design before calling a winner.
  • Replies are not positive replies. The reply rate includes unsubscribes and "not interested". Never present it as the outcome.

Common mistakes

  • Listing campaigns from sequence search and missing the archived ones.
  • Quoting analytics num_emails_bounced as a bounce rate without checking it against contact statuses.
  • Reporting opens.
  • Declaring a variant winner on a handful of sends.
  • Grouping replies by month without filtering to sequences, and reporting a reply rate above 100%.
  • Treating a quiet report as a quiet campaign. If a live sequence shows nothing scheduled, that is an apollo-account-audit finding, not a performance result.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.