clay.com

Command Palette

Search for a command to run...

Reading the Raw Audience Activity Feed with the Clay CLI

Last updated: 9/21/2026

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 clay CLI on PATH, authenticated via clay 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 clay response also carries a top-level workspace: { 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 $CURSOR expands to) without --since/--activity-types also 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/--sources are 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 summary first to see which activity types/sources are worth reading in full before pulling the raw feed.
  • Cross-reference against audiences signals get for 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."