Track Fact-Checks on Viral X Posts With Community Notes
Check whether specific X posts carry Community Notes — summary, reasons, showing status — as JSON, for reporting and moderation research.

TL;DR — The X Community Notes Scraper checks whether specific posts carry Community Notes — the fact-check text, reasons, and whether it's showing. Pass post IDs, get the notes dataset's answer as JSON. No login needed.
Why "is this post fact-checked" should be a lookup
When a claim goes viral, the question for researchers, moderators, and journalists is whether the crowd has already evaluated it. Community Notes does that evaluation — but finding whether a given post carries a note means either eyeballing X or parsing a giant TSV.
The job-to-be-done: a lookup — post ID in, note record out.
How does this compare to the alternatives?
| Checking on X | Bulk TSV grep | Thirdwatch actor | |
|---|---|---|---|
| Cost | Free, one at a time | Free + pipeline | Pay per result |
| Reliability | Manual | Full data, heavy lift | Filtered lookup |
| Setup time | Zero | Hours | Minutes |
| Maintenance | Per post | Pipeline upkeep | Handled |
How to check posts in 4 steps
How do I look up a post list?
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("thirdwatch/x-community-notes-scraper").call(
run_input={
"tweetIds": ["1834560000000000000", "1834570000000000000"],
"includeStatus": True,
"maxResults": 100,
}
)
notes = list(client.dataset(run["defaultDatasetId"]).iterate_items())How do I map notes to posts?
by_post = {n["tweetId"]: n for n in notes}
for tid in tweet_ids:
n = by_post.get(tid)
print(tid, "->", (n["isShowingOnX"], n["summary"][:80]) if n else "no note")Posts with no record carry no community fact-check — the distinction matters for "unchecked claim" stories.
How do I read the fact-check?
summary is the note's text; reasons gives the structured why — misleadingFactualError, misleadingOutdatedInformation, etc. trustworthySources marks notes that cite sources.
How do I track status over time?
Notes move through rating states — snapshotDate pins the dataset version; rerun over time and statusLabel/isShowingOnX show when a correction actually became visible.
Sample output
{"noteId": "1834567890123456789", "tweetId": "1834560000000000000",
"tweetUrl": "https://x.com/i/status/1834560000000000000",
"summary": "This image is from a 2019 incident, not current events.",
"classification": "MISINFORMED_OR_POTENTIALLY_MISLEADING",
"isMisleading": true,
"reasons": ["misleadingOutdatedInformation", "misleadingMissingImportantContext"],
"trustworthySources": true, "isMediaNote": true,
"createdAt": "2026-08-14T09:20:00Z",
"status": "CURRENTLY_RATED_HELPFUL", "isShowingOnX": true,
"statusLabel": "Currently rated helpful"}Common pitfalls
A note can exist but not be showing — isShowingOnX is the field that matters for "users see this correction." The dataset lags real-time — notes minutes old may not appear yet. Deleted posts keep their note records — useful for removal studies, confusing otherwise. Lookups return what X's public dataset holds; private or region-limited surfaces aren't in scope.
Related use cases
Frequently asked questions
How do I check whether a specific post has a note?
Pass its ID in tweetIds — the actor returns the note record if one exists: the fact-check text, its reasons, and whether it's currently rated helpful enough to show.
Does it tell me the note is actually visible?
With includeStatus on, each record carries status, isShowingOnX, and statusLabel — notes under rating scrutiny differ from notes currently displayed.
Can I check a list of posts at once?
Yes — tweetIds is an array. A viral-claims list becomes a lookup table in one run.
What if a post has no note?
It simply returns no record for that ID — absence is the finding: no community fact-check exists in X's public dataset.