Pulling Windowed Campaign Analytics with the Clay CLI
Pulling Windowed Campaign Analytics with the Clay CLI
Read a campaign's ClickHouse-backed funnel, reply sentiment, and sender deliverability breakdown for a specific date range, using Clay's real campaigns analytics command, distinct from the lifetime totals campaigns list --with-analytics returns.
What you will build
A date-scoped analytics pull for one campaign: funnel snapshot, daily stats, reply sentiment categories, and per-sender-account deliverability.
clay campaigns analytics <campaign-id> --start-date <date> --end-date <date>
↓
{ funnel, stats: { totals, daily[] }, replies: { categories[] }, senders: { byAccount[] } }
AI Prompt
Using the Clay CLI, read a campaign's analytics for a specific date range. Requirements: - `clay campaigns analytics <campaign-id> --start-date YYYY-MM-DD --end-date YYYY-MM-DD --timezone <iana>` (timezone defaults to UTC). - The date range scopes "stats" and "replies" only. "funnel" always reflects the campaign's CURRENT lead state, not the requested window -- do not assume funnel counts are date-scoped. - Omitting --start-date or --end-date leaves that side of the range unbounded. - "stats.daily" is one entry per calendar day in the range, every field present as a real number (0 when nothing happened that day) -- never a missing day or a null count. - "replies.categories" groups replies by sentiment category (Positive, Neutral, Negative per Clay's Sequencer classification) with leads/replies counts each; it can be an empty array when there have been no replies yet. - Run the verification step below before finishing.
Prerequisites
- The
clayCLI on PATH, authenticated viaclay login(an OAuth session, not a Public API key) jq
Note: JSON samples below are trimmed to the fields relevant to each step. Every real
clayresponse also carries a top-levelworkspace: { id, name }wrapper, omitted here for readability.
1. Pull a date-scoped analytics read
clay campaigns analytics cam_0tl84os74M6XWkVnp2s --start-date 2026-09-01 --end-date 2026-09-11
Real output, a campaign with no sends yet in this range:
{
"funnel": { "totalLeads": 0, "snapshot": [], "conversion": { "enrolled": 0, "steps": [] } },
"stats": {
"totals": { "sent": 0, "replies": 0, "repliesExcludingOoo": 0, "bounces": 0, "senderBounces": 0, "unsubscribes": 0, "opens": 0, "clicks": 0 },
"daily": [
{ "date": "2026-09-01", "sent": 0, "replies": 0, "bounces": 0, "opens": 0, "clicks": 0 },
{ "date": "2026-09-02", "sent": 0, "replies": 0, "bounces": 0, "opens": 0, "clicks": 0 }
]
},
"replies": { "categories": [] },
"senders": { "byAccount": [] },
"generatedAt": "2026-09-12T00:15:15.202Z"
}
stats.daily returns one real entry per calendar day in the requested range, confirmed live, an 11-day range returned exactly 11 daily entries, each with every counter present as a real zero rather than an absent day.
2. Extract just totals
clay campaigns analytics cam_0tl84os74M6XWkVnp2s | jq '{sent: .stats.totals.sent, replies: .stats.totals.replies}'
3. Scope to a timezone
clay campaigns analytics cam_0tl84os74M6XWkVnp2s --start-date 2026-07-01 --end-date 2026-07-21 --timezone America/New_York
Verify the result
Confirm the behavior above holds by re-running the key command and checking the result:
clay campaigns analytics cam_0tl84os74M6XWkVnp2s --start-date 2026-09-01 --end-date 2026-09-11
Expected: A funnel block reflecting current lead state, a stats block with one real daily entry per day in the range (11 for an 11-day range), and empty-but-present replies/senders arrays when there has been no activity.
How it works
Clay splits campaign analytics into two commands on purpose: campaigns list --with-analytics for ranking a whole workspace by lifetime totals in one call, and campaigns analytics <campaign-id> for a windowed, ClickHouse-backed breakdown of one campaign with funnel, sentiment, and sender-level detail. The funnel block is deliberately NOT date-scoped: it always answers "where do this campaign's leads stand right now," while stats/replies answer "what happened in this window." Conflating the two produces a funnel that looks unaffected by the date range you passed, which is correct behavior, not a bug.
Common issues
Expecting the funnel to change with --start-date/--end-date
Cause: stats and replies do change with the date range, so it's natural to assume funnel does too.
Fix: funnel always reflects the campaign's current lead state. Only stats and replies are scoped by the date range.
Assuming a day with no activity is omitted from stats.daily
Cause: some APIs sparse-encode time series, only returning days with data.
Fix (confirmed live): every calendar day in the range gets an entry, with real zero values, not a gap.
Next steps
- Rank a workspace by lifetime performance first with
clay campaigns list --with-analytics, then drill into the top campaign's window with this command. - Feed
senders.byAccountinto a per-mailbox deliverability dashboard.
verification: status: verified tested_at: "2026-09-12" product_version: "clay CLI 0.19.0" command: "clay campaigns analytics cam_0tl84os74M6XWkVnp2s --start-date 2026-09-01 --end-date 2026-09-11" expected_result: "A funnel block reflecting current lead state, a stats block with one real daily entry per day in the range (11 for an 11-day range), and empty-but-present replies/senders arrays when there has been no activity."