DEV Community

Eliot S
Eliot S

Posted on

AI Detector Accuracy Test: I Built a Python Script to Send the Same Essay to 5 Tools at Once

#ai

Last semester I pasted the same essay into two detectors back to back and got 82% on one, 31% on the other. No edits. Same paste. Within the same hour.

I stared at that for a while. Like, which one do I trust? Both? Neither? If I'd only checked one, I'd have a completely different read on my actual situation. That's when I decided manual tab-switching wasn't going to cut it for a real AI detector accuracy test.

So I spent a Saturday morning building a script. This is that script plus what I found when I actually ran it.

Why I bothered automating the AI detector accuracy test

Honestly, two reasons.

The boring one first: speed. If you're comparing versions of the same text (raw, edited, humanized), that's five tools times three versions equals fifteen paste jobs. I don't have that kind of patience and I suspect you don't either.

The less obvious one is that these tools aren't consistent even with themselves. I pasted the same block of text into ZeroGPT twice, no changes at all, and got slightly different numbers. Not dramatically different, but different. If you're anywhere near a threshold that matters, that variance is a problem. Running everything in one script simultaneously at least controls for that. Not a perfect solution, but better.

For my test I used three versions of the same essay:

  • Version A: Straight from GPT-4o, zero editing
  • Version B: About 20 minutes of hand editing
  • Version C: Processed through a humanizer tool

The five detectors

  1. GPTZero — my university writing center literally name-dropped this one in their updated AI policy email. So that's probably what people in my department are running.
  2. Originality.ai — has an actual documented API, used a lot in publishing
  3. Winston AI — good docs, and you can get per-sentence breakdowns which turns out to be useful
  4. ZeroGPT — free, no account, but I'm using an unofficial endpoint. Could stop working tomorrow, no idea.
  5. Copyleaks — handles both AI detection and plagiarism in one go. I'm not implementing it fully here because the OAuth flow adds a bunch of boilerplate that's not really the point of this post.

The code

The main thing is aiohttp so all four requests fire simultaneously instead of waiting in sequence. Install it first:

pip install aiohttp
Enter fullscreen mode Exit fullscreen mode

Then the full script:

import asyncio
import aiohttp
import json
from dataclasses import dataclass

@dataclass
class DetectionResult:
    tool: str
    score: float        # 0.0 = human, 1.0 = AI
    error: str = None

API_KEYS = {
    "gptzero":     "YOUR_GPTZERO_KEY",
    "originality": "YOUR_ORIGINALITY_KEY",
    "winston":     "YOUR_WINSTON_KEY",
}

ESSAY = """Paste your essay text here."""


async def check_gptzero(session: aiohttp.ClientSession, text: str) -> DetectionResult:
    url = "https://api.gptzero.me/v2/predict/text"
    headers = {
        "x-api-key": API_KEYS["gptzero"],
        "Content-Type": "application/json",
        "Accept": "application/json",
    }
    payload = {"document": text, "multilingual": False}
    try:
        async with session.post(url, headers=headers, json=payload) as resp:
            data = await resp.json()
            score = data["documents"][0]["completely_generated_prob"]
            return DetectionResult(tool="GPTZero", score=score)
    except Exception as e:
        return DetectionResult(tool="GPTZero", score=0, error=str(e))


async def check_originality(session: aiohttp.ClientSession, text: str) -> DetectionResult:
    url = "https://api.originality.ai/api/v1/scan/ai"
    headers = {
        "X-OAI-API-KEY": API_KEYS["originality"],
        "Content-Type": "application/json",
    }
    payload = {"content": text, "aiModelVersion": "1"}
    try:
        async with session.post(url, headers=headers, json=payload) as resp:
            data = await resp.json()
            return DetectionResult(tool="Originality.ai", score=data["score"]["ai"])
    except Exception as e:
        return DetectionResult(tool="Originality.ai", score=0, error=str(e))


async def check_winston(session: aiohttp.ClientSession, text: str) -> DetectionResult:
    url = "https://api.gowinston.ai/functions/v1/predict"
    headers = {
        "Authorization": f"Bearer {API_KEYS['winston']}",
        "Content-Type": "application/json",
    }
    payload = {"text": text, "sentences": False}
    try:
        async with session.post(url, headers=headers, json=payload) as resp:
            data = await resp.json()
            return DetectionResult(tool="Winston AI", score=data["score"] / 100)
    except Exception as e:
        return DetectionResult(tool="Winston AI", score=0, error=str(e))


async def check_zerogpt(session: aiohttp.ClientSession, text: str) -> DetectionResult:
    # unofficial — may break at any time
    url = "https://api.zerogpt.com/api/detect/detectText"
    headers = {"Content-Type": "application/json"}
    payload = {"input_text": text}
    try:
        async with session.post(url, headers=headers, json=payload) as resp:
            data = await resp.json()
            score = data["data"]["fakePercentage"] / 100
            return DetectionResult(tool="ZeroGPT", score=score)
    except Exception as e:
        return DetectionResult(tool="ZeroGPT", score=0, error=str(e))


async def run_all_detectors(text: str) -> list[DetectionResult]:
    async with aiohttp.ClientSession() as session:
        tasks = [
            check_gptzero(session, text),
            check_originality(session, text),
            check_winston(session, text),
            check_zerogpt(session, text),
        ]
        return await asyncio.gather(*tasks)


def print_results(results: list[DetectionResult], version_label: str):
    print(f"\n{'=' * 50}")
    print(f"Version: {version_label}")
    print(f"{'=' * 50}")
    print(f"{'Tool':<22} {'Score':>8}  {'Verdict':>10}")
    print("-" * 44)
    for r in sorted(results, key=lambda x: x.score, reverse=True):
        if r.error:
            print(f"{r.tool:<22} {'ERROR':>8}  {r.error[:20]}")
        else:
            pct = r.score * 100
            verdict = "AI" if pct > 50 else "Human"
            print(f"{r.tool:<22} {pct:>7.1f}%  {verdict:>10}")


if __name__ == "__main__":
    versions = {
        "Version A (raw GPT-4o output)": ESSAY,
        # swap in your other versions:
        # "Version B (light edits)": ESSAY_B,
        # "Version C (humanized)":   ESSAY_C,
    }
    for label, text in versions.items():
        results = asyncio.run(run_all_detectors(text))
        print_results(results, label)
Enter fullscreen mode Exit fullscreen mode

Version A output:

==================================================
Version: Version A (raw GPT-4o output)
==================================================
Tool                     Score     Verdict
--------------------------------------------
Originality.ai          94.0%          AI
Winston AI              88.0%          AI
GPTZero                 81.0%          AI
ZeroGPT                 74.0%          AI
Enter fullscreen mode Exit fullscreen mode

AI detector accuracy test results across all three versions

Here's what I got:

Version A — Raw GPT-4o:

  • Originality.ai: 94%
  • Winston AI: 88%
  • GPTZero: 81%
  • ZeroGPT: 74%

Version B — Lightly edited by hand:

  • Originality.ai: 71%
  • Winston AI: 62%
  • GPTZero: 58%
  • ZeroGPT: 43%

Version C — Humanized:

  • Originality.ai: 31%
  • Winston AI: 28%
  • GPTZero: 24%
  • ZeroGPT: 19%

The Version A spread killed me a little. 74% to 94% on the exact same raw GPT-4o output. That range matters because schools draw the line in different places: 80% at some institutions, 50% at others, 60% at others depending on who wrote the policy that week. You can pass one bar and fail another on the same document.

Version B was the disappointing one. I actually put time into those edits — went through every paragraph, tried to break up the cadence, cut some sentences, added my own phrasing. Still got flagged by three out of four. ZeroGPT was the only one that dipped under 50%. Twenty minutes of editing barely moved Originality.ai. Wasn't expecting that.

Version C passed everything. Still a 12-point spread (19% to 31%) but well below any real threshold. The variance didn't disappear though. These four tools are clearly measuring different things.

Most accurate AI detector 2026: what I actually found

Nobody's running away with this. That's the honest take from my data and the benchmarking stuff I've read elsewhere.

If I had to pick one for catching raw, unedited AI output: Originality.ai. It came in highest on Version A by a margin and was the last to budge as I edited. But that aggression is a double-edged thing. I've seen it flag heavily stylized human writing that just happens to be formal and structured. If you're testing a student paper from someone who writes in a clean, academic style, I'd double-check with a second tool before acting on that result.

GPTZero was the most relaxed. Lowest false positive rate of the four, which probably reflects how it was designed. Specifically for academic submissions where wrongly flagging a real student is a much bigger deal than missing a borderline AI piece. Catches less, but what it catches it's more confident about.

Winston AI landed somewhere in between. Comparable to GPTZero on raw output but less aggressive on edited text. Per-sentence view is genuinely handy if you want to see which paragraphs pushed the needle instead of just getting a single number and guessing.

ZeroGPT? All over the place. Free, no sign-up required, which is why it's everyone's first stop. But the variance makes it basically useless for anything where the stakes are real.

The question "most accurate AI detector 2026" kind of assumes there's a right answer. There isn't. High detection sensitivity and low false positive rate pull in opposite directions. You're always trading one for the other.

AI detector comparison: why the same text scores differently

When I first saw the results I thought one of the tools had to be wrong. But that's not really how this works.

These things aren't running the same model. Some are built around perplexity and burstiness, meaning how predictable the word choices are and how uniform the sentence lengths are. GPT-4o output is low-perplexity almost by definition. The model is trained to pick the most probable next token, which makes the text statistically smooth in ways human writing isn't. We're messier. We change our minds mid-sentence, pick words for rhythm, write shorter when tired.

Other tools look at semantic patterns instead — whether the writing hedges, goes off-topic, self-corrects, circles back. That stuff shows up in human writing because we're thinking while typing. AI generates from a prompt in one pass and has no reason to qualify or digress.

So this AI detector comparison isn't really about which tool is better. Originality.ai weights semantic signals more heavily, which is why it nails raw output but sometimes overcorrects on human writing that's direct and well-structured. GPTZero's calibration is different because it was trained on a different population of text.

Paste the same essay into four tools, get four different scores — you're probably looking at genuinely borderline content. That's not a calibration error. That's what the gray zone looks like.

Can Turnitin detect ChatGPT?

Yes. And it's not in this script, which is the more important part.

Turnitin launched their AI detection feature in April 2023. Updated a few times since. Covers ChatGPT, Claude, Gemini, and the usual suspects. Their own published figures say something like 98% accuracy on unedited AI output and a 1% false positive rate on human writing. Take self-reported numbers with appropriate skepticism, but they're probably in the right ballpark.

It's not in this script because there's no public API. Their detection is baked into the submission pipeline. Canvas, Blackboard, whatever LMS your school uses. The only way to test against Turnitin is to actually submit.

I found this out the hard way. Ran something through this script, got a 22% on GPTZero, submitted it, got a 71% back from Turnitin. That was a bad day. Their model has context I don't — submission history, cross-comparison patterns, document metadata. It's doing something different from the external tools. Pre-checking with this script is still worth it, but a clean result here is not a Turnitin guarantee.

What this AI detector accuracy test tells you (and what it doesn't)

The main thing: one tool isn't enough. The variance is too wide to make decisions from a single number.

Four tools all flagging high? Real signal. The text is probably still close to raw output and needs more work. Four tools splitting 50/50? Genuine gray zone, and your actual risk depends on which specific tool is running on the other end.

The script is good for:

  • Cross-checking whether something is flagging consistently
  • Seeing how sensitive different detectors are to the specific edits you're making
  • Cutting the manual tab-switching down to one function call

The editing and humanization side — what actually moves scores — is a longer topic. I went into it on my Substack, specifically the part of the process most people skip entirely, which is also why a lot of people are still getting flagged even after running their text through a humanizer once.

The script above is minimal by design. Per-sentence Winston output, Copyleaks integration, and CSV batch logging are reasonable things to bolt on if you need them.

Top comments (0)