Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Footnote¹

Live fact-checks on your livestream, with sources, while you're still talking.

Footnote listens to a live conversation, pulls out checkable claims, verifies them against high-trust sources, and puts a broadcast-quality verdict lower-third on the stream — seconds later, with a human holding the AIR button.

Built for streamers, IRL broadcasters, debate shows, and anyone who talks about the news on camera. Verdicts are True / False / Misleading / Needs Context / Unverifiable, each with a one-line correction and a cited source — and the source is trust-tier ranked server-side, so what airs is always the most credible citation, never a Reddit thread.

Architecture

flowchart LR
    A["🎙 live audio<br/>(mic / call tab / OBS bus)"] --> B["STT<br/>Deepgram streaming"]
    B -->|"final sentence"| C["claim extraction<br/>Claude Haiku<br/>/api/extract"]
    C -->|"atomic claim (or NONE)"| D["verification<br/>Perplexity sonar-pro<br/>trust-tiered sources<br/>/api/verify"]
    D -->|"verdict + correction + source"| E["operator queue<br/>/control<br/>AIR / SKIP / HOLD<br/>(or auto-air + veto window)"]
    E -->|"AIR"| F["state channel<br/>/api/onair (Redis)<br/>per-room, write-key gated"]
    F -->|"adaptive poll"| G["/overlay<br/>transparent lower-third"]
    G --> H["OBS Browser Source<br/>or Moblin widget"]
Loading

/control (the producer console) and /overlay (the graphic) run in separate browser processes — often separate machines — and are bridged by a per-room state channel. Rooms are capability URLs: the first writer registers the room's write key, the overlay just reads. Every stage is swappable (see Plugin points).

The pipeline is deliberately human-in-the-loop: a check lands in the operator queue and only airs when a human airs it — or via confidence-gated auto-air with a veto countdown, where auto only takes definitive, high-confidence, sourced verdicts and a human can still pull anything. Airing a wrong fact-check is worse than airing none.

Quickstart A — self-host (BYOK)

Clone → keys → running control room and overlay, in about two minutes. One Node ≥ 20 process, zero npm dependencies, no external store: locally the control→overlay state channel runs in-memory inside the server.

git clone https://github.com/jordanpeele/footnote && cd footnote
cp .env.example .env      # paste your three keys (Redis not needed locally)
npm start                 # → http://localhost:3000/control  +  /overlay?room=…

Or containerized, same thing: docker compose up (mounts the repo into node:22-alpine, reads .env, serves port 3000).

Bring your own keys:

Key For Where to get it
DEEPGRAM_API_KEY streaming speech-to-text deepgram.com — must be a grant-capable key (Member scope) so the server can mint short-lived browser tokens; your key never ships to the client
ANTHROPIC_API_KEY claim extraction (Claude Haiku) console.anthropic.com
PERPLEXITY_API_KEY verification (sonar-pro web search) perplexity.ai
KV_REST_API_URL / KV_REST_API_TOKEN state channel + rate limiting (Upstash Redis) upstash.comnot needed for self-host (npm start defaults to the in-memory state channel, FOOTNOTE_STATE=memory); required on serverless deploys, or set FOOTNOTE_STATE=upstash locally to use it

Then: open /control, allow the mic, hit Start Stream, say something checkable ("the Great Wall is visible from space"), and AIR the card that lands in the queue. Add the overlay URL from the OBS OVERLAY bar as a 1920×1080 Browser Source (OBS_SETUP.md).

Quickstart B — deploy to Vercel (hosted)

Deploy with Vercel

You'll be prompted for the same five env vars as above. Installing Upstash from the Vercel Marketplace sets KV_REST_API_URL / KV_REST_API_TOKEN automatically. Your deployment serves /control and /overlay?room=… — the overlay URL goes straight into an OBS Browser Source or a Moblin Browser widget on a phone.

Plugin points

Every vendor-touching stage sits behind a small interface, with the shipping vendor as the reference adapter.

Stage Interface Reference adapter Build your own
Verifier (claim → verdict) src/core/interfaces/verifier.js src/adapters/verifier/perplexity/ — sonar-pro + trust-tier citation ranking Any search+synthesis stack (Brave/Exa + Claude, a RAG over your own archive…) — walkthrough in CONTRIBUTING.md
STT (audio → final sentences) src/core/interfaces/stt.js src/adapters/stt/deepgram/ — streaming WS, server-minted tokens Local Whisper server, another cloud STT — CONTRIBUTING.md
State channel (control → overlay) src/core/interfaces/state-channel.js src/adapters/state-channel/upstash-redis/ — REST, per-room, TOFU write key Durable Objects, plain WebSocket relay, anything that can hold {card, seq} per room — CONTRIBUTING.md
Overlay skin (card → pixels) src/core/interfaces/overlay-skin.js src/adapters/overlay/broadcast/ — the news lower-third A skin is one HTML/CSS/JS bundle that renders a card — CONTRIBUTING.md

There are drafted good first issues for one of each.

The editorial layer

The interesting part of Footnote isn't the API calls — it's the rules about what is allowed to reach the screen. Those rules are written down in HOW_FOOTNOTE_DECIDES.md: what counts as a checkable claim, why sources are tiered and social/forums are blocklisted, why corrections are phrased "per [source]" and never as bare assertion, why auto-air only takes definitive verdicts and everything spicy waits for a human.

Treat that file as the spec. Accuracy-as-spec is the differentiator here: a fact-checker that's fast but sloppy is worse than no fact-checker, so changes to the editorial policy get a higher review bar than changes to code (see CONTRIBUTING.md).

Costs, limits, receipts

This is BYOK and every check spends real money. Deepgram streaming + one Haiku call per candidate sentence + one sonar-pro call per extracted claim works out to roughly $0.50–1.00 per active streaming hour across the three APIs, depending on how talkative the stream is. The Haiku gate exists to keep the expensive verify calls down.

  • Rate limits: every API route is rate-limited per IP out of the box (api/_ratelimit.js); limits fail open if Redis is absent, so a keyless local setup runs unlimited. Tune the per-route limits at the call sites.
  • Receipts: every aired check is appended to a durable per-room log (verdict, correction, source, timestamp) — the accountability record for anything Footnote ever put on a screen. Public receipts pages render that log per stream.

Docs

Doc What it covers
OBS_SETUP.md Overlay + control in OBS, audio routing (virtual cables), producer controls
REMOTE_CALL_SETUP.md Fact-checking a remote call, phone streaming with Moblin, the street rig
HOW_FOOTNOTE_DECIDES.md The editorial policy — the spec for what airs
eval/README.md Golden claim set + calibration harness; how adapters prove themselves
CONTRIBUTING.md Running locally, building adapters and skins, review bars
BACKLOG.md Parked work and the triggers that un-park it

License

MIT

About

Real-time fact-checking for livestreams — STT finds claims, an LLM verifies against trust-tiered sources, a human airs or vetoes, and a broadcast lower-third lands in OBS seconds later. BYOK, pluggable, receipts for every aired check.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages