Prep is a web-first marketing surface and a native-app exam surface. Practice in any browser; sit a paid mock or tournament only in the app. This split has been the most argued-over decision in the project. Here is the reasoning.
1 · What "anti-cheat" actually means here
For free practice — none of this matters. Cheat all you want; you only cheat yourself. The interesting question is mocks and tournaments where money or rankings are on the line. There we need to prove (within reason) that:
· The person sitting the exam is the account-holder. · They aren't copy-pasting screenshots into ChatGPT, then answering. · They aren't running answer-key apps in a second window. · They aren't using screen-share to phone a friend. · They aren't recording the question paper for resale.
2 · What the browser cannot do
The browser intentionally cannot:
· Disable screenshots. There is no API. Even if there were, the OS-level screenshot mechanism bypasses the browser entirely. · Detect screen recording. Some browsers expose getDisplayMedia state, but it is opt-in and trivially bypassed. · Hide from the OS's "switch apps" snapshot. Cmd-Tab on macOS / app-switcher on Android shows the current page. · Prove the app is unmodified. There is no equivalent of App Attest for web pages. · Use the Secure Enclave / Keystore for device-binding. WebAuthn helps but is not the same primitive.
These are deliberate browser security boundaries. We respect them — but they mean the browser is the wrong place for paid mocks.
3 · What native gives us
On Android: WindowManager.LayoutParams.FLAG_SECURE makes the window uncapturable by screen recorders, screenshots, and the recent-apps thumbnail. Play Integrity attests the app build hasn't been tampered with.
On iOS: UIScreen.captured fires when the user starts a screen recording — we can pause the mock. Secure-text input prevents the keyboard cache from leaking. App Attest does the same job as Play Integrity.
On macOS (Flutter Desktop): NSWindow.sharingType = .none → screen-capture APIs see nothing. App-switcher snapshot suppression on willResignActive.
On Windows: SetWindowDisplayAffinity(hwnd, WDA_EXCLUDEFROMCAPTURE) — screen recorders see a black rectangle.
On Linux: nothing. Linux has no universal capture-block primitive. We disable paid mocks on Linux and surface a clear banner. Free practice + study notes + library all work; this is the honest trade-off.
4 · What we give up
Friction. Installing an app is more work than opening a URL. Some students will bounce at the install step. We bet that the students who actually pay for serious prep will install — and they are the ones we care most about getting a fair experience to.
Iteration speed. App-store review is slow. We ship the web 4× faster than we ship the app. So we keep the web rich — every dashboard, every report, every chat with the AI coach — and only the exam-taking screen requires the native app.
Cross-platform UI variance. We use Flutter to avoid this: same Skia rendering on Android, iOS, macOS, Windows, Linux. One codebase for all 5.
5 · What we explicitly chose not to do
We do not require a webcam for free practice. We do not require government-ID verification for normal use. We do not record audio outside of disclosed proctored sessions. We do not lock people out of practice if they can't install the app — they just can't sit official tournaments.
The principle: anti-cheat scales with stakes. A free practice MCQ should have zero friction. A 10,000-prize tournament should have full attestation + recorded session.
6 · The web demo at prep.theosintra.org
The live demo is entirely the web app. You can browse all 60+ pages, sign in as any role, and see every dashboard. There is no exam-taking surface in the demo — that lives in the apps. The flow on a real paid mock will be: tap "Start mock" on the web → universal-link opens the app → app runs the mock with secure-window → results sync back to the web dashboards.
"You can build a beautiful exam-prep website. You cannot build a fair exam in one."