Threads Brand Monitor avatar

Threads Brand Monitor

Pricing

from $1.20 / 1,000 results

Go to Apify Store
Threads Brand Monitor

Threads Brand Monitor

Monitor Threads for brand mentions, competitor posts, keyword activity, and alerts with scheduled Apify runs.

Pricing

from $1.20 / 1,000 results

Rating

0.0

(0)

Developer

DigitalNomadPH

DigitalNomadPH

Maintained by Community

Actor stats

0

Bookmarked

4

Total users

3

Monthly active users

16 days ago

Last modified

Share

Track brand mentions, competitor posts, hashtag activity, and keyword conversation on Threads from scheduled Apify runs — without needing a Threads account or API access.


What does Threads Brand Monitor do?

Threads Brand Monitor fetches public posts from Threads handles, keyword searches, and hashtags, normalises them into structured records, and emits per-group summaries and alerts. You configure one or more watchlists — each watchlist is a named group of handles, keywords, and/or hashtags — and the actor produces:

  • Post records for every matched Threads post
  • Reply records (optional) for reply threads under matched posts
  • Author records (optional) with bio, follower count, and bio links for discovered post authors
  • Profile records with follower counts, bios, and verification status for each monitored handle
  • Summary records per watchlist group with volume, engagement, sentiment breakdown, top posts/authors/keywords, and change vs. the previous run
  • Alert records when thresholds are crossed (risk keyword hit, mention spike, competitor breakout, high-engagement post)
  • A run summary with totals and timing

Run it on a schedule (daily or hourly) to track how a brand, competitor, campaign, or hashtag conversation evolves on Threads over time.


Why use Threads Brand Monitor?

  • No Threads account required — works with publicly accessible Threads pages
  • Scheduled monitoring — pair with Apify's built-in scheduler and mode: "monitor_new_posts" for daily or hourly reports
  • Robust new-post tracking — repeat runs flag is_new_since_last_run: true and can skip already-seen posts entirely, using both a last-run anchor and a persisted seen-post set
  • Multi-group watchlists — track your brand, competitors, campaigns, and hashtags in a single run, each with its own summary
  • First-class hashtags — monitor hashtags directly instead of folding them into keyword lists
  • Differentiated alerts — risk keyword hits, whole-group and per-query mention spikes, competitor breakouts, and high-engagement posts, each with a severity level
  • Structured output — clean JSON records ready for Google Sheets, BigQuery, Zapier, or any webhook

How to use

  1. Open the actor on Apify Console and click Try for free
  2. Configure your watchlists — add at least one group with handles, keywords, and/or hashtags to monitor (see Input section below)
  3. Choose a modebrand_monitor for a full run, or monitor_new_posts for scheduled runs (see "Understanding mode" below)
  4. Set your risk keywords — words that trigger alert records when found in post text (e.g. outage, refund, bug)
  5. Click Start — the actor runs and saves results to the default dataset
  6. Export or connect — download as CSV/JSON from the Output tab, or connect via Apify's API or integrations

Understanding mode

mode picks the overall run style. It defaults to brand_monitor.

modeWhat it does
brand_monitorFull run: emits posts, profiles, summaries, alerts, and a run summary. Best for a first run or an on-demand report.
monitor_new_postsScheduled-run style: emits only new post/reply/author rows plus a compact run summary (no summary/alert records). Automatically defaults onlyNewPosts to true. Best for frequent scheduled runs feeding a downstream pipeline.

For most users: use brand_monitor for manual/occasional runs, and monitor_new_posts for anything on a schedule.


Search coverage: focused vs. balanced

searchCoverage controls how thoroughly keyword and hashtag searches are covered:

  • focused (default) — searches the most relevant results view only. Fastest, fewest requests.
  • balanced — also fetches a more recent-oriented results view and merges results with the focused view, deduplicating by post ID. Improves coverage of newer posts at the cost of extra requests per query.

Matched posts record which view(s) surfaced them in matched_views ("relevant", "recent", or both).

Be aware: public Threads search is a bounded, best-effort surface — it does not guarantee exhaustive or stable results. The same query can return a different mix of posts between runs, and typical/common keywords will surface more noise. Use specific brand names, handles, or hashtags for the cleanest signal.


Watchlists, keywords, and hashtags

Each watchlist group can combine handles, keywords, and hashtags:

{
"name": "Campaign — Launch Week",
"type": "campaign",
"handles": [],
"keywords": ["product launch"],
"hashtags": ["#LaunchWeek", "productlaunch"]
}
  • Hashtags can be entered with or without a leading #"#LaunchWeek" and "LaunchWeek" both normalize to the same internal feed (#launchweek).
  • Hashtag-matched posts are tagged match_type: "hashtag" with a normalized matched_hashtag field.
  • Keyword-matched posts are tagged match_type: "keyword"; handle-timeline posts are tagged match_type: "profile_post".

Scheduled monitoring example

For a recurring "what's new" feed, use monitor_new_posts (or onlyNewPosts: true under brand_monitor):

{
"mode": "monitor_new_posts",
"watchlists": [
{
"name": "Our Brand",
"type": "brand",
"handles": ["our-threads-handle"],
"keywords": ["our-product-name"],
"hashtags": ["#ourhashtag"]
}
],
"searchCoverage": "balanced"
}

Set up a daily or hourly Apify Schedule pointed at this actor with the input above. Each run persists a per-group seen-post set and last-seen anchors in Apify's Key-Value Store, so subsequent runs skip posts already returned — no manual date-range management needed.

If you want the fuller summary/alert reporting on a schedule too, use mode: "brand_monitor" with onlyNewPosts: true instead — you'll get new-post filtering plus summaries and alerts each run.


Full input reference

FieldTypeDefaultDescription
modeenumbrand_monitorRun style — see "Understanding mode" above.
watchlistsarrayRequired. One or more named groups to monitor. Each group has name, type (brand, competitor, campaign, topic), and handles/keywords/hashtags arrays.
searchCoverageenumfocusedfocused (relevant view only) or balanced (relevant + recent, merged). See "Search coverage" above.
maxPostsPerHandleinteger25Max posts to collect per handle per run. Threads embeds only a handful of posts in the initial page load — raising this past what Threads serves will not return more posts.
maxPostsPerKeywordinteger50Max posts to collect per keyword or hashtag search query.
dateFromdate stringunsetKeep posts published on or after this date (inclusive).
dateTodate stringunsetKeep posts published on or before this date (inclusive). When either bound is set, posts with no timestamp are dropped.
includeProfileRepliesbooleanfalseInclude replies that already appear in monitored handle timelines. Does not fetch reply trees under matched posts — see includeReplyThreads for that.
includeRepliesbooleanfalseDeprecated alias for includeProfileReplies. Used only if includeProfileReplies is not explicitly set.
includeReplyThreadsbooleanfalseFetch the public post page for each matched post and emit its replies as record_type: "reply" rows, linked via parent_post_id/parent_post_url. Increases runtime and output size.
replyDepthinteger1How many reply levels to fetch when includeReplyThreads is on. 1 = top-level replies (fully supported); 2 additionally fetches each reply's own replies (extra requests per reply).
includeProfileStatsbooleantrueEmit a profile record per monitored handle with follower count, bio, and verification status.
includeReportsbooleantrueEmit per-group summary and alert records. Disable to return only post/reply/author/profile rows plus the compact run summary (also off automatically in monitor_new_posts mode).
onlyNewPostsbooleanfalse (true when mode is monitor_new_posts)Return only posts not seen in previous runs, using both a last-run anchor and a persisted seen-post set. Recommended for scheduled runs.
deltaModebooleanfalseDeprecated alias for onlyNewPosts. Used only if onlyNewPosts is not explicitly set.
includeAuthorDetailsbooleanfalseEmit an author record for each distinct post author discovered during the run (bio, follower count, verification, bio links).
includeAuthorContactsbooleanfalseOpt-in, off by default. Extracts emails and phone numbers from public author bio text (and bio links, if followAuthorLinks is also on), and adds them to the author record. Enabling this alone (with includeAuthorDetails left off) still emits author records — it needs somewhere to attach the extracted fields. See "Contact extraction and compliance" below.
followAuthorLinksbooleanfalseOnly has an effect together with includeAuthorContacts. Visits a bounded number of public bio-link-hub pages (e.g. Linktree) per author to look for additional contact info.
riskKeywordsarray["outage","refund","bug","broken","support","scam","cancel"]Posts containing any of these words are flagged in risk_flags and can trigger negative_post alerts.
minEngagementinteger0Skip posts with fewer total interactions (likes + replies + reposts). Only applied when engagement data is available (see "When engagement fields are unavailable" below) — keyword/hashtag results without engagement data always pass through.
alertThresholdsobjectsee belowControls when alert records fire — see "Alerts" below.
proxyConfigurationobjectApify residentialResidential proxies are recommended for keyword/hashtag search. Threads may block datacenter IPs on search routes.

alertThresholds fields

FieldTypeDefaultDescription
mentionSpikeMultipliernumber3Volume multiplier (vs. the previous run) that triggers a mention_spike alert, both whole-group and per-query.
minEngagementForAlertnumber100Minimum total interactions (likes + replies + reposts) for a new_high_engagement_post alert to fire. Also used to scale severity (see "Alerts" below).
competitorBreakoutMultipliernumber2Volume or engagement multiplier (vs. the previous run) that triggers a competitor_breakout alert for competitor-type groups.
riskPostAlertLevelenum (low/medium/high)lowMinimum severity a risk-keyword post alert must reach to be emitted. low means any risk-keyword match alerts.

Example input

{
"mode": "brand_monitor",
"watchlists": [
{
"name": "Our Brand",
"type": "brand",
"keywords": ["our-product-name"],
"handles": ["our-threads-handle"],
"hashtags": ["#ourhashtag"]
},
{
"name": "Competitors",
"type": "competitor",
"handles": ["competitor-a", "competitor-b"],
"keywords": [],
"hashtags": []
},
{
"name": "Campaign — Launch Week",
"type": "campaign",
"keywords": ["product launch"],
"handles": [],
"hashtags": ["#launchweek"]
}
],
"searchCoverage": "balanced",
"maxPostsPerHandle": 25,
"maxPostsPerKeyword": 50,
"onlyNewPosts": true,
"riskKeywords": ["outage", "bug", "refund", "broken", "cancel", "scam"],
"alertThresholds": {
"mentionSpikeMultiplier": 3,
"minEngagementForAlert": 500,
"competitorBreakoutMultiplier": 2,
"riskPostAlertLevel": "low"
}
}

Contact extraction and compliance

includeAuthorContacts and followAuthorLinks are opt-in and off by default. When enabled, they extract emails and phone numbers found in publicly visible author bio text and, optionally, in public bio-link-hub pages (e.g. Linktree-style pages linked from a bio).

  • This is best-effort pattern matching over already-public text, not a verified contact directory.
  • Enabling these fields does not imply permission to contact anyone — you are solely responsible for lawful processing of any extracted contact data (including applicable privacy/data-protection law) and for complying with Threads' and any linked site's terms of service.
  • If you don't need contact data, leave both fields off — includeAuthorDetails alone gives you bio, follower count, verification, and bio links without contact extraction.

Output

All records land in the actor's default dataset. Each record has a record_type field to distinguish them.

Record types

record_typeOne row perKey fields
postEach matched Threads posttext, author_handle, published_at, like_count, reply_count, repost_count, match_type, matched_views, risk_flags, sentiment_direction, is_new_since_last_run
replyEach reply row (when includeReplyThreads is on)parent_post_id, parent_post_url, reply_to_author, text, like_count, reply_count
authorEach distinct discovered author (when includeAuthorDetails or includeAuthorContacts is on)handle, bio, follower_count, verified, bio_links, emails/phone_numbers (only with includeAuthorContacts)
profileEach monitored handlehandle, display_name, follower_count, bio, verified_status
summaryEach watchlist groupsee "Summary fields" below
alertEach threshold crossedalert_type, severity, message, trigger_value, post_url, query
run_summaryEntire runtotal_posts_returned, new_posts_returned, alerts_generated, run_started_at, run_finished_at

Summary fields

Beyond the original volume/engagement/sentiment counts, each summary record includes:

FieldDescription
top_risk_postsUp to 5 risk-keyword-flagged posts, sorted by engagement (desc) then recency, as a flat array of {post_url, author_handle, risk_flags, engagement, published_at}.
top_authorsUp to 5 authors by post count (ties broken by total engagement), as {handle, post_count, total_engagement}.
top_keywordsUp to 10 most frequent matched keywords/hashtags this run, as {term, count}.
posts_by_match_typePost counts grouped by match type: {keyword, handle, hashtag, profile_post, reply}.
coverage_notesShort strings noting search limitations observed this run (e.g. a query returned no results, or a query hit its maxPostsPerKeyword/maxPostsPerHandle cap and more results may exist). Empty when nothing notable was observed.

All of the above are flat arrays of simple objects/primitives (no deep nesting) so they export cleanly to CSV/Google Sheets.

Sample post record

{
"record_type": "post",
"group_name": "Our Brand",
"group_type": "brand",
"match_type": "keyword",
"query": "our-product-name",
"platform": "threads",
"post_id": "3906263078447871896",
"post_url": "https://www.threads.net/@someuser/post/3906263078447871896",
"author_handle": "someuser",
"author_name": "Some User",
"text": "Just tried our-product-name for the first time and it's great!",
"published_at": "2026-05-27T11:54:28.000Z",
"like_count": 42,
"reply_count": 7,
"repost_count": 3,
"matched_views": ["relevant"],
"risk_flags": [],
"sentiment_direction": "positive",
"is_new_since_last_run": true
}

Sample summary record

{
"record_type": "summary",
"group_name": "Our Brand",
"group_type": "brand",
"new_posts": 12,
"total_posts_seen": 12,
"unique_authors": 9,
"total_likes": 847,
"total_replies": 134,
"top_post_url": "https://www.threads.net/@topuser/post/...",
"risk_post_count": 1,
"positive_post_count": 7,
"negative_post_count": 1,
"neutral_post_count": 4,
"volume_change_vs_previous_run": 4,
"top_risk_posts": [
{
"post_url": "https://www.threads.net/@x/post/1",
"author_handle": "x",
"risk_flags": ["refund"],
"engagement": 22,
"published_at": "2026-05-27T09:00:00.000Z"
}
],
"top_authors": [{ "handle": "topuser", "post_count": 3, "total_engagement": 210 }],
"top_keywords": [{ "term": "our-product-name", "count": 9 }],
"posts_by_match_type": {
"keyword": 9,
"hashtag": 0,
"profile_post": 3,
"reply": 0
},
"coverage_notes": [],
"summary_generated_at": "2026-05-27T12:03:11.000Z"
}

Sample alert records

{
"record_type": "alert",
"alert_type": "negative_post",
"severity": "medium",
"group_name": "Our Brand",
"trigger_value": 1,
"threshold": 1,
"post_url": "https://www.threads.net/@user/post/...",
"message": "1 post(s) matched risk keywords for \"Our Brand\"",
"generated_at": "2026-05-27T12:03:11.000Z",
"query": "our-product-name"
}
{
"record_type": "alert",
"alert_type": "competitor_breakout",
"severity": "high",
"group_name": "Competitors",
"trigger_value": 480,
"threshold": 200,
"post_url": "https://www.threads.net/@competitor/post/...",
"message": "Competitor \"Competitors\" broke out 2x vs previous run (engagement: 100 → 480)",
"generated_at": "2026-05-27T12:03:11.000Z",
"query": null
}

Alert types

alert_typeFires when
negative_postOne or more posts in the group matched a risk keyword this run. Gated by riskPostAlertLevel. Severity escalates with post count and risk-post engagement.
mention_spikeWhole-group volume, or a single keyword/hashtag/handle query's volume, is mentionSpikeMultiplier× the same scope's previous-run volume. Per-query spikes carry the triggering query.
competitor_breakoutA competitor-type group's volume or engagement is competitorBreakoutMultiplier× its previous-run baseline.
new_high_engagement_postThe group's top post's engagement crosses minEngagementForAlert. Severity scales with how far past the threshold the post is. Re-firing is suppressed for a previously-seen post unless its engagement increased by more than 25% since it was last tracked.

Keyword sentiment

sentiment_direction (positive, neutral, mixed, negative) is produced by simple keyword sentiment — a small fixed list of English positive/negative words matched against post text. It is not a machine-learning or multilingual sentiment model. Non-English posts will generally not match either list and will return neutral (or null when there's no text to evaluate).


When engagement fields may be unavailable

  • Handle-timeline posts (match_type: "profile_post") include full engagement metrics (like_count, reply_count, repost_count, quote_count) parsed from Threads' embedded page data.
  • Keyword and hashtag search results may have null engagement fields when Threads' search results page doesn't expose structured engagement data for a given result. The actor never fabricates a value — a null means "not available," not "zero."
  • minEngagement filtering is only applied to posts where engagement data is present; posts with null engagement always pass through the filter.

Pricing and cost estimation

This actor is billed pay-per-result: $2.00 per 1,000 dataset items on the Free plan, $1.20 per 1,000 on Business (Gold discount). Results include post, reply, author, profile, summary, alert, and run_summary records — every row in the dataset counts as one result, regardless of type. Each run also incurs a small, infrequent actor-start charge ($0.00005, scaled to actor memory) — negligible at any real run volume. Platform usage (compute/proxy overhead) is included free; you are only billed for results and the actor-start event.

ScenarioApprox. dataset items per runFree plan ($2.00/1,000)Business plan ($1.20/1,000)
1 brand + 2 competitors, 3 keywords, daily~50-170 items~$0.10-$0.34/run~$0.06-$0.20/run
5 watchlist groups, 10 keywords, hourly~300-650 items~$0.60-$1.30/run~$0.36-$0.78/run
Large campaign with 20 keywords~500-1,050 items~$1.00-$2.10/run~$0.60-$1.26/run

Residential proxy usage (recommended for keyword/hashtag search) is covered by the included platform usage above and does not add a separate line-item cost. Reply threads (includeReplyThreads) and author enrichment (includeAuthorDetails/includeAuthorContacts) increase both output size and runtime — each additional reply or author row is billed the same as a post row, so enable them only when you need that context. Use onlyNewPosts (or mode: "monitor_new_posts") on scheduled runs to minimise repeat volume and cost.


Tips

Recommended schedule for brand monitoring:

  • Daily at 08:00 UTC — morning briefing cadence
  • Use mode: "monitor_new_posts", or onlyNewPosts: true, to avoid re-processing the same posts
  • Set includeProfileStats: true to track follower count changes over time

Keyword and hashtag search quality:

  • Threads keyword/hashtag search returns posts by relevance, not strictly recency — results can vary between runs, and public search is a bounded, best-effort surface rather than a full firehose
  • Common keywords return more spam; use specific brand names, product handles, or hashtags for cleaner signal
  • Use searchCoverage: "balanced" if you want broader coverage of newer posts, at the cost of extra requests

Proxy configuration:

  • Residential proxies are pre-selected and recommended — Threads blocks datacenter IPs on search routes
  • Handle-based monitoring works without proxies; keyword/hashtag search benefits most from residential IPs

Connecting results to other tools:

  • Use Apify's Google Sheets integration to append each run's posts to a tracking sheet
  • Use the webhook trigger to POST alert records to Slack or a CRM when severity: "high"
  • Filter the dataset by record_type: "summary" for a quick daily briefing

FAQ

Does this require a Threads login? No. The actor accesses public Threads pages only. Private accounts and login-gated content are not accessible.

How many posts does it return per handle? Threads embeds only a handful of posts in the initial page load per handle. Setting maxPostsPerHandle higher than this will not return more posts — the limit is what Threads serves in the public page, not a parameter we control.

Why are engagement metrics null for some keyword/hashtag results? See "When engagement fields may be unavailable" above — this is intentional: the actor never fabricates a value it can't extract.

What languages does it support? All languages. Threads is a global platform and search results include posts in any language. Keyword sentiment detection uses English keyword matching only — non-English posts typically return sentiment_direction: "neutral" or null.

What's the difference between includeProfileReplies, includeReplyThreads, and includeReplies? includeProfileReplies includes replies that already show up in a monitored handle's own timeline — no extra fetching involved. includeReplyThreads is a separate feature that fetches each matched post's public post page and pulls its actual reply thread, emitting record_type: "reply" rows. includeReplies is a deprecated alias for includeProfileReplies, kept for backward compatibility.

Does new-post tracking work across separate runs? Yes. State (last-seen anchors and a capped seen-post-ID set) is stored in Apify's Key-Value Store, which persists between runs of the same actor. Each handle, keyword, and hashtag feed has its own anchor.

What happens if a handle doesn't exist or is private? The actor logs a warning and skips that handle. Other handles, keywords, and hashtags in the same watchlist group continue processing normally.


Support

Found a bug or have a feature request? Use the Issues tab on the actor page, or contact via the Apify Console support chat.