Skip to content
Back to skills

Campaign Report

ASecurity

Generate a per-campaign marketing performance report (pipeline + content + funnel) for the board: a two-funnel (New Business / Account Management) HubSpot analysis built from a manual lead sweep reconciled three ways, destination-dated conversions (monthly counts, quarterly and YTD rates), GA4 traffic on one unified campaign page set, edition-over-edition deltas, and a board key takeaway. Markdown source + self-contained HTML; optional gated publishing step. Use when the user says \"/campaign...

  • 5 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 19, 2026
content-marketingrustgosqlspringperformance

Works with

  • terminal
  • cli

Security analysis

A100/100

Scanned October 1, 2026

npx -y skills add risukisu/marketing-skills --skill campaign-report --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Campaign Report?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Campaign Report
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/risukisu-campaign-report/badge)](https://www.skillsdirectory.com/skills/risukisu-campaign-report)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: campaign-report
description: "Generate a per-campaign marketing performance report (pipeline + content + funnel) for the board: a two-funnel (New Business / Account Management) HubSpot analysis built from a manual lead sweep reconciled three ways, destination-dated conversions (monthly counts, quarterly and YTD rates), GA4 traffic on one unified campaign page set, edition-over-edition deltas, and a board key takeaway. Markdown source + self-contained HTML; optional gated publishing step. Use when the user says \"/campaign-report\", \"campaign performance report for [campaign]\", \"build the [X] campaign report\", or wants one campaign's marketing and pipeline performance packaged for leadership. NOT the monthly board snapshot (marketing-monthly) and NOT the company-wide RevOps diagnostic (pipeline-analysis). Company, CRM ids, page sets, templates, and publishing targets come from a context pack in the workspace you launch from, chosen per run from the company and period you pass (e.g. /campaign-report Acme spring-launch YTD); nothing client-specific lives in this skill."
---

# campaign-report — per-campaign performance report

Produces, for **one campaign** over a period (default: YTD): a **markdown source**, a self-contained
**HTML report** in the client's design system, and, when the pack defines a target and the owner
says go, **ships it**. Funnel metric definitions are `pipeline-analysis/definitions.md`; do not
redefine them here.

**Paths.** `references/…` is relative to this skill's folder. Every output, template, and
publishing path comes from the client pack, never from the current directory.

## Step 0 — Company, campaign, and period (every run, one question)

Same procedure as `pipeline-analysis` Step 0 (one pack serves all three reporting skills). This
skill's folder never stores company data: the library is a public repository.

1. **Read the arguments**, in any order: a company, a campaign, and a period, e.g.
   `/campaign-report Acme "Spring launch" YTD`. Any may be missing.
2. **Find the packs** in the launch directory: markdown files with `pack: reporting` in their
   front-matter (skip `*.TEMPLATE.md`); read only `company` and `aliases`. Note filenames of
   campaign context nearby (a campaign README, a content plan, an earlier `*-performance-*.md`).
3. **Ask one question, always**, pre-filled from the arguments: "Acme · Spring launch · YTD to
   31 Aug · pack `…/reporting.md` — go?" No company given → list the companies found. No campaign
   → list the campaign page sets in the chosen pack. No period → propose YTD to the end of the
   last full month. Other answers: point me elsewhere / paste the essentials / start with none.
   Wait.
4. **Read only the approved pack**; its relative paths resolve from its folder. "None" means Step 1
   also collects portal id, funnels, GA4 property, and output path, and the run renders in the
   neutral default style.
5. **No pack yet?** Create one in the launch workspace from
   `pipeline-analysis/references/context-pack.TEMPLATE.md` (next to the company's other context,
   e.g. `companies/<company>/context/reporting.md`; ask), fill it with the user, verify ids live,
   continue. Never create it inside a skill folder.
6. **Legacy packs** (`references/<client>-context.local.md` here or in `pipeline-analysis/`): offer
   one only when `<client>` appears in the launch directory's path; say it is the old location
   and offer to move it into the workspace.

## Critical rules

1. **No fabrication.** Every number traces to a CRM or analytics query. Empty result → say so.
2. **Attribution = the manual sweep is the source of truth.** There is no clean campaign tag on
   tickets or deals. The report owner (or Sales) provides the authoritative lead list; the skill
   cross-checks each lead against the live CRM but never invents membership. A lead whose only deal
   is a different offering is excluded with an audit note.
3. **All campaign leads are marketing-attributed.** The channel split shows *how each lead
   arrived*; it is never a subdivision of attribution. No "marketing-attributable subset".
4. **Two funnels, never blended.** New Business and Account Management per the pack. AM is
   **flagged ⚑**, kept separable, and counts in the campaign roll-up but never in NB-only counts.
5. **MQL / SQL / Won-Lost** per `definitions.md`: MQL = an associated NB deal exists, counted by
   deal `createdate`; SQL = a main-pipeline deal at the SQL stage or later; Won/Lost across all
   pipelines by per-pipeline stage ids.
6. **Home currency only** (`amount_in_home_currency`).
7. **Association pulls are incomplete — reconcile three ways.** Ticket↔deal links are patchy in
   most portals. For every lead: (a) association pull, (b) deal-name / company search for unlinked
   deals, (c) the manual sweep. Never trust associations alone. Every broken link becomes a
   CRM-hygiene follow-up item; never fix associations in the live CRM without explicit approval.
8. **Destination-dated conversions.** Count a conversion in the period it *reaches* the stage.
   Show **monthly counts** and **quarterly/YTD rates only**; monthly rates can exceed 100% and
   mislead. Flag YTD as the reliable rate.
9. **One unified page set** per campaign for every content and traffic table. Search Console's
   relative-day tools cannot hit exact month boundaries; flag GSC as a separate cut.
10. **Shipping is gated and name-aware.** The report carries client and contact names. Confirm
    with the report owner before any push; a push is an outward action even behind a password.
11. **CRM numbers are directional, not absolute.** Say so in the footer.

## Workflow

### Step 1 — Intake (always ask)
Campaign and period are settled in Step 0. In one message: **the authoritative lead list** (CRM record links; offer to draft a candidate list for confirmation if
none is ready, but membership is the owner's call); **the campaign page set** (landing pages +
posts; confirm slugs against the pack).

### Step 2 — CRM pull + three-way reconcile
For each lead: pull the **ticket** (`subject, createdate, hs_pipeline, hs_pipeline_stage,
source_type, hubspot_owner_id`); pull **associated deals** (`dealname, pipeline, dealstage,
amount_in_home_currency, deal_currency_code, createdate, closedate, hs_is_closed_won, <SQL
stage-entry property>`); for every lead with no associated deal, run a **deal-name search**
(`dealname CONTAINS_TOKEN "<company>"`); record link status (linked / unlinked-but-found /
no-deal). Confirm Won/Lost stage ids per pipeline with a `GROUP BY pipeline, dealstage` if unsure.

> ⚠️ Raw record queries drop same-day upper-bound rows and can truncate at ~20–25 rows; use
> end-of-month bounds and reconcile against `DATE_TRUNC(createdate,'MONTH'), COUNT(*)` aggregates.

### Step 3 — Compute the funnel (small N, directly from the reconciled set)
Leads by ticket `createdate` month (deal-only records by deal `createdate`) · MQL by deal
`createdate`, NB vs AM kept separate · SQL = main-pipeline deals at SQL+ (often 0 early in a
campaign; say so plainly) · Won/Lost by `closedate` · open pipeline by stage (MQL-stage NB / AM vs
SQL-stage; Closed-Lost separately) · destination-dated monthly counts + quarterly/YTD rates ·
channel split by `source_type` family (events shown as "Events · <event>" when leads are generated
onsite; inbound; outbound; cross-sell/AM; referral). Before calling anything "deal-only", name-search
tickets too; a ticket can exist and be unlinked.

### Step 4 — GA4 content and traffic (unified page set)
Per page, period + de-duped YTD (`pagePath` in-list, `activeUsers`, `sessions`); de-duped monthly
aggregate via `yearMonth` (a per-page sum double-counts); pillar benchmark vs comparable pages when
relevant. Apply the pack's exclusions.

### Step 5 — Render markdown + HTML
Markdown → the pack's campaign report path (funnel, conversion, content, methodology, audit notes:
exclusions, unlinked-deal flags, page-set definition). HTML → copy the pack's reference campaign
report and swap the data; if none exists, build the first one from the structure below in the
neutral default style and register it in the pack as the reference. Links: deals `/0-3/<id>`,
tickets `/0-5/<id>`, pages `<website>/<path>`.

### Step 6 — Board key takeaway
One or two sentences of interpretation: cause → state → next action, and **who owns which open
decision**. It surfaces, it never decides strategy. Top-of-report banner, mirrored in the markdown.
Run `/copy-deslop` if it reads generic.

### Step 7 — Ship (only if the pack defines a target and the owner says go)
Follow the pack's publishing block exactly: file location and naming, metadata entry, build step,
commit, push, deployment verification. Respect any "never do X" line in it.

## Report structure (sections, in order)
1. **Header** — logo, "Campaign Report · Confidential", kicker, H1 + italic sub (period, sources),
   link to the campaign master file, pill-link to the previous edition.
2. **Key takeaway banner.**
3. **The pipeline this campaign is building** — 4 hero stats (Leads / MQL / SQL / Open pipeline)
   with edition-over-edition delta chips, then two callouts: a dry funnel one-liner (do not
   re-narrate the hero numbers) and a compact "what generated it" list of lead-gen artifacts.
4. **Pipeline value by stage** — MQL (NB + AM ⚑) vs SQL vs Closed-Lost, home currency, plus a
   **bridge table** for any material move since the previous edition (previous total → per-deal
   deltas → new total; "confirm with Sales" where a re-scope is undocumented).
5. **Conversion** — dual view behind a toggle: monthly counts table (hover tooltips name the
   accounts per cell) + quarterly/YTD rates, and the drop-out funnel (light accent = still live,
   red = terminally lost, chevrons for stage→stage and cumulative rates).
6. **Leads by channel** — channel bars in the accent colour (a ranking, not a funnel stage), a
   stage-key legend, then a **lead roster** grouped by channel with visible dividers between groups
   (account · journey · stage pill · deal value linking to the deal; `New · <Mon>` pill on new
   entries).
7. **Collapsed by default** (`<details>`): landing pages & pillar · content performance (sortable
   table: release date ↔ YTD traffic, sum row in `<tfoot>`, titles linking to live posts, author
   name + avatar from the CMS, publish dates from the CMS field not page markup) · traffic ·
   webinars.
8. **Data quality & technical notes** — open section immediately before the footer. Standing home
   for CRM findings (unlinked deals, sync gaps), each with a one-sentence recommendation the owner
   can share verbatim. Never at the top of the report.
9. **Methodology footer** (collapsed) — definitions, two-funnel note, colour key, association
   note, page-set definition, currency, sources, source-file pointer.

## Edition-over-edition conventions
- Deltas everywhere (hero chips, roster "New" pills, bridge table).
- Summary first and DRY; corrections live in the bridge, not in a top callout.
- The takeaway names owners of open decisions; it does not recommend high-stakes moves.
- Meta remarks (coverage, cross-check dates) go in hover info-pills or the footer, never as a
  visible intro paragraph. Info pills on every non-obvious metric; canonical ⚑ tooltip: "AM ⚑ =
  Account Management, existing-client expansion. Marketing-influenced and counted in this
  campaign's MQL total; the flag keeps the NB vs AM split visible. AM is a separate funnel and is
  never mixed into NB-only counts."
- Plain headlines ("State of the revenue pipeline"), no rhetorical ones.
- **Freeze + retitle:** when a new edition ships, retitle the previous one to its period in its
  `<title>`, H1, and metadata, tag it "frozen snapshot", and never edit it again.

## Colour semantics (defaults; the pack's design system overrides the values, not the roles)
Leads = ink · MQL = accent (NB light, AM dark) · SQL = gold · Won = green · Lost = red. Channel
bars use the accent, never the funnel greens or ambers. Use the pipeline's display name in the
body; keep raw ids in the footer.

## House style (defaults; the pack's §6 overrides)
Board-appropriate, candid, interpretive. No emoji unless asked. No "From X to Y" / "Beyond the X"
titles. Round headlines, full precision in detail. Client and contact names only inside the gated
report and the private source repo; de-identify elsewhere.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.