Watching an Audience for Job Changes with the Clay CLI
Watching an Audience for Job Changes with the Clay CLI
Create a signal that fires when a tracked person's current company changes, scoped to a saved audience segment rather than a table, using Clay's real signals create --type JobChange, which ships with a real confidence filter by default.
What you will build
A Paused JobChange signal watching every contact in a saved audience, using the type's real default schedule and confidence filter.
clay signals create --type JobChange --input '{"entityType":"CONTACT","segmentIds":[...]}'
↓
{ id (td_...), runStatus: "Paused", schedule: { periodUnit: "monthly" }, filter: { confidence >= 90 } }
AI Prompt
Using the Clay CLI, create a signal watching an audience segment for job
changes.
Requirements:
- `clay signals create --type JobChange --input '{"entityType":"CONTACT",
"segmentIds":["<audience-id>",...]}' [--schedule <cadence>] [--name
<name>] [--activate]`.
- JobChange watches by personIdentifier and defaults to a MONTHLY schedule.
entityType for an audiences-based signal must be CONTACT ("people" in
audiences terms) -- ACCOUNT is rejected for this type, because the
identifier this type checks by comes from the type itself, not from
entityType.
- Without --input's default filter overridden by --filter, JobChange ships
a REAL default filter: confidence >= 90 on the detected event. A signal
that "looks unfiltered" (no --filter passed) still only fires on
high-confidence detections -- not on every detected change.
- The signal is created Paused unless --activate is passed. Paused means it
neither runs nor spends credits -- safe to create for inspection first.
- "ALL" as a member of segmentIds is a sentinel for the whole audience of
that entity type, not a saved segment with that literal name.
- Run the verification step below before finishing.
Prerequisites
- The
clayCLI on PATH, authenticated viaclay login(an OAuth session, not a Public API key) - An existing people audience segment (
clay audiences list --entity-type people)
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. Create the signal, Paused
clay signals create --type JobChange --input '{"entityType":"CONTACT","segmentIds":["audseg_0tjs3u3yAgacWPpe926"]}' --name "TPC Docs: Champions moving"
Real output, created Paused, with the type's real default schedule and filter:
{
"id": "td_0tl866woYQ5ScAFSHRP",
"name": "TPC Docs: Champions moving",
"runStatus": "Paused",
"signal": {"id": "sig_0tl866wRB5EJ8XVbVbg", "type": "JobChange", "inputs": {"lookBackTimeWindowInMonths": 3, "entityType": "CONTACT", "segmentIds": ["audseg_0tjs3u3yAgacWPpe926"]}},
"input": {"table": null, "audiences": {"segmentIds": ["audseg_0tjs3u3yAgacWPpe926"], "entityType": "CONTACT"}},
"destinationTable": null,
"schedule": {"periodAmount": 1, "periodUnit": "monthly", "lastRunAt": null},
"filter": {"type": "GroupOp", "combinationMode": "And", "items": [{"type": "BinOp", "dataPath": ["confidence"], "operator": "GreaterThanOrEqual", "value": 90}]}
}
2. Confirm it before activating
clay signals get td_0tl866woYQ5ScAFSHRP | jq '{runStatus, filter}'
3. Widen or remove the confidence filter, if intended
clay signals update td_0tl866woYQ5ScAFSHRP --clear-filter
--clear-filter removes the default confidence gate entirely, so every detected job change fires regardless of confidence, a deliberate, real tradeoff between recall and noise.
Verify the result
Confirm the behavior above holds by re-running the key command and checking the result:
clay signals create --type JobChange --input '{"entityType":"CONTACT","segmentIds":["audseg_0tjs3u3yAgacWPpe926"]}'
Expected: A real signal is created in Paused status, watching the given audience segment, carrying the type's real default monthly schedule and confidence >= 90 filter.
How it works
JobChange (and Promotion) are the only two signal types that ship a non-empty default filter; every other type (NewHire, JobPost, News, the topic-intent types) defaults to firing on every detected change. That asymmetry exists because identity-matching a "this specific person changed companies" event carries real ambiguity that a confidence score is built to capture, while "a company posted a job" or "a company appeared in the news" doesn't have an analogous confidence dimension to filter on.
Common issues
A JobChange signal that "runs but produces almost nothing"
Cause: assuming an unfiltered signals create --type JobChange (no --filter passed) fires on every detected change, since no filter was explicitly set.
Fix: JobChange and Promotion both default to confidence >= 90 even with --filter omitted: this is a real default, not an unfiltered state. Use --clear-filter (via signals update) to actually remove it.
Passing entityType: "ACCOUNT" for an audiences-based JobChange signal
Cause: assuming entityType is a free choice independent of the signal type.
Fix: JobChange watches people (CONTACT) only: ACCOUNT is rejected as a validation_error, because the type itself fixes what it watches.
Next steps
- Resolve real topic ids first with
clay signals search-topicsbefore creating aPersonTopicIntent/CompanyTopicIntentsignal. - Use
clay signals list | jqto triage every signal in the workspace by type and run status.
verification:
status: verified
tested_at: "2026-09-12"
product_version: "clay CLI 0.19.0"
command: "clay signals create --type JobChange --input '{\"entityType\":\"CONTACT\",\"segmentIds\":[\"audseg_0tjs3u3yAgacWPpe926\"]}'"
expected_result: "A real signal is created in Paused status, watching the given audience segment, carrying the type's real default monthly schedule and confidence >= 90 filter."