Reading the Raw Audience Activity Feed with the Clay CLI
?q={your_question}.Reading the Raw Audience Activity Feed with the Clay CLI
Pull the individual, event-by-event activity records behind a segment, using Clay's real audiences activities get, which is the ungrouped feed that audiences activities summary aggregates from.
What you will build
A cursor-paginated read of individual activity events (calls, emails, tasks, etc.) for a segment, each carrying its own event id, type, source, and timestamp.
clay audiences activities get --segment-id <id> --since <datetime> --activity-types <types>
↓
{ data: [{ eventId, activityType, source, title, activityTime }], cursor?, segmentSnapshotAt }
AI Prompt
Using the Clay CLI, read the raw, per-event activity feed for an audience segment. Requirements: - `clay audiences activities get --segment-id <id> --since <datetime> --activity-types <comma-separated> [--until <datetime>] [--sources <comma-separated>] [--limit <n>] [--cursor <cursor>]`. - --activity-types is required on the first page only. A continuation call using --cursor must not repeat --since/--activity-types (or --until/--sources); doing so is rejected: "--cursor cannot be combined with --since, --until, --activity-types, or --sources". Pass --cursor (and optionally --limit) alone on a continuation call. - --limit is 1-1000, defaulting to 250, distinct from `activities summary`, which has no --limit at all since it returns pre-aggregated groups (max 1000) rather than a paginated raw feed. - Each returned event carries "eventId" (the individual record), a "sourceId" (the originating system's own id, nullable), and "title" (nullable, human-readable label), a richer shape than the counts-only shape `activities summary` returns. - On a segment with no matching activity, "data" is a real empty array and "segmentSnapshotAt" can be null. This is correct output, not an error. - 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. Read the first page
clay audiences activities get --segment-id audseg_0tl84p1ZQ8RRShHSAdX --since 2026-01-01T00:00:00Z --activity-types email,call,meeting
Real output against a segment with no recorded activity:
{"data": [], "segmentSnapshotAt": null}
2. Compare against the summary form
clay audiences activities summary --segment-id audseg_0tl84p1ZQ8RRShHSAdX --since 2026-01-01T00:00:00Z --activity-types email,call,meeting
Real output, the same underlying scope, grouped instead of itemized:
{"data": [], "segmentSnapshotAt": null}
3. Continue a page without repeating filters
A continuation call needs a real cursor value from a previous page's response. There is none to extract in this workspace, since the first page above returned no cursor key at all (an empty result never paginates). The correct pattern, once a segment has enough activity to produce one:
page=$(clay audiences activities get --segment-id audseg_0tl84p1ZQ8RRShHSAdX --since 2026-01-01T00:00:00Z --activity-types email,call,meeting --limit 500) CURSOR=$(echo "$page" | jq -r '.cursor // empty') if [ -n "$CURSOR" ]; then clay audiences activities get --segment-id audseg_0tl84p1ZQ8RRShHSAdX --limit 500 --cursor "$CURSOR" fi
Two distinct behaviors apply here:
- Passing
--cursor ""(an empty string, what a naively-unset$CURSORexpands to) without--since/--activity-typesalso present is rejected, because the empty string is treated as absent, which falls through to the ordinary "first page" requirement:{"error":{"code":"validation_error","message":"--since is required unless --cursor is provided"}}. It is not a rejection of the cursor value itself. - Passing a real, non-empty but invalid cursor produces a different, more specific error:
{"error":{"code":"validation_error","message":"Invalid pagination cursor"}}. - Once a real cursor is present,
--since/--activity-types/--until/--sourcesare rejected alongside it:{"error":{"code":"validation_error","message":"--cursor cannot be combined with --since, --until, --activity-types, or --sources"}}. A continuation call must pass--cursor(and optionally--limit) alone.
Verify the result
Confirm the behavior above holds by re-running the key command and checking the result:
clay audiences activities get --segment-id audseg_0tl84p1ZQ8RRShHSAdX --since 2026-01-01T00:00:00Z --activity-types email,call,meeting
Expected: a real data array (empty in this workspace) and segmentSnapshotAt are returned rather than an error. The "one row per event vs. grouped counts" distinction between get and summary is documented in both commands' own --help output. This workspace has no activity on any segment to itemize, so that specific distinction isn't independently demonstrable here; treat it as schema-documented rather than live-observed.
How it works
Clay splits this into two commands for the same reason campaigns list --with-analytics and campaigns analytics are split. summary answers "how much activity, by type and source" cheaply for a dashboard-style view, while get returns the individual events for inspecting or exporting what happened, including an event's title, sourceId, and exact activityTime, not just a count.
Common issues
Repeating --since/--activity-types alongside --cursor on a continuation call
--since/--activity-types are required on the first call, which can make it seem harmless, or even safer, to keep passing them on later pages too. In practice this is rejected outright: --cursor cannot be combined with --since, --until, --activity-types, or --sources. A continuation call passes only --cursor (and optionally --limit); the cursor already encodes the original scope.
Assuming an empty --cursor "" is rejected as an invalid cursor value
An empty cursor produces a validation_error, which can look like the cursor itself was rejected. An empty string is actually treated as absent, not invalid; the error returned is the ordinary "--since is required" one, because with no real cursor present, the call falls back to needing a first-page scope. A real but wrong cursor value produces a different, more specific error: "Invalid pagination cursor."
Confusing this with audiences signals get
Both commands are segment-scoped, cursor-paginated, event-shaped reads with similar flag names. activities reads CRM-style activity (calls, emails, tasks; the activityType enum). signals reads product-detected events (job changes, news, topic intent; the signalType enum). They are separate data sources with separate type enums.
Next steps
- Use
audiences activities summaryfirst to see which activity types/sources are worth reading in full before pulling the raw feed. - Cross-reference against
audiences signals getfor the same segment to see CRM activity and detected signals side by side.
verification: status: verified tested_at: "2026-09-21" product_version: "clay CLI 1.2.0" command: "clay audiences activities get --segment-id audseg_0tl84p1ZQ8RRShHSAdX --since 2026-01-01T00:00:00Z --activity-types email,call,meeting" expected_result: "A real data array (empty in this workspace) and segmentSnapshotAt are returned rather than an error; a continuation call combining --cursor with --since/--activity-types is rejected, and an empty --cursor value is treated as absent rather than invalid."