AI Humanizer Benchmark

Methodology

This page is the complete rulebook: what gets tested, how it is scored, and what would have to be true for a score to be wrong. Some humanizers in these rankings are made by the operator of this benchmark; they play by every rule on this page, identically to every other tool. Nothing below asks for trust: each cycle ships its inputs, outputs, detector verdicts, and scoring code in a public repository (MIT for code, CC BY 4.0 for data), so every claim here is checkable against the files. Read our fairness policy or why we built this. Current version: v1.0.0.

Sample selection

A cycle's test set spans the seven kinds of writing people actually run through a humanizer:

academic_essay
argumentative essays, lit-review intros
application_essay
personal statements, cover letters
blog_post
listicles, how-to guides
business_email
professional emails, outreach
marketing_copy
product descriptions, landing pages
discussion_board
discussion-board responses
news_article
news article writing

Every cycle publishes its complete template set, word-count targets and placeholder tokens included, as templates.json, and the AI-written source texts the humanizers must rewrite as samples.json. How many samples ran is visible directly in the published data.

Templates carry [BRACKETED] tokens: [TOPIC], [ROLE], [FIELD], and so on. When a cycle starts, a secret random nonce drives a deterministic selection that picks which value from each bank lands in each slot. The banks themselves live in version control and are frozen into the cycle as banks.json.

Why draw topics from banks at all?

Because the alternative is us typing topics by hand, and a benchmark operator choosing topics after seeing how tools behave is exactly the discretion a fair test has to remove. With banks plus a seeded draw, the selection is mechanical, and once the nonce is revealed anyone can replay it and land on the identical prompts.

Automated execution and evidence

No hands touch a test. Each tool runs automatically on its default settings, which is what makes the procedure identical across all of them and the results re-derivable from the published files. Tools that can only be operated manually stay out of the benchmark: a run nobody can repeat is a run nobody can check. And because humanizers are stochastic (the same input produces a different rewrite each time), judgment comes from the whole sample set, never from one lucky or unlucky output.

Each run produces three layers of evidence:

Humanizer configuration

Humanizers are not standardized: each exposes its own modes, models, and strength settings. One configuration rule applies to every tool, so none is tuned more favorably than another:

Whatever configuration actually ran is written into leaderboard.json as plan_tier_used and settings_used; no score exists without its settings on record beside it.

Detectors

Every output is scored by seven independent commercial AI detectors: GPTZero, Originality.ai, Copyleaks, Winston AI, ZeroGPT, QuillBot, and Grammarly. None of them are operated, fine-tuned, or coordinated with by this benchmark. Each detector receives the identical text and returns its own verdict, recorded on a [0, 1] scale: 1 means the detector judged the text human, 0 means it judged it AI.

Normalization is limited to unit conversion: an AI probability becomes human = 1 − ai, and a 0–100 scale is divided by 100. Beyond that, no calibration, reweighting, or adjustment is applied: the number the vendor returned is the number that enters the per-test median. All verdicts are published per cycle in detector-scores.json, one scores object per test, keyed by detector.

Scoring formula

A humanizer's composite is built from four sub-scores, each in [0, 1]. The weighted sum is bounded [0, 100]; applied penalties come off that sum, and the result is kept within [0, 100]:

composite_raw =
    42 * bypass_rate
  + 32 * meaning_preservation
  + 16 * readability
  + 10 * consistency_across_categories

composite = max(0, composite_raw - sum_of_penalty_deltas)
Bypass 42%Meaning 32%Readability 16%Consistency 10%

The weights and penalty constants are written directly into the scoring.js shipped with each cycle, so every published leaderboard carries the exact constants that produced it. Aggregation covers every test in the cycle regardless of status: an errored, refused, or identical result counts toward the averages and triggers its penalty. If failures were excluded instead, failing would raise a tool's score.

bypass_rate

Each test contributes the median of its seven detector scores. A null indicates the detector could not be reached for that test; it is skipped, not counted as zero, because missing data is not a verdict. The bypass rate is the mean of these per-test medians.

Why the median and not the mean?

Several detectors report values pinned near 0 or 1. In a seven-member panel, one outlier verdict shifts a mean by up to 1/7 (≈0.14) on every test it touches. The median bounds the influence of any single detector.

meaning_preservation

Measured per test as the cosine similarity between embeddings of the input and the output, clamped to [0, 1]. The raw value is published in tests.json; the meaning-drift penalty reads the same number.

Why rescale the cosine?

Two on-topic English passages rarely score below ~0.85 cosine similarity, which would compress all faithful rewrites into a narrow band at the top despite meaning carrying 32% of the composite. The aggregate therefore maps [0.75, 1.0] onto [0, 1] before averaging. The mapping is monotonic (it spreads scores without ever changing their order), and the published scoring code applies it identically.

readability

Each output receives one writing-quality rating in [0, 1] for clarity, fluency, and naturalness, assigned by a language model and cached by text hash, so the value is stable across re-runs. The per-test rating is published in tests.json, and the published scoring code only averages those stored values. Reproducing the leaderboard therefore requires no model access at all.

consistency_across_categories

Within each writing category, the per-test bypass medians are averaged; consistency is then max(0, 1 - stddev(category_means)). Equal performance in every category yields 1. Strong results in one category paired with weak results in another pull this term down.

Why a neutral 0.5 below three categories?

A standard deviation over one or two categories says little. When a cycle covers fewer than three, the term is fixed at a neutral 0.5 instead of granting a free 1.0; otherwise narrow testing would outscore broad testing with minor variance.

Penalties

Output-quality failures reduce the composite. Every penalty carries a fixed per-occurrence deduction and a per-code cap, which bounds the total possible deduction at -50.0 of 100 and prevents any one failure mode from deciding a ranking on its own. Each humanizer's applied deductions appear in leaderboard.json, itemized.

PenaltyTriggerPerCap
Meaning drift
severe_meaning_drift
The rewrite stopped saying what the original said: detector-safe, but no longer the same text.
Per test where meaning_preservation < 0.85.-1.0-10.0
Length inflation
length_inflation
The rewrite ballooned well past the input, burying the AI signal under extra words instead of removing it.
Per test where output/input word ratio > 1.4.-1.0-10.0
Length deflation
length_deflation
The rewrite came back far shorter than the input; content was cut, not rephrased.
Per test where output/input word ratio < 0.6.-1.0-10.0
Identical to input
identical_to_input
The text came back essentially untouched: a rewrite was requested and an echo returned.
Per test with status = "identical".-2.0-10.0
Refusal
refusal_in_output
The tool declined the text outright, usually tripping on its own content filter.
Per test with status = "refusal".-1.0-10.0

Unavailability is excluded, not penalized

When half or more of a tool's attempts fail at the access level (service down, quota exhausted, requests blocked), that cycle did not meaningfully test the tool. It is excluded from the ranking for the cycle and listed separately in leaderboard.json with its attempt counts, rather than scored on whatever fraction happened to complete or docked points for an outage. Quality failures are treated differently: if the tool ran and returned a bad result, the penalties above apply.

Transparency and verification

Cycle names follow the calendar, so if the prompt draw were seeded on the name, any vendor could compute October's prompts in September and train against them. The seed is therefore a secret, but one we prove we did not change after the fact, using commit-reveal:

  1. 1
    Commit

    Before anything runs, a random 32-byte nonce is generated and only its SHA-256 fingerprint goes public, as commit.json. The nonce itself stays sealed.

  2. 2
    Run

    Every humanizer processes the corpus automatically, and every output is scored. What gets kept is the result (input, output, settings), not the network traffic around it.

  3. 3
    Reveal

    When the cycle closes, the nonce goes public together with frozen copies of the templates, banks, selection code, and the prompts they produced.

  4. 4
    Anchor

    The finished bundle's hash is stamped with a public timestamping service: independent proof the data existed in exactly this form at publication.

One command checks the whole chain, and each check closes off a different way a benchmark could be quietly manipulated:

To see for yourself:

git clone https://github.com/AIHumanizerBenchmark/AIHumanizerBenchmark.git
cd AIHumanizerBenchmark
npm run verify                      # checks all published cycles
npm run verify -- "September 2026"  # checks a single cycle

There is no install step. The verifier uses only Node's standard library and runs entirely offline. A verification tool whose dependencies you have to trust does not verify much.

Recomputing every score from the raw data

Every number on the leaderboard is a function of the published files. The scoring script in each cycle bundle is self-contained, with no dependencies; recomputing the full ranking is an import and one function call:

import { computeLeaderboard } from "./cycles/september-2026/scoring.js";
import tests from "./cycles/september-2026/tests.json";
import detectorScores from "./cycles/september-2026/detector-scores.json";

// Returns every humanizer, ranked by composite descending.
const ranked = computeLeaderboard(tests, detectorScores);
console.log(ranked[0]); // top-ranked humanizer for the cycle

A single sub-score can be checked by hand. For one humanizer's bypass rate:

  1. Take that humanizer's rows from tests.json, all of them. Rows with error, refusal, or identical status stay in, since dropping failures would raise the average.
  2. For each row, locate its entry in detector-scores.json and take the median of the scores values. Skip any null; an unreachable detector is missing data, not a zero.
  3. Average those medians. That is the bypass rate.
  4. Compare against leaderboard.json, using an absolute tolerance of 1e-4 for floating point.
No tooling at all?

Every panel detector is a public product. Paste any published output into one and compare its verdict with the recorded score.

Versioning

Every cycle's leaderboard.json records three version stamps:

StampBumped when
methodology_versionSomething described on this page moves: a weight, a sub-score definition, a penalty rule.
scoring_versionThe scoring code itself changes, usually in step with methodology_version.
prompt_set_versionThe templates, the value banks, or the selection algorithm behind the prompts change in any way.

Roster changes do not move any stamp. Which humanizers and detectors ran is recorded in each cycle's own data, and that record is the authority.

Published cycles never change. A bundle (templates, banks, selection code, scoring code, raw data, leaderboard) is frozen the moment it is published. Later methodology changes affect later cycles and their version stamps; they cannot reach backward.

Methodology integrity

Rankings are never edited by hand. They are the output of the published scoring code applied to the published data, and the claim rests on structure, not reputation: a leaderboard that did not come from that code and that data fails public verification, and the verifier is available to anyone.

How to contribute or dispute

Think a score is wrong, or spotted an error in the data? File a dispute: we respond within 14 business days and publish the resolution. You can also submit a humanizer or suggest a detector for a future cycle. For anything else, including corrections, questions about the data, or a security report about the verification code, write to contact@aihumanizerbenchmark.com.