Slopwatch 🤖🔎
“Wait… did a human actually write this, or is it slop?”
Slopwatch is a one-click browser extension that reads the page you’re on and gives you a probabilistic second opinion on whether the text was AI-generated — an overall score, a calibrated label, the model’s reasoning, and paragraph-level highlights you can hover for a per-paragraph rationale.
It is Firefox-first (Chromium second), Manifest V3, and built to be honest about a genuinely hard problem.
What makes it different
- Inert by default. It does nothing — no scanning, no network, no permissions used — until you click the toolbar robot.
- Bring your own model. Plug in an Anthropic key, any OpenAI-compatible endpoint, or a local Ollama model so nothing leaves your machine.
- Never a bare verdict. Score and label and reasoning, together, always — with a permanent Uncertain band that can’t be configured away.
- You can see where your data goes. A persistent indicator tells you, every run, whether analysis ran in the cloud or on your device.
How it works
Click the icon → it grabs temporary read access to the current tab (activeTab,
nothing broader) → extracts the primary content (Readability for articles, per-platform
extractors for feeds) → sends it to your chosen model → shows an overall AI-likelihood
score, a label, the reasoning, and highlights the suspicious paragraphs in place.
A note on what this is — and isn’t
LLM-based “is this AI?” detection is genuinely unreliable, with real false-positive and false-negative rates, and is biased against formal, template-following, or non-native-English writing. Slopwatch is built to make that honest — and it never labels people, only text. See Responsible use.
Install
From the store (recommended)
Once Slopwatch is listed, open its page in Firefox and click Add to Firefox. That’s it — updates happen automatically. (Chromium: Add to Chrome.)
From source (developers)
git clone https://github.com/DisplaceTech/slopwatch
cd slopwatch
corepack enable
pnpm install
pnpm build:firefox
Then load it in Firefox:
- Open
about:debugging→ This Firefox. - Load Temporary Add-on…
- Pick
.output/firefox-mv3/manifest.json.
(For Chromium: pnpm build, then chrome://extensions → enable Developer mode →
Load unpacked → pick .output/chrome-mv3.)
Temporary add-ons reset when the browser restarts — fine for trying it out. For a permanent, auto-updating install, use the store listing.
First run
- Click the robot in the toolbar.
- The popup opens. Open Settings to pick a provider and add a key — or just try the offline Mock provider to see the flow.
- Click Run analysis on this page on any article.
Next: choose a provider.
Choosing a provider
Slopwatch doesn’t ship a model — it uses one you choose, configured in Settings.
Anthropic
A cloud model from Anthropic. Best quality-for-effort default for most people.
- Settings → select Anthropic.
- Paste your API key. It’s stored session-only by default (cleared when the browser restarts) unless you opt into saving it.
- Leave the model at
claude-haiku-4-5(cheap and capable) or set your own. - Click Test connection.
Your key goes directly from your browser to Anthropic and is never sent to any Slopwatch server (there isn’t one). Because the key is used client-side, prefer a scoped/limited key. The popup shows ☁️ Cloud for this path.
Ollama (local)
Run a model on your own machine — nothing leaves your device. The popup shows 🔒 Local.
- Install and run Ollama, and pull a model (e.g.
ollama pull qwen3:4b). - Settings → select Ollama, base URL
http://localhost:11434. - Click Fetch models and pick one; Test connection.
Fixing a CORS error
Ollama must allow the extension’s origin. If you see a CORS error, set OLLAMA_ORIGINS
and restart Ollama — Slopwatch shows you the exact snippet, which looks like:
OLLAMA_ORIGINS="chrome-extension://*,moz-extension://*" ollama serve
OpenAI-compatible
A configurable base URL covering OpenAI, OpenRouter, vLLM, LiteLLM, and similar gateways. (Provider work is ongoing; Anthropic and Ollama are the supported paths today.)
Permissions
Slopwatch requests a provider’s network host only when you use it, from your click — never up front, and never broadly. It does not request access to all sites.
Privacy & your data
Slopwatch has no backend and collects no analytics. The only network requests it makes are the analysis requests you trigger, sent directly to the provider you chose.
Where your data goes
- Cloud provider (Anthropic / OpenAI-compatible): the extracted page text and your API key are sent directly from your browser to that provider, under their privacy policy. The popup shows ☁️ Cloud.
- Local Ollama: nothing leaves your device. The popup shows 🔒 Local.
The cloud-vs-local indicator is shown before and after every run so there’s never a surprise about where analysis happened.
API keys
- Keys default to in-memory session storage — cleared when the browser restarts.
- Persisting a key to disk is an explicit opt-in with a visible warning: saved keys are stored unencrypted in your browser profile, so anyone with access to the device’s files could read them. Consider full-disk encryption, or leave persistence off.
- Keys are write-only from the UI’s perspective — the settings screen shows a masked “Configured ✓” state and never echoes the value back. Keys are never logged, never put in cached results, and never sent anywhere except the provider they belong to.
Cached results
Analysis results are cached locally (keyed by URL + a content hash) to avoid re-charging for the same page. The cache lives only in your browser, carries a 7-day expiry, is size-bounded, contains no keys, and is clearable in Settings.
Diagnostics
There is an off-by-default local diagnostics log (provider, latency, token counts, error class). It stays on your device, is viewable/exportable by you, and never contains page content or keys.
Responsible use
Slopwatch produces a probabilistic signal, not proof. Please hold its output loosely.
What the result means
Every result couples a score with a calibrated label (Likely human · Uncertain · Likely AI) and a short explanation. The middle Uncertain band is permanent and can’t be configured away — because the underlying detection genuinely is uncertain.
The limits (please read)
- False positives are real. Human writing — especially formal, technical, template-following, or non-native-English text — can read as “AI.” A high score is not evidence that a person used AI.
- False negatives are real too. Capable models can produce text that reads as human.
- It’s one model’s opinion. Different providers may disagree; you can re-run with another to compare.
- It assesses text, not people. Don’t use Slopwatch to accuse anyone, grade students, screen candidates, or make consequential judgments about a person. That’s not what a probabilistic stylistic signal can support.
A good way to use it
Treat a flag as a prompt to look closer — to read more carefully, check sources, and use your own judgment — not as a gavel.
For maintainers
Building, testing, and shipping Slopwatch.
Day-to-day
pnpm dev # Chromium with hot reload
pnpm dev:firefox # Firefox via web-ext
pnpm test # Vitest (unit + integration + component)
pnpm e2e # Playwright (Chromium, MockProvider)
pnpm lint
pnpm typecheck
pnpm build / pnpm build:firefox
Definition of done for any change: pnpm lint && pnpm typecheck && pnpm test && pnpm build && pnpm build:firefox all pass. CI runs the same plus the Chromium E2E.
Architecture (where things live)
entrypoints/—background(orchestrator),popup,options, andinpage(the unlisted script injected at click time for extraction + Shadow-DOM highlights).lib/— pure, tested logic:extraction(Readability + feeds + segmenter),analysis(prompt, schema, mapper, budgeter),providers,orchestrator,cache,diagnostics,storage,messaging.
The full design lives in the repo: TDD.md, ROADMAP.md, TESTING.md, USABILITY.md,
and CLAUDE.md (invariants + conventions).
Releasing
The step-by-step runbook is RELEASING.md.
In short: green CI → manual Firefox smoke → bump package.json + CHANGELOG.md → tag
vX.Y.Z → push. The release.yml workflow builds the Firefox package + AMO sources
archive and the Chromium package, attaches them to a GitHub Release, and submits to the
stores when credentials are configured as secrets.
Hard invariants
Inert by default (activeTab only, no <all_urls>); never a bare verdict (score + label
with a permanent Uncertain band + reasoning); no data leaves the device except to the
chosen provider; keys session-default and write-only; provider responses validated; page
text treated as hostile. These are enforced throughout and must not regress.