How Saidtree works

Every rule behind a tree, a badge, a status and the Grove, with the numbers the code uses. Nothing here is our verdict on whether a claim is true.

Last updated Wednesday, September 23

How to read a tree

A tree is one story, as told by the public accounts we track. Its root is the earliest post we track about it. Every later post from one of those accounts is a branch. Headlines from publisher feeds sit next to the tree as press, never as branches.

A sample treelet, drawn from fictional posts. The numbers match the list below.
  1. 1The root: the earliest post we track, drawn as a solid dot at the left.
  2. 2The trunk is time, from the root to the latest branch. It turns dotted when the tree stops growing.
  3. 3Each branch is one voice's post, in its segment's color: Official, Newsroom and Expert above the trunk, the others below.
  4. 4Two limbs: a fork, where the posts split into two framings.
  5. 5Ticks on the bottom edge: articles from the publisher feeds we read.
  6. 6A green ring: a branch added since your last visit.

A post joins a tree when its words are close enough to the tree's other posts, and clearly closer to that tree than to any other. We compare meaning with a text-embedding model, and fall back to shared words when that model is unavailable. Posts that match nothing start a sapling, which only editors see. A sapling becomes a public tree once it has a post from Meta and at least two independent sources. Saplings nobody plants expire after 48 hours.

A tree grows while new branches arrive. After 72 hours without one it is dormant, and after 14 more days it is archived. 180 days after its last branch it retires: the summary, post text and quotes are deleted, and the title, dates, voices and counts stay.

Root

The root is the post with the earliest time among the live branches: the time the platform gives, or for a post an editor added, the time shown on the post. An exact time beats an approximate one when they tie. Press articles are never the root.

The root line always says "first seen in the sources we track", because an earlier post may exist somewhere we can't see. When a post an editor added showed only a relative time, such as "3h", the root line says "about". When two voices posted within a minute of each other (or within an hour, when either time is approximate), we show both as the earliest posts.

Under the root we show milestones: the first official voice, the first newsroom, the first first-hand post and the first article, each as time after the root. When an article came before every post we track, we say so. If an earlier post is added at least 5 minutes before the root, or the root post is removed, the root moves, and the tree says so in its rings.

Voices

We count voices, not posts: an account that posts ten times counts once. Every voice sits in one segment, always shown in the same order: Official, Newsroom, Expert, Advocacy, Creator, Public and Unknown. Official includes organizations speaking for themselves.

A tree can show up to two missing-voice notes: "No official voice yet", "No newsroom yet" or "Only creators so far". They appear only after a tree is 2 hours old, and "No official voice yet" only on topics where an official voice is expected.

Members of the public are counted, never named: a list says "3 members of the public".

Forks

Some stories split: part of the voices tell it one way, part another. Once a tree has 6 branches with text from at least 4 voices, Claude groups the posts by their own wording into at most two framings. Each branch it assigns must come with a quote that appears word for word in that post, or the assignment is dropped.

We show a fork only when each framing has at least 2 voices and at least 20% of the assigned branches. The framing names are AI-written and labelled that way; each framing is backed by quotes from the posts. Framing names never appear in rings, titles or emails. An editor can rename or lock a framing, and a renamed framing loses its AI label.

Depth: shallow roots and deep roots

Depth compares how loud a story is with how well it is sourced. It looks at the tree's last 7 days.

  • Loudness adds up the voices on the tree, weighted by reach: small accounts count 1, mid 2, large 3 and mass 4. It is compared with every tree that grew this week, once there are at least 10; before that, fixed cut-offs apply.
  • Primary material is the share of labelled posts that are official statements, first-hand posts or documents.
  • Reporting counts newsrooms on the tree and outlets in the publisher feeds, each organization once.
  • Depth is half primary material (full marks at 50%) and half reporting (full marks at 4 organizations), from 0 to 1.

A tree gets Shallow roots when it is in the loudest quarter of the week, its depth is below 0.30 and it has at least 5 voices. It gets Deep roots when it is in the quieter half, its depth is at least 0.65 and it has at least 2 primary posts. Each badge needs a clear change to go away again, so it doesn't flicker. Other trees get a plain line instead: "Loud and well sourced, with little reporting yet", "Talked about and reported", or "Neither unusually loud nor unusually quiet".

Every depth line carries its caveat: this compares attention, not truth, and coverage outside the sources we track is not counted. A tree's "Why?" drawer shows every number against its threshold.

Depth is rated only when our coverage is good enough. Facebook Pages must have been connected for the tree's whole life (up to 48 hours), we must read at least 100 Facebook Pages automatically, at least 80% of our news feeds must have been fetched in the last 2 hours, and post labels must have passed their accuracy check. Otherwise the tree says "Depth not rated" and gives the reason. A tree also needs 3 labelled posts, 3 voices and 2 hours of age before it is compared.

Status

Every tree has exactly one status from a fixed list. A status describes what the voices we track have posted. It is never our ruling on whether a claim is true.

The seven statuses a tree can have
StatusWhat it meansSet by
Unverified claimWhat the voices we track have posted has not been backed by enough independent accounts yet.A rule
Eyewitness post — not independently verifiedSomeone posted what they saw first-hand, and two or fewer independent accounts back it.A rule
Corroborated (N independent accounts)Corroborated means N separate organizations or accounts reported or stated it. It does not mean we checked it.A rule
Confirmed by official accountAn editor confirmed an official account's own statement as the evidence, and at least two independent sources carry the story.An editor
DisputedAn editor recorded which branch disputes the claim, and why.An editor
Recycled mediaAn editor linked an earlier upload of the same photo or video. That branch is never used as evidence.An editor
CorrectedWe published a correction, or an editor confirmed that a voice corrected its own post.An editor

Rules are checked in order: an editor's status first, then the emergency window, then Corroborated, then Eyewitness, and otherwise Unverified claim. Corroborated counts independent organizations or accounts with evidence, so reshares and aggregators don't count, and several accounts of one organization count once. "Corroborated" means that many separate organizations or accounts reported or stated it. It does not mean we checked it.

A tree resting on a single independent source can never be Corroborated or Confirmed by official account. If an editor's status loses its evidence, it is suspended until an editor looks again. Every status change is listed on the tree under "Changes to this tree".

In an emergency, for the first 60 minutes after the root, a tree shows only what official accounts said, no AI text, and the "Developing" chip.

Rings

Rings show what changed on a tree since you last looked. Each ring comes from a fixed sentence template, such as "Root moved", "An official voice joined", "Now reported by 5 outlets" or "Status: Unverified claim → Corroborated". Rings are never written by AI.

We know when you last looked from your account if you're signed in, or from this device's own storage if you're not. The first time you see a tree, rings count from when the day's Grove was published. New branches are folded into one line, such as "+4 branches from 3 voices", and never counted as rings on their own. When a post is removed, the ring says only that a post is no longer available, never which one.

A pruned ring means an editor confirmed a correction: a voice corrected, withdrew or edited its own post, or we corrected our summary. Code can propose a prune, but only an editor confirms one. A removed post is never called pruned.

For stories about government, elections, courts, health, the economy or the environment, or with official or advocacy voices, we check Meta's Ad Library for US political and issue ads from the tree's voices, or with wording an editor chose. Every result waits for an editor: an ad appears on a tree only after an editor confirms it is about that story.

Spend and impressions are the ranges Meta reports, never exact amounts, and different currencies are never converted. "Paid for by" is the advertiser's own disclaimer. Ad text is never sent to Claude, and it is deleted once an editor decides.

The Grove

The Grove is one short, finished edition a day, with at most 12 trees. Code suggests an order; editors choose, reorder and approve, and only trees with an editor-written title can be published.

A tree is a candidate when it is public, has at least 3 voices and grew in the last 36 hours. A tree from yesterday's edition returns only with at least 2 new rings, marked "Still growing". The suggested order is:

  • 30% how loud the tree is this week,
  • 30% its depth,
  • 20% freshness (a root under 24 hours old counts fully, under 48 hours half),
  • 20% momentum (new voices in the last 12 hours, full marks at 5).

When a tree's depth can't be rated, freshness and momentum count half each. Loudness and depth weigh the same, so the Grove is not a list of what is loudest. Filling it, we take at most 3 trees per topic, keep 2 places for Deep roots trees when there are any, and allow at most 2 Shallow roots trees, which always show their badge.

Code proposes the edition at 5:00 am ET. Editors publish it when it's ready; at 7:00 am ET, the approved trees are published in the suggested order. After that the edition never changes, except that a tree taken down is marked in place.

AI-written summaries

Summaries and framing names are written by Claude, by Anthropic, and are always labelled "AI-written". Titles are never written by AI: an editor writes them, or they quote a post word for word.

What Claude reads: the text of public posts from organizations and public voices on the tree, and quotes our editors typed from such posts, up to 40 posts per summary. What Claude never reads: posts by members of the public, editor notes, anything readers send us, Meta's embeds, radar results, Ad Library data, press headlines, and posts that name a private person or identify a minor.

A summary has 2 to 5 sentences of at most 40 words each. Every sentence must cite the posts it came from, and each citation must match the post's text exactly. Then every sentence is checked twice:

  • By code: a sentence without a citation, with a citation that doesn't match, naming a member of the public, using the words we never use, or, in an emergency's first hour, stating casualty numbers, a perpetrator or a motive, is dropped.
  • By a second Claude call that reads each sentence with only its cited text: a sentence that is only partly supported, or not supported, is dropped. A sentence that makes an allegation about a person becomes a direct quote from the post instead.

A summary is published only when at least 2 sentences survive and no more than 30% were dropped. Otherwise the tree shows attributed quotes instead. Each time a page loads, a sentence is shown only while every post it cites is still live and still says the same words.

Summaries are rewritten when at least 2 new posts arrive, at most every 30 minutes and 12 times a day, and at once when a cited post is edited or removed. Trees held for review, and trees in an emergency's first hour, show quotes only until an editor approves.

Claude, by Anthropic, writes every AI text on Saidtree.

What Claude does on Saidtree, and how it is set up
TaskModelEffortPrompt version
Summariesclaude-opus-5highsummarize.v1#c87ca4bb6007
Checking summaries against their postsclaude-opus-5highverify.v1#8eba446ba967
Post labelsclaude-opus-5lowclassify.v1#5c7908e5386c
Framingsclaude-opus-5mediumframing.v1#8e0cd4221f1f
Proposed voice typesclaude-opus-5lowvoice.v1#1aa9481266d9

Latest eval

The eval hasn't been run and committed yet. Until it passes, a prompt or model change can't ship.

The bar is 1%: a prompt or model change can't ship above it.

Post labels

Each post gets labels: how close its author is to the events (official statement, first-hand, document, reporting or commentary), whether it is original, a reshare or an aggregation, how it shows its sources, and what kind of work it is (news, analysis, opinion, sponsored, satire). An editor's label always wins, then a fixed rule, then Claude's. Claude must quote the words that justify each label, and a label whose quote isn't in the post is discarded.

The two-person gold set isn't finished yet, so no κ is published and classifier labels aren't shown on trees.

Classifier labels are shown on trees only when every label reaches κ 0.70.

Our sources

Where we are now

Facebook Pages: not connected yet. We've applied for Meta's approval. Until then, posts appear when an editor adds them.

0 Facebook Pages read automatically · 131 publisher feeds · 0 accounts whose posts editors add

Facebook Pages
Posts from the public Facebook Pages in our list, read automatically through Meta's Page Public Content Access once it is approved. We keep the text and the reaction, comment and share totals; never photos, videos or comments.
Instagram, Threads and other Facebook posts
Added by editors, from links they find or readers send. We keep the link, the time shown on the post, an editor's note and an optional quote the editor typed. The post itself loads through Meta's own embed, only when a reader asks.
Threads radar
Private searches readers run with their own Threads account. Results are shown only to them and never feed Saidtree.
Publisher feeds
Headlines from publishers' RSS feeds, as a baseline to compare against. Headlines only, never articles.
Meta Ad Library
US political and issue ads, shown on a tree only after an editor matches them to it. Spend and reach are the ranges Meta reports.

How each source is doing

Each source, its state and its limits
SourceStateSinceLast successLimits
Facebook PagesOffSep 23, 11:39 pm ETNeverBusy Pages every 15 min, others every 60 min or 6 h; slow polls pause at 80% of Meta's rate limits
Instagram and Threads embedsOffSep 23, 11:39 pm ETNeverAt most 900 embeds an hour per platform, only when a reader chooses Show post
Threads radarOffSep 23, 11:39 pm ETNeverAt most 200 searches a day per reader, with the reader's own account
Publisher feedsOffSep 23, 11:39 pm ETNeverEach feed at most every 15 min; headlines only
Meta Ad LibraryOffSep 23, 11:39 pm ETNeverAt most 100 requests an hour; US political and issue ads only

A source can be off, sample data, testing, live, degraded (no success for three times its usual interval), paused, or access stopped (Meta withdrew permission). A source runs only when its credentials exist, an admin turned it on, and the site is running on real data.

No source changed state in the last 90 days.

How Meta approvals work

Reading public Facebook Pages automatically needs Meta's Page Public Content Access, granted after business verification and an app review. Instagram and Threads posts can only be shown through Meta's own embeds, so our editors add them one by one. Searching Threads needs Meta's approval for keyword search; when it is granted, readers search with their own Threads account and the results stay private to them. Saidtree is not affiliated with or endorsed by Meta.

What we can't see

  • Private accounts and private posts.
  • Facebook groups and personal profiles. Meta offers no way for apps like ours to read them.
  • Reels posted by other Facebook Pages.
  • Instagram personal accounts, and Instagram posts nobody has added.
  • Threads posts nobody has added.
  • Every post from busy Facebook Pages. Facebook's API returns about 600 posts per Page per year.
  • Posts deleted before we saw them, and anything outside the sources we track.
  • Paid promotion other than US political and issue ads.
  • Community Notes. Meta doesn't make them available to apps like ours.

Privacy tiers

  • Tier A: government bodies, companies, nonprofits, media outlets, elected officials and public figures posting in that role. They can be named in AI text and quoted, and they have a page on Saidtree.
  • Tier B: semi-public voices, such as local officials, creators and commentators with a large audience, posting on public matters. They are named and quoted on the public matter only, and they have no page.
  • Tier C: members of the public, eyewitnesses included. They are never named, their posts are never sent to AI, and they have no page. Their posts appear only through Meta's embed, when a reader asks. An editor may quote one only when it is the only first-hand account of something newsworthy, and never with the handle.

Deletion

We check whether posts still exist: on every poll for a Facebook post's first 48 hours, then every 6 hours for a week, daily for a month, and weekly after that until the tree retires. A post an editor added is checked when readers report that it no longer loads.

When a post is gone, or someone asks us to remove it, we delete its text, quotes and links, drop every summary sentence that cited it, recompute the tree, and rewrite the summary. If the tree is left with fewer than 2 independent sources, we take it down. Our target is under 1 hour from a confirmed removal to a clean page, and never more than 24 hours.

How long we keep each kind of data
DataKept for
Facebook Page post text and counts not attached to any public tree72 hours
Facebook Page post text and counts on branches of public treesUntil the tree retires (180 days after its last branch) or the post is removed
Curated typed quotes30 days after the tree goes dormant
Editor notesUntil the tree retires
Press headlines not matched to a tree / matched14 days / until the tree retires
EmbeddingsSame as their item
Ad records: confirmed / rejected or unmatched candidates / creative textUntil the tree retires / 30 days / deleted on decision (a hash is kept)
Radar hit IDs and shortcodes7 days; immediately on disconnect or account deletion
Threads tokensUntil disconnect, deletion, a Meta callback, or 90 days of radar inactivity
AI run logs12 months, with cited text redacted when a post is removed
Tips and trace sends / their emails90 days after closing / 30 days
Error reports / their emails12 months after resolution / 30 days after resolution
Data-rights requests and takedown notices / their contact details3 years after closing / reduced to a salted hash 30 days after closing
Meta callback records12 months
Ingest run records and error text90 days
Tombstones12 months
Audit log3 years, append-only; holds ids, enums and hashes only, never post text or contact details
Suppression hashesIndefinitely
Account dataUntil you delete your account

Every number we use

These are read from the same file the code reads, so this page can't fall out of date. They are starting values, tuned on sample data; every change is logged below.

Every threshold the engine uses
NameValueWhat it doesWhere
JOIN / ​JOIN_MARGIN / ​PRESS_JOIN0.8 / 0.03 / 0.78Similarity a post or headline needs to join a tree, and how far ahead of the next tree it must be.How to read a tree
JOIN_LEX / ​PRESS_JOIN_LEX0.3 / 0.28The same, when word overlap is used instead of embeddings.How to read a tree
REGROW / ​MERGE0.85 / 0.86Similarity to wake a dormant tree, and to merge two saplings overnight.How to read a tree
REGROW_LEX / ​MERGE_LEX0.35 / 0.36The same two, when word overlap is used instead of embeddings: the same distance above the joining threshold.How to read a tree
ENTITY_BONUS / ​ENTITY_BONUS_MAX0.04 / 2Added to the similarity for each name a post shares with a tree, for at most this many names.How to read a tree
SAPLING_TTL_H / ​DORMANT_H / ​ARCHIVE_D / ​RETIRE_D48 h / 72 h / 14 d / 180 dHow long a sapling waits to be planted, and when a quiet tree goes dormant, is archived and retires.How to read a tree
NEEDS_BRANCHES_OUTLETS5Outlets a press-only cluster needs before editors are asked to look for posts.Our sources
NEAR_TIE_EXACT_MIN / ​NEAR_TIE_APPROX_MIN1 min / 60 minTwo earliest posts this close together are shown as a near-tie.Root
ROOT_MOVE_MIN5 minHow much earlier a new post must be to move the root.Root
FORK_MIN_BRANCHES / ​FORK_MIN_VOICES6 / 4Text-bearing branches and voices a tree needs before we look for a fork.Forks
FRAMING_MIN_VOICES / ​FRAMING_MIN_SHARE / ​MAX_FRAMINGS2 / 20% / 2Voices and share of branches each framing needs, and the most framings shown.Forks
REACH_WEIGHTsmall 1, mid 2, large 3, mass 4, unknown 1How much each voice adds to loudness, by reach.Depth: shallow roots and deep roots
POP_MIN10 treesTrees needed this week before loudness is compared by percentile.Depth: shallow roots and deep roots
LOUD_PCT_ON / ​LOUD_PCT_OFF0.75 / 0.65Loudness percentile to enter and leave shallow roots.Depth: shallow roots and deep roots
QUIET_PCT_ON / ​QUIET_PCT_OFF0.5 / 0.6Loudness percentile to enter and leave deep roots.Depth: shallow roots and deep roots
LOUD_ABS / ​QUIET_ABSL ≥ 12 / L ≤ 6Loud and quiet while fewer than POP_MIN trees exist.Depth: shallow roots and deep roots
LOUD_ABS_OFF / ​QUIET_ABS_OFFL < 10 / L > 8Where those badges are lost again.Depth: shallow roots and deep roots
SHALLOW_D_ON / ​SHALLOW_D_OFF / ​SHALLOW_MIN_VOICES< 0.3 / ≥ 0.4 / 5Depth to enter and leave shallow roots, and voices needed.Depth: shallow roots and deep roots
DEEP_D_ON / ​DEEP_D_OFF / ​DEEP_MIN_PRIMARY≥ 0.65 / < 0.55 / 2Depth to enter and leave deep roots, and primary posts needed.Depth: shallow roots and deep roots
DEPTH_MIN_LABELLED / ​DEPTH_MIN_VOICES / ​DEPTH_MIN_AGE_H3 / 3 / 2 hLabelled posts, voices and age before depth is compared.Depth: shallow roots and deep roots
GATE_WINDOW_H / ​GATE_MIN_PPCA_VOICES / ​GATE_FEED_HEALTH48 h / 100 / 80%Coverage we need before any depth badge is shown.Depth: shallow roots and deep roots
CORROBORATED_MIN3Independent accounts with evidence needed for Corroborated.Status
CRISIS_WINDOW_MIN60 minHow long an emergency tree shows only official quotes and no AI text.AI-written summaries
GROVE_MAX / ​GROVE_TOPIC_MAX / ​GROVE_DEEP_RESERVE / ​GROVE_SHALLOW_MAX12 / 3 / 2 / 2Grove size, trees per topic, slots kept for deep roots, and the most shallow-roots trees.The Grove
SUMMARY_SENTENCES / ​SENTENCE_MAX_WORDS / ​SUMMARY_MIN_KEEP / ​SUMMARY_MAX_DROP2–5 / 40 / 2 / 30%Summary length, sentence length, and when a summary is withheld.AI-written summaries
SUMMARY_MAX_DOCS / ​REGEN_MIN_INTERVAL_MIN / ​REGEN_MAX_PER_DAY40 / 30 min / 12Posts a summary may read, and how often it may be rewritten.AI-written summaries
QUOTE_MAX_CHARS / ​QUOTE_MAX_SENTENCES / ​NOTE_MAX_CHARS / ​TITLE_MAX_CHARS300 / 2 / 280 / 90The longest quote, editor's note and title we show.AI-written summaries
PAID_SIM / ​PAID_SIM_LEX0.7 / 0.25Below this, a wording match to an ad is shown as weak.Paid branches
OEMBED_BUDGET_H / ​OEMBED_READER_H / ​OEMBED_DESK_H900 / 800 / 100Embeds per hour per platform, for readers and for editors.Our sources
TEND_MAX / ​RADAR_SEARCH_MAX / ​ANON_SEEN_MAX100 / 10 / 200Trees you can tend, saved radar searches, and trees remembered on a device.Rings
DRAW_MAX_BRANCHES / ​TREELET_MAX_DOTS80 / 40Branches drawn in the tree view and dots in a treelet; all branches are always listed.How to read a tree

Changes

No threshold has changed since launch: every value above is its starting value.

No voice label has been changed after a dispute.