Intake filters & tagging rules
Two kinds of rules shape what lands in your Dataset: intake filters decide whether an item is stored at all, and tagging rules label the records that match. This page documents both — every field, every operator, and the rule JSON.
Intake filters vs tagging rules
- Intake filters are a hard gate. An item must pass every intake filter to be ingested at all — fail one and it's dropped before it reaches your Dataset or costs you a record. Use them to cut noise: minimum score, minimum length, English only, no NSFW.
- Tagging rules are labels. They never block ingestion — items that don't match still ingest. Matching records get the rule's tags, which power the
matchedview, tag filters in search and GET /v1/records, and tag-based Alerts.
Rule of thumb
If you never want to see it, use an intake filter. If you want to see it sorted, use a tagging rule.
Where you edit them
Both kinds live on the thing they filter: open a Watcher or a Keyword Monitor keyword and you'll find an Intake filters section and a Tagging rules section. Each rule is a visual builder — match ALL or ANY of a list of conditions — with a Preview matches button that runs the rule against recent items before you save. A tagging rule with no conditions matches every record its Watcher ingests (that's how a keyword tags all of its finds).
Adding a new tagging rule to a community Watcher backfills matches from the last 7 days of ingested posts, so a new tag is never empty while you wait.
Fields you can filter on
| Field | Type | Meaning |
|---|---|---|
| platform | string | Source platform — 'reddit', 'hackernews', … |
| channel | string | Subreddit name or query the item came from (lowercase) |
| createdAt | date | When the post was created on the platform |
| title | string | Post title |
| body | string | Post body text |
| author | string | Author username |
| score | number | Upvotes / points at crawl time |
| numComments | number | Comment count at crawl time |
| questionDetected | boolean | True when the post reads like a question ("how", "recommend", "vs", ends with ?) |
| hasLink | boolean | True when the post links out |
| linkDomainCategory | string | Linked domain class: 'social', 'dev', 'blog', or 'other' |
| freshnessBucket | string | Post age: '<1h', '<6h', '<24h', '<72h', or 'older' |
| lengthBucket | string | Body length: 'empty', 'short' (<280 chars), 'medium' (<1200), or 'long' |
| language | string | 'en', 'other', or 'unknown' (lightweight detection) |
| nsfw | boolean | Reddit NSFW flag (Reddit items only) |
| flair | string | Reddit post flair (Reddit items only) |
| hnTags | string | Hacker News tags, comma-joined: story, ask_hn, show_hn, front_page, poll (HN items only) |
Derived fields (questionDetected, freshnessBucket, lengthBucket, language, linkDomainCategory) are computed by Prowlo at ingestion, so you can filter on them without writing your own heuristics.
Operators
| Operator | Meaning |
|---|---|
| eq / neq | Equals / not equals |
| in / nin | Value is in / not in a list |
| contains / not_contains | String contains / does not contain |
| regex_i | Case-insensitive regular expression match |
| gt / gte / lt / lte | Number comparisons (score, numComments) |
| after / before | Date comparisons (createdAt) |
| exists | Field has a value |
The rule document (JSON)
Under the visual builder, every rule is a small JSON document: a match tree of conditions composed with all (AND), any (OR), and not, plus an optional tag list on tagging rules. A tagging rule that labels English question posts scoring 20+:
{
"version": 1,
"match": {
"all": [
{ "field": "score", "op": "gte", "value": 20 },
{ "field": "language", "op": "eq", "value": "en" },
{ "field": "questionDetected", "op": "eq", "value": true }
]
},
"tag": ["hot-question"]
}An empty all ({ "all": [] }) matches everything — that's the "tag every find" rule. On intake filters the tag list is ignored: intake only decides whether the item is stored.
Recipes
- Drop low-effort posts — intake:
score gte 5andlengthBucket neq empty - English only — intake:
language eq en - No bots or promo accounts — intake:
author nin ["AutoModerator", …] - Only fresh threads — intake:
freshnessBucket in ["<1h", "<6h", "<24h"] - Tag buying questions — tagging:
questionDetected eq true+ tagquestion - Tag competitor mentions — tagging:
body contains "competitorname"(orregex_ifor variants) + tagcompetitor - Only Show HN launches — intake on an HN Watcher:
hnTags contains show_hn
Working with tagged records
Tagged records show up everywhere downstream: the matched view in the dashboard and in GET /v1/records (view=matched unlocks the tags filter), Alerts that fire when a record with a given tag lands, and your agent over MCP — the keyword_* tools manage tagging rules conversationally ("add a tag for 'onboarding frustration'").