FactGuard β Devlog #1
Time logged: 1hr 19min
FactGuard is a browser extension that injects credibility badges into Google Search results and provides a full verification popup for any webpage or chat platform. Built with WXT + Svelte on the frontend and FastAPI + OpenAI on the backend.
Architecture
Three-part system:
- Browser extension (WXT + Svelte) β badges, popup UI, chat scraping
- FastAPI backend on Google Cloud Run β crawling and AI verification via OpenAI
- Next.js web app β forum/reporting interface
The extension runs a crawl β summarize β verify_content pipeline, with domain-level fast verification for Google Search badges separately via domain_verify.
Features Shipped
Google Search badge injection
Injected verification badges directly into Google Search result cards using querySelectorAll('cite') and DOM traversal to find result headings. Badges show one of three states: Likely Accurate, Unverified, or Potentially Misleading β each with SG/non-SG variants (6 SVG badge assets total).
Popup verification flow
Full credibility review in the extension popup: crawls the active tab, runs AI verification, and renders verdict, reasoning, supporting/contradicting sources, comparison against a reliable benchmark source, and contextual flags (missing context, potential risks). Supports English, Malay, Tamil, Korean, and Chinese.
Chat platform verification
Detects when the active tab is Facebook, Messenger, Telegram, or WhatsApp. Scrapes visible messages via platform-specific DOM selectors, lets the user select which messages to analyze, and runs the same verify pipeline on the excerpt. Suspicious results trigger a report flow that submits to the FactGuard web app.
Login + session
JWT-based login flow persisted in browser.storage.local. Auth state guards all verification features.
Optimisation
-
24hr cache TTL β Verified results stored in
browser.storage.local under a url::language composite key. On read, entries older than 24hrs are evicted immediately rather than served stale.
-
URL + language cache key β Cache is per
(url, language) pair so switching languages always fetches fresh results without polluting other language caches.
-
150ms debounce on MutationObserver β Google Search updates the DOM frequently on scroll/pagination. All mutation callbacks funnel through
scheduleInject with a 150ms debounce to batch DOM work and avoid thrashing.
-
Priority URL sorting β Newly added DOM nodes (from mutations) have their URLs extracted and sorted to the front so freshly loaded results get badges faster than already-processed ones.
-
AbortController timeout β Domain verify requests are cancelled after 8 seconds via
AbortController so stale network calls donβt block the badge queue.
-
Shared async OpenAI client β Backend reuses a single
AsyncOpenAI instance per module rather than constructing one per request, reducing connection overhead.
Backend
FastAPI with three active endpoints (/crawl, /verify_content, /domain_verify), rate limiting per IP with a sliding window counter, shared-secret auth via X-FactGuard-Key header, and structured JSON responses parsed from OpenAI prompt outputs. /verify kept for backwards compat but marked deprecated with Sunset: 2025-12-31 headers.
Testing
Unit tests cover cache TTL logic, config URL normalization (trailing slash handling), auth storage read/write/clear, login API success and error paths, and chat domain detection. Backend tests cover middleware auth, deprecation headers, and JSON parse guards on all three OpenAI wrappers.