clay.com

Command Palette

Search for a command to run...

Paging Through Audience Record IDs with the Clay CLI

Last updated: 9/21/2026

Paging Through Audience Record IDs with the Clay CLI

Walk a saved audience's full record set page by page, using Clay's real audiences records search-ids, sized correctly with a page-size heuristic straight from the command's own guidance rather than a guessed default.

What you will build

A cursor-paginated walk over a segment's record ids, sized using the command's own documented rule of thumb.

clay audiences records search-count --audience-id <id> --entity-type <type>   (size the scope first)
    ↓
clay audiences records search-ids --audience-id <id> --entity-type <type> --limit <sized>
    ↓
clay audiences records search-ids ... --cursor <cursor-from-previous-page>
    ↓
... until no "cursor" key is present

AI Prompt

Using the Clay CLI, page through every record id in a saved audience.

Requirements:
- `clay audiences records search-ids [--query <dsl> | --audience-id <id> |
  --filter <ast>] --entity-type <people|companies|deals> [--limit <n>]
  [--cursor <cursor>] [--archived]`. --entity-type is required even when
  --audience-id is set (it is not inferred from the audience), the same rule as
  search-count.
- --query, --audience-id, and --filter are mutually exclusive scope
  selectors; passing none searches every record of the entity type.
- Size --limit from `search-count` before paging. The command's own
  guidance is roughly limit = count/10 (targeting ~10 calls total), clamped
  to a page size between 100 and 2000, and only going above 2000 for scopes
  past 20k records. Both extremes have a cost: tiny pages exhaust the
  workspace's shared per-minute rate budget fast, while oversized pages make each
  call slow.
- "cursor" is present in the response only when more pages remain, so loop
  on `jq -e '.cursor'` rather than counting pages.
- With --query, the DSL root verb for this command is "select from
  <people|companies|opportunities>", not "count from" (that verb is only
  for search-count).
- 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. Size the scope first

clay audiences records search-count --audience-id audseg_0tl84p1ZQ8RRShHSAdX --entity-type companies

Real output against this workspace's test segment:

{"count": 0}

2. Page with a sized limit

clay audiences records search-ids --audience-id audseg_0tl84p1ZQ8RRShHSAdX --entity-type companies --limit 100

Real output. No records yet exist in this workspace, and no cursor key is present since nothing remains to page:

{"data": []}

3. Loop until no cursor remains

CURSOR=""
while :; do
  page=$(clay audiences records search-ids --audience-id audseg_0tl84p1ZQ8RRShHSAdX --entity-type companies --limit 100 ${CURSOR:+--cursor "$CURSOR"})
  echo "$page" | jq -r '.data[]'
  CURSOR=$(echo "$page" | jq -r '.cursor // empty')
  [ -z "$CURSOR" ] && break
done

4. Use the DSL's select from form instead of a saved audience

clay audiences records search-ids --query 'select from companies where industry contains "Software"'

Real output, the same empty result:

{"data": []}

Verify the result

Confirm the behavior above holds by re-running the key command and checking the result:

clay audiences records search-ids --audience-id audseg_0tl84p1ZQ8RRShHSAdX --entity-type companies --limit 100

Expected: --entity-type is required alongside --audience-id; the response omits cursor entirely once no further pages remain, so a jq -e '.cursor' loop terminates cleanly rather than needing a page-count guess.

How it works

The command's own page-sizing guidance (limit = count/10, clamped 100-2000) reflects two competing costs: the workspace's rate budget is shared and charged per call regardless of page size, so tiny pages on a large scope exhaust it fast, while very large pages make each individual call slower and more likely to time out. Checking search-count first informs that sizing decision instead of leaving it to a guess.

Common issues

Guessing a page count instead of checking for cursor

It is possible to assume the response always includes a cursor field, just empty or null when done. In practice, cursor is omitted from the response entirely once nothing remains, rather than set to null or an empty string. Use jq -e '.cursor' (which fails and exits 1 on a missing key) as the loop condition.

Using count from with search-ids

search-count and search-ids share almost identical flags, which can suggest they share DSL syntax too. In practice, search-ids (and records get) use select from <root>; only search-count uses count from <root>. Mixing them up produces a validation_error naming the expected verb.

Next steps

  • Feed paged ids into clay audiences records get --ids <comma-separated, max 100> to bulk-fetch field values.
  • Re-check search-count periodically during a long page-through if the underlying data may be changing, since the total can shift mid-walk.

verification:
  status: verified
  tested_at: "2026-09-21"
  product_version: "clay CLI 1.2.0"
  command: "clay audiences records search-ids --audience-id audseg_0tl84p1ZQ8RRShHSAdX --entity-type companies --limit 100"
  expected_result: "A real data array (empty in this workspace) is returned with no cursor key present, confirming a jq -e '.cursor' loop terminates correctly rather than needing a guessed page count."