PrivacyGPT tracks how major AI companies handle conversational data — training practices, opt-out options, data retention, deletion rights, third-party sharing, and human review policies. Each datapoint is sourced from primary-source privacy policies and verified.
The dashboard lets you compare companies side by side, filter by privacy stance, and get a weighted score based on what matters to you. An automated watchdog monitors policy pages for changes and surfaces them in a changelog with AI-powered review and admin workflow.
- Comparison Dashboard — Score cards, multi-condition filters (trains on data? opt-out available? no human review?), and search across 40+ AI companies
- Weighted Scoring — Adjust the importance of six privacy categories; scores update in real-time with letter grades (A–D)
- Company Profiles — Deep-dive pages with score breakdown, citation sources, verification badges, and raw privacy stance data
- Side-by-Side Comparison — Select multiple companies and compare their privacy profiles directly
- Automated Watchdog — Cron-scheduled pipeline fetches privacy policy URLs daily, detects changes via content hashing, and queues entries for admin review
- AI-Powered Review — Cloudflare Queue-based system automatically reviews changelog entries for breaking changes and policy updates using AI
- Changelog with Admin Workflow — Review pending changes, approve or reject, add notes, and notify subscribers
- Email Subscriptions — Double opt-in subscription system for changelog alerts per company
- Methodology & Scoring Rubric — Transparent documentation of how scores are calculated, with verification confidence ratings and FAQ
- Admin CRUD — HTTP Basic Auth protected interface for managing companies and changelog entries
- PWA Support — Service worker with cache-first strategies for offline access
- Dark Mode — Light/dark/system theme toggle with localStorage persistence
- Atom & RSS Feeds — Auto-discoverable changelog feeds
flowchart TD
Browser["Browser\n(React 19)"]
Worker["Cloudflare Worker\n(TanStack SSR)"]
D1["D1 Database\n(libsql)"]
Watchdog["Watchdog (Cron)\nfetches & diffs"]
WatchdogQueue["Watchdog Queue\n(async processing)"]
AIReviewQueue["AI Review Queue\n(async review)"]
DLQ["Dead Letter Queue\n(failed reviews)"]
Browser --> Worker
Worker --> D1
subgraph WorkerInternal [" "]
Router["Router\n(TanStack Start)"]
ServerFns["Server Functions\n(API)"]
Watchdog["Watchdog (Cron)\nfetches & hashes"]
end
Worker -.-> Router
Worker -.-> ServerFns
Worker -.-> Watchdog
Worker --> WatchdogQueue
Worker --> AIReviewQueue
Watchdog --> D1
WatchdogQueue --> D1
WatchdogQueue -.->|failures| DLQ
AIReviewQueue --> D1
AIReviewQueue -.->|failures| DLQ
The app runs on Cloudflare Workers with server-side rendering via TanStack Start. Data is fetched through createServerFn calls — no direct database access from the client. A scheduled cron trigger runs the watchdog daily, which fetches privacy policies, detects changes via content hashing, then queues results for AI-powered review and admin workflow. The AI review system processes changelog entries asynchronously via Cloudflare Queues with automatic retry and dead letter queue handling.
Note
In development, the database runs on a local libsql (SQLite) file. In production, it uses Cloudflare D1. The same codebase handles both transparently via getDb().
| Layer | Technology |
|---|---|
| Runtime | Bun (dev) / Cloudflare Workers (prod) |
| Framework | TanStack Start (React 19 + TypeScript 6) |
| UI | Tailwind CSS v4 + shadcn/ui |
| Database | libsql (dev) / D1 (prod) via Drizzle ORM |
| Queues | Cloudflare Queues (async processing with dead letter queues) |
| State | TanStack React Query (SSR with 5-min stale time) |
| Routing | TanStack Router (file-based, SSR) |
| Testing | Vitest |
| CI/CD | GitHub Actions → Cloudflare Workers via Wrangler |
- Bun >= 1.0
# Clone the repository
git clone https://github.com/<your-org>/privacygpt.git
cd privacygpt
# Install dependencies
bun install
# Copy environment variables and fill them in
cp .env.example .env
# Seed the database with company privacy data
bun run src/lib/db/seed.ts
# Start the development server
bun run devThe app will be available at http://localhost:3000.
The file src/lib/db/seedData.json is an initial snapshot used to bootstrap or reset the database. Live updates to company privacy data are applied directly to the database via the admin review workflow.
To manually add a new company or perform a full environment reset:
- Edit
seedData.json - Run
bun run src/lib/db/seed.ts - Run
bun run testto verify structure
bun run test # Run vitest suite
bun run lint # Lint with ESLint
bun run typecheck # Verify TypeScript compilation
bun run format # Format with Prettiersrc/
├── routes/ # TanStack Start file-based routing
│ ├── __root.tsx # Main layout (navbar, footer, theme toggle)
│ ├── index.tsx # Comparison dashboard
│ ├── compare.tsx # Side-by-side comparison
│ ├── company.$companyKey.tsx # Company profile
│ ├── methodology.tsx # Scoring rubric & FAQ
│ ├── changelog.tsx # Policy changelog feed
│ ├── changelog.feed[.]xml.ts # Atom/RSS XML feed
│ ├── admin.tsx # Admin CRUD interface
│ ├── blog.index.tsx # Blog listing page
│ ├── blog.$slug.tsx # Individual blog post
│ ├── blog.feed[.]xml.ts # Blog RSS feed
│ ├── sitemap[.]xml.ts # Sitemap XML endpoint
│ ├── faq.tsx # FAQ page
│ ├── privacy.tsx # Privacy policy page
│ └── terms.tsx # Terms of service page
├── components/
│ ├── ui/ # shadcn/ui components
│ ├── CompanySelect.tsx
│ ├── CompanyLink.tsx
│ ├── CompareScores.tsx
│ ├── CompareSection.tsx
│ ├── ThemeProvider.tsx
│ └── ThemeToggle.tsx
├── lib/
│ ├── db/ # Drizzle schema, seed data, client
│ ├── __tests__/ # Vitest test suites
│ ├── api.ts # Server functions (createServerFn)
│ ├── ai-reviewer.ts # AI-powered changelog review logic
│ ├── blog-data.ts # Blog post metadata
│ ├── queries.ts # TanStack Query hooks
│ ├── scoring.ts # Scoring engine (6 weighted categories)
│ ├── utils.ts # Classnames merge helpers
│ └── watchdog.ts # Policy change detection pipeline
├── content/blog/ # MDX blog posts
├── styles.css # Tailwind v4 + custom theme
├── router.tsx # Router configuration with SSR hydration
└── entry.ts # Cloudflare Worker entry point
Users can adjust the relative importance of six scoring categories via the dashboard weights panel. Changes recalculate scores and letter grades instantly on the client side.
| Category | Default Weight | Description |
|---|---|---|
| Training Data | 30% | Does the company train on user conversations by default? |
| Opt-Out | 20% | Can users opt out of training data use? |
| Data Retention | 15% | How long is conversational data retained? |
| Deletion | 15% | Can users request deletion of their data? |
| Third-Party Sharing | 10% | Is data shared with third parties for training? |
| Human Review | 10% | Are conversations reviewed by humans? |
The project is designed for Cloudflare Workers. Deploy with:
# Deploy main application
npx wrangler deployConfiguration is in wrangler.jsonc (main app and scheduled cron triggers).
| Variable | Description |
|---|---|
ADMIN_USERNAME / ADMIN_PASSWORD |
HTTP Basic Auth for admin interface |
APP_URL |
Public application URL |
FIRECRAWL_API_KEY |
API key for Firecrawl JS fallback scraper |
AI_REVIEW_ENABLED |
Enable AI-powered changelog review (default: true) |
The application uses two Cloudflare Queues for async processing:
| Queue | Purpose |
|---|---|
privacygpt-watchdog-queue |
Processes watchdog change detection results |
privacygpt-watchdog-dlq |
Dead letter queue for watchdog change detections |
privacygpt-ai-review-queue |
AI-powered changelog entry review |
privacygpt-ai-review-dlq |
Dead letter queue for failed AI reviews |
Queues are automatically created during CI/CD deployment.
When modifying the Drizzle schema in src/lib/db/schema.ts:
# Generate SQL migrations
npx drizzle-kit generate
# Push changes to local database
npx drizzle-kit push