DocsOpen app
Docs/Features/Filters & tagging

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 matched view, 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

FieldTypeMeaning
platformstringSource platform — 'reddit', 'hackernews', …
channelstringSubreddit name or query the item came from (lowercase)
createdAtdateWhen the post was created on the platform
titlestringPost title
bodystringPost body text
authorstringAuthor username
scorenumberUpvotes / points at crawl time
numCommentsnumberComment count at crawl time
questionDetectedbooleanTrue when the post reads like a question ("how", "recommend", "vs", ends with ?)
hasLinkbooleanTrue when the post links out
linkDomainCategorystringLinked domain class: 'social', 'dev', 'blog', or 'other'
freshnessBucketstringPost age: '<1h', '<6h', '<24h', '<72h', or 'older'
lengthBucketstringBody length: 'empty', 'short' (<280 chars), 'medium' (<1200), or 'long'
languagestring'en', 'other', or 'unknown' (lightweight detection)
nsfwbooleanReddit NSFW flag (Reddit items only)
flairstringReddit post flair (Reddit items only)
hnTagsstringHacker 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

OperatorMeaning
eq / neqEquals / not equals
in / ninValue is in / not in a list
contains / not_containsString contains / does not contain
regex_iCase-insensitive regular expression match
gt / gte / lt / lteNumber comparisons (score, numComments)
after / beforeDate comparisons (createdAt)
existsField 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 5 and lengthBucket 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 + tag question
  • Tag competitor mentions — tagging: body contains "competitorname" (or regex_i for variants) + tag competitor
  • 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'").