Assessment & Proctoring

The candidate owns the browser.

Every integrity check you ship runs on hardware the person being examined administers, in a browser they can restart with a debugger attached. That single fact decides which controls are real and which only look like controls — and it is why the useful question for an assessment vendor is not “how do I stop cheating with JavaScript?” but “what is actually worth protecting in this bundle, and what has to move to the server?”

First Principle

Score on the server.

If the client can compute the result, the client can choose the result. Everything else on this page is about cost and attribution, not about trust.

Protect the psychometricsAdaptive routing and scoring rules are the real IP in the bundle.
Automation is a signalDriver markers are graded as hints, never as proof of misconduct.
Accessibility comes firstTwo defenses collide with accommodations candidates are entitled to.
The Honest Boundary

What client-side protection cannot do for an exam

Assessment is the use case where overclaiming does the most damage, because a vendor who believes a client-side control is authoritative will design an appeals process around it. Start from what the browser actually guarantees, which is nothing.

The result must not be computable on the client

If your bundle contains enough information to mark an answer, it contains the answer. No amount of renaming, string encoding or control-flow rewriting changes that — the data is present because the code needs it. Deliver items individually, mark on the server, and let the client render outcomes it was told rather than outcomes it derived.

Every reported value is a claim

Time remaining, focus changes, tab switches, paste events, window dimensions, camera state: all of it arrives as a message from a machine the candidate controls. Record these as evidence for human review. Do not let any of them fail a candidate automatically, because a fabricated value and a real one are indistinguishable at the point they reach you.

Obfuscation is not invigilation

A lockdown browser is a separate application with operating-system privileges over process launching and screen capture. Protection operates on the JavaScript inside your web application and can see nothing outside the page. Both can be worth having; conflating them in a tender response is how a platform ends up defending a claim it cannot support.

Determined defeat is always available

Checks written in JavaScript are neutralised by an attacker who is patient and controls the runtime — the documentation for the integrity checks says exactly this. The realistic goal is to make casual and scripted circumvention expensive and noisy, so that the people who bypass it are few enough to review individually.

What Is Worth Protecting

Four assets in an assessment bundle

Once the answer key is server-side where it belongs, the code that remains still carries most of what makes an assessment platform valuable. This is the part obfuscation is genuinely for.

1. Scoring and partial-credit rules

How a constructed response earns three marks rather than two, how negative marking is applied, how a rubric maps to a scale. This is commercial logic refined over years, it is readable in a minified bundle in an afternoon, and a competitor can reimplement it without ever touching your servers.

2. Item selection and adaptive routing

A computerised adaptive test carries difficulty and discrimination parameters, stopping rules and exposure controls. That is the psychometric work an institution is paying for. It is also the most damaging thing to leak, because published item parameters compromise the bank itself, not just the software.

3. The integrity heuristics themselves

Readable detection logic is a specification for evading it. A candidate who can see which events you sample, on what interval, and what thresholds trip a flag knows precisely how to stay under them. Protection does not make this secret — it makes reading it a project rather than a glance.

4. Integration and entitlement logic

How your player negotiates with an institution's identity provider or gradebook, which tenant flags exist, what an unreleased proctoring mode is called. This is the same exposure described in your bundle leaks your roadmap, and in education procurement it lands in front of the people evaluating you.

Notice what is not on this list. Answer keys, correct-response flags, mark schemes for unseen items and licence secrets do not belong in shipped JavaScript under any protection setting — the same argument as why you cannot hide an API key in JavaScript. Obfuscation protects logic that has to run on the client. It is not a place to put data that should never have been sent.

Automation detection, graded honestly

The environment-integrity checks ship three probes, and the third is the one assessment teams ask about. automation looks for driver and headless markers: navigator.webdriver, PhantomJS and Selenium leftovers, and the ChromeDriver-family cdc_ properties. The other two, hookedBuiltins and crossRealm, compare watched builtins against a native shape and against a pristine same-origin realm, which catches a hook that also spoofed its own toString.

The grading is the important part. Automation findings are capped at signal severity and never reported as high, deliberately, because navigator.webdriver is a one-line patch and a tuned headless browser leaves none of these markers behind. A platform that fails candidates on a signal-severity finding will eventually fail an honest one, and in assessment that is a serious outcome for a real person.

Route these to a review queue with the session recording attached. The value is triage: they tell you which of ten thousand sittings deserve a human look, which is a genuinely useful thing for a check that costs almost nothing to run.

Probe before a sensitive transition, not once at load
const ei = require("jso-protector/runtime/environment-integrity");

const probe = ei.createEnvironmentIntegrityPolicy({
  checks: ["hookedBuiltins", "crossRealm", "automation"],
  watch: ["Function.prototype.call", "JSON.parse"]
});

// Run at item transitions and before submission -
// the policy is inert data until inspect() is called.
const report = probe.inspect(window);

if (!report.ok) {
  // Attach to the session for human review.
  // Do NOT terminate the sitting on this alone.
  flagForProctorReview(report.violation);
}
Read This Before Shipping

Two defenses that collide with accessibility duties

Assessment vendors sell to universities, awarding bodies and government agencies, which means accessibility obligations are usually contractual rather than aspirational. Two protection options work directly against them.

BlockDevToolsKeys — leave it off

Alongside intercepting F12 and the Ctrl combinations, it registers a global contextmenu handler that calls preventDefault() on every right-click in the page. That removes copy, paste, spell-check, translation and the menu keyboard users open with Shift+F10 — for every candidate, in exchange for closing one of several routes to bytes the browser already downloaded. The accessibility analysis reaches the same conclusion from the other side.

AntiMonkeyPatching — exclude, do not disable

It watches event registration, timers, Fetch, XHR, Promise, storage and Web Crypto. Screen readers, magnifiers, text-to-speech extensions and accessibility overlays replace exactly those APIs by design, so an approved accommodation reads as tampering. Use AntiMonkeyPatchingExcludeGlobals for the specific dotted paths and reconsider AntiMonkeyPatchingCleanRealm when the patch lands before your bundle starts.

Choose a failure action that degrades

The runtime-defense action set includes throw, blank, redirect, reload, callback and degrade. A blanked page mid-sitting is an incident for the candidate least able to recover from it. Degrade or callback lets you record the event, notify an invigilator and keep the session alive for a human decision.

Test with the accommodations you actually approve

You cannot enumerate every overlay an institution mandates, but you can run your own approved-accommodations list against a protected build before a live sitting. It is a short test and it is the one that catches this class of problem before a candidate does.

Per-institution build, attributable and reproducible
npm run build                             # player -> dist/

npx jso-protector dist/ \
  --out dist-protected/ \
  --preset maximum \
  --seed "$RELEASE_TAG" \                 # byte-identical rebuilds
  --watermark "tenant:$INSTITUTION_ID" \  # attribution, not prevention
  --watermark-key "$WM_KEY" \
  --report build/report-$INSTITUTION_ID.json \
  --manifest build/manifest.json

npx jso-protector --verify-manifest build/manifest.json \
  --audit-source-maps                     # no source shipped alongside

Attribution is the control that survives

You cannot prevent a bundle being copied — it was served to a browser. You can make a copy identify itself. A watermark is an HMAC-SHA256 tag written into every protected file's header comment and verified later with the scan tooling, so a bundle that turns up in a competitor's product or on a file-sharing site names the tenant it was issued to.

A seed makes that claim provable. The same input, options and seed produce byte-identical output, so months later you can rebuild exactly what a given institution was served and demonstrate it rather than assert it. When an academic-integrity dispute becomes a contractual one, the difference between those two verbs is the whole argument. The mechanics are in reproducible builds.

Keep the per-release report permanently. Symbolication only works against the report that produced that exact build, and a candidate reporting a fault during a high-stakes sitting is precisely when you need to reconstruct what happened.

Frequently Asked

Assessment protection questions, answered

Can obfuscation stop candidates cheating on an online exam?

No, and no client-side control can. The exam runs inside a browser the candidate administers, on hardware they own, and every check you ship is JavaScript executing in their environment. Obfuscation raises the cost of reading and modifying your code, which is worth doing, but it does not make the browser trustworthy. The controls that actually decide an exam result are server-side: score on the server, deliver items one at a time, keep the answer key out of the bundle entirely, and treat every value the client reports as a claim rather than a fact.

What in an assessment bundle is actually worth protecting?

Four things, none of which is the answer key — that should never have been in the bundle. First, scoring and partial-credit rules, which are commercial logic that a competitor can lift verbatim. Second, item-selection and adaptive routing, including the difficulty parameters behind a computerised adaptive test, which represent years of psychometric work. Third, the client-side integrity heuristics themselves, because reading them tells a candidate exactly which behaviours are watched. Fourth, integration and licensing logic that reveals how your platform talks to an institution's systems.

Will the automation checks detect a candidate using Selenium or Puppeteer?

They will detect an unprepared one. The automation check looks for driver and headless markers — navigator.webdriver, PhantomJS and Selenium leftovers, and ChromeDriver-family cdc_ properties. That catches someone who downloaded a script and ran it. It does not catch a tuned headless browser, and the documentation is explicit that automation findings are capped at signal severity and never reported as high, because navigator.webdriver is a one-line patch. Route these findings to review queues and score-flagging workflows, never to an automatic fail.

Should an exam platform enable BlockDevToolsKeys?

Almost certainly not, and accessibility is the reason before security is. The option registers a global contextmenu handler that calls preventDefault on every right-click in the page, which removes copy, paste, spell-check, translation and the menu route keyboard users reach with Shift+F10. Assessment platforms usually carry contractual accessibility obligations to public institutions, and suppressing the context menu for every candidate is a poor trade against a control that only slows the incurious — the bytes are already downloaded by the time any key handler runs.

Will runtime defense interfere with accessibility tools candidates are entitled to use?

It can, and this is a real risk for assessment specifically. AntiMonkeyPatching watches event registration, timers, Fetch, XHR, Promise, storage and Web Crypto, and reports the first replacement it finds. Screen readers, magnifiers, text-to-speech extensions and accessibility overlays work by replacing exactly those APIs. A candidate using an approved accommodation can therefore trip a tamper signal through no fault of their own. Exclude the relevant dotted API paths with AntiMonkeyPatchingExcludeGlobals, choose a failure action that degrades rather than blanks the page, and test with real assistive technology before a live sitting.

How do per-institution builds and watermarks help an assessment vendor?

They convert a leak from an anonymous event into an attributable one. A watermark is an HMAC-SHA256 tag embedded in every protected file's header, verifiable later with the scan tooling, so a bundle recovered from a file-sharing site or a competitor's product identifies which institution's build it came from. Combined with a build seed, which makes protected output byte-identical for the same input and options, you can rebuild and prove exactly what a given tenant was served on a given date — useful when an academic-integrity dispute becomes a contractual one.

Is obfuscation a substitute for a lockdown browser or live proctoring?

No. A lockdown browser is a separate application with operating-system privileges that can restrict process launching, screen capture and display configuration. Obfuscation is a source-protection measure applied to the JavaScript in your web application, and it has no visibility outside the page. They solve different problems and the honest position is to say so: use obfuscation to protect your intellectual property and raise the cost of tampering with the client, and use invigilation, lockdown software or server-side item delivery to address exam integrity.

How do I debug a failed sitting when the code is obfuscated?

Keep the protection report for every release, tagged with the version each institution was served. Symbolication translates an obfuscated stack trace back to real names, but only against the report that produced that exact build, so if the report is lost the trace is unreadable permanently. In assessment this matters more than in ordinary software, because a candidate who reports a fault during a high-stakes sitting may be entitled to a remedy and you will need to establish what actually happened.

Related Guides

Protecting other JavaScript targets

Widgets & SDKs

Code that runs on somebody else’s page, where domain locking is the primary control.

Paywalled content

Metered publishing, where the article was delivered before the overlay rendered.

E-learning & SCORM

Courseware shipped as an archive, where the asset is the course and redistribution is the threat.

HTML5 games

The other domain where client-side integrity and server-side authority have to be separated.

Environment integrity

The three checks, how severity is graded, and why automation findings stay signals.

Runtime defense

Every guard, failure action and telemetry option referenced on this page.