ProctorLink runs inside a cross-origin iframe, the enclave, served from its own domain so that the camera permission, the session token, and the capture code live on an origin you do not control. That boundary is what lets the camera permission persist across every site that embeds ProctorLink, keeps the session token out of host-page JavaScript, and keeps the integrity score computed server-side where a candidate cannot reach it. Your page adds one line of Content-Security-Policy and hands the SDK a token. Everything below is grounded in the ProctorLink API reference and architecture.
Schedule a DemoThe ProctorLink SDK is a thin loader, about 3 KB gzipped. It does not capture anything itself. When you call it, it mounts a cross-origin iframe, the enclave, served from enclave.proctorlink.com. The camera, the session token, and the keyframe capture all live inside that frame, on an origin that belongs to ProctorLink rather than to you. Your page talks to it only through the SDK.
// In your exam page. The loader is about 3 KB gzipped.
// It mounts a cross-origin iframe (the enclave) served from
// enclave.proctorlink.com, not from your own origin.
import { ProctorLink } from '@proctorlink/sdk';
const session = ProctorLink.createSession({
jwt: sessionJwt, // short-lived, origin-bound session token
sessionId, // session_id from your mint call
mount: '#proctor-preview', // where the enclave's preview sits (optional)
});
// Requests the camera against the ENCLAVE origin, not your domain.
await session.start();Because the enclave is cross-origin, the browser treats it as a separate security context. Your page cannot read into it, and it cannot read out into your page, except through the narrow interface the SDK exposes. That single design choice is what makes the three properties below possible. If you are new to the integration as a whole, start with how to add proctoring to a web application, then come back here for why the boundary is drawn where it is. For the wider decision between an SDK, a REST API, and an LMS plugin, see proctoring SDK vs API vs LMS plugin.
Browsers scope a camera grant to an origin. The enclave always loads from the same origin, enclave.proctorlink.com, no matter whose site embeds it. So a candidate who has already granted the camera to the enclave on one exam is not prompted again when they sit another exam on a different site that also embeds ProctorLink, because the browser sees the same iframe origin it granted before.
Run the same capture code as same-origin script in each customer page and you lose this. The browser would bind the grant to every customer domain separately and re-prompt on each one, which is friction at exactly the moment a candidate is nervous about starting. Putting the camera behind one stable origin trades a one-line CSP change for a permission that behaves consistently everywhere.
Minting is a server-to-server call. Your backend calls POST /v1/sessions with your access-token and secret-token, and those credentials never leave your server. The browser receives only the session_jwt, a short-lived token scoped to one attempt and bound to the origins you listed in allowed_origins.
// Your backend. The API key stays here and never reaches the browser.
POST /v1/sessions
access-token: <YOUR_ACCESS_TOKEN>
secret-token: <YOUR_SECRET_TOKEN>
content-type: application/json
{
"external_user_id": "candidate-123",
"attempt_id": "attempt-789",
"allowed_origins": ["https://exams.yourcompany.com"]
}
// The browser receives only this: a token scoped to one attempt and
// bound to your origin. It lives inside the enclave, not your JavaScript.
{
"session_id": "6a7b18df70e4f8ecf2597b6f",
"session_jwt": "eyJhbGciOi...",
"expires_at": 1786443201
}That token then lives inside the enclave, not in your page’s JavaScript. A script running on your page, whether it is your own, a third-party tag, or something injected, cannot read it, because it sits behind the cross-origin boundary. The same goes for the camera stream: the enclave holds it, and your page never touches raw video. The split is deliberate, and it is the same split described in the web application integration guide: the API key stays server-side, the browser only ever holds a token it cannot misuse.
| What | Where it stays | Why |
|---|---|---|
| API key (access-token, secret-token) | Your backend only | Never sent to the browser. Anyone holding it can mint sessions billed to you. |
| Session token (session_jwt) | Inside the enclave | Short-lived and origin-bound. Scoped to one attempt; safe to hand to the browser. |
| Integrity score | Computed server-side | The client cannot influence the verdict. This is the core anti-tamper property. |
One thing. If your page sets a Content-Security-Policy, allow the enclave origin as a frame source so the iframe can mount:
frame-src https://enclave.proctorlink.com;You do not self-host the capture code, so there is nothing to add to script-src or connect-src for ProctorLink. By default the SDK shows a small floating picture-in-picture preview; pass a mount element to createSession to place that preview inside your own layout, or set showPreview to false to hide it. Either way the preview is still the enclave’s frame, so you are choosing where it sits, not pulling camera handling into your own code. One design consequence to know up front: a page that disables the camera wholesale through a browser Permissions-Policy will also stop the enclave from using it, so make sure the camera is not blocked globally.
The integrity score is computed server-side only. Nothing in the browser, inside or outside the enclave, can change the verdict, which is the core anti-tamper property of the design. The cross-origin boundary reinforces it from the other direction: a candidate cannot reach the capture code or the token from your page to feed the server false data. Keyframes upload from the enclave straight to object storage through presigned URLs, so the image bytes never pass through the API or through any code the candidate controls, and only periodic stills are captured rather than continuous video, which keeps bandwidth predictable.
A candidate can still refuse the camera or close the tab. Those are recorded as signals in the report, not as a way to edit a score. For what the browser can and cannot observe in the first place, and why the extension and desktop tiers exist, read what browser-based proctoring can and cannot detect. For how the server turns those signals into a verdict a reviewer can trust, see what AI proctoring measures.
| Property | In the cross-origin enclave | If it ran in your page |
|---|---|---|
| Camera permission | Binds to enclave.proctorlink.com. Granted once, reused on every site that embeds ProctorLink. | Binds to each customer domain, so the browser re-prompts on every new site. |
| Session token | Held inside the enclave frame. Unreachable from host-page JavaScript. | Sits in your page, readable by any script on it, including third-party or injected ones. |
| Camera stream | Held by the enclave origin. Your page never touches raw video. | Flows through your own code, which you then have to secure. |
| Capture and upload | Runs in the enclave. Keyframes go straight to object storage via presigned URLs. | Ships in your bundle, so you own and must maintain the capture path. |
| What you change | One line of CSP: frame-src https://enclave.proctorlink.com. | Self-hosted script plus wider script-src and connect-src rules. |
frame-src. If your policy does not allow enclave.proctorlink.com, the browser blocks the iframe and the enclave never mounts, so capture never starts. Fix: add frame-src https://enclave.proctorlink.com; to your Content-Security-Policy.access-token and secret-token in client code hands anyone the ability to mint sessions billed to you, and it throws away the token model entirely. Fix: mint on your backend and pass the browser only session_jwt and session_id.Put together, the choices reinforce one another. The API key stays on your server. The browser receives a short-lived, origin-bound token that lives inside the enclave rather than in your application state. The camera permission binds to the enclave origin, so a candidate who granted it once is not prompted again elsewhere. The integrity score is computed server-side, so the verdict cannot be edited from the exam page. Each property follows from the same cross-origin boundary rather than from a separate feature you have to configure.
If some of your exams run inside Moodle rather than your own engine, you do not wire the SDK there at all; you use the drop-in plugin covered in best Moodle proctoring plugin. Across published deployments, ProctorLink has supported more than one million proctored exam sessions (methodology note below). Full cohort sizes and outcomes are on the case studies page.
Institutions evaluating proctoring tools often look for independent feedback outside vendor case studies. ProctorLink is listed on G2, where Moodle administrators and training teams share verified product reviews.
Read ProctorLink reviews on G2 →Deployment statistics and product behaviour described in this guide link to the sources below.
Want to see the enclave mount and report a real attempt? Sign up at app.proctorlink.com to get your API keys, add the one-line CSP, and run a session end to end.
Create an account at app.proctorlink.com to get your SDK credentials and start minting sessions.
Install @proctorlink/sdk, the thin loader that mounts the enclave and captures keyframes.
See the enclave, the camera permission, and the integrity report in a 30-minute walkthrough.
Per-session and subscription models for custom applications and LMS exams.
The full walkthrough of minting a session, running the SDK, and reading the report.
What a browser tab can and cannot observe, and why the extension and desktop tiers exist.
Back to the knowledge hub for the full SDK and proctoring series.
Online proctoring supervises remote exams via webcam and microphone inside your LMS, logging rule violations with timestamps so reviewers judge flagged cases, not every session.
AI proctoring uses machine learning to automatically detect suspicious exam behaviour such as multiple faces, tab switching, and absence from the camera.
A comparison of leading Moodle proctoring plugins for universities that need native LMS integration, AI monitoring, and institution-owned data.
How university exam offices choose online proctoring software for entrance grids, finals, and multi-faculty calendars, including stakeholder RFPs and centre-vs-online cost tradeoffs.
How certification bodies and training providers use online proctoring for identity proofing, item-bank protection, and defensible, audit-ready credentialing exams.
A side-by-side comparison of AI proctoring and live human proctoring for cost, scale, accuracy, and exam security.
Practical steps to reduce cheating in Moodle quizzes using proctoring settings, question banks, timing controls, and AI monitoring.
Feature-by-feature comparison of Moodle proctoring plugins covering integration, AI detection, pricing, and data storage.
A guide to online exam proctoring for Indian universities and certification providers, including compliance, pricing in INR, and local case studies.
How to choose between a proctoring LMS plugin, a browser SDK, and a REST API when adding proctoring to software you already own, with a decision guide and code examples.
A step-by-step guide to adding exam proctoring to a web app you own: mint a session on your backend, run the browser SDK, and read a server-side integrity report, with code from the API reference.
What browser-based proctoring can detect (tab switches, clipboard, faces, identity) and what it cannot (phones, a second monitor, a virtual machine), and why the tiering exists.
A step-by-step guide to adding exam proctoring to a React app: mint a session on your backend, wrap the browser SDK in a useEffect hook, handle StrictMode and token expiry, and read a server-side integrity report.
A step-by-step guide to adding exam proctoring to an Angular app: mint a session on your backend, hold the browser SDK in an injectable service, start it in ngOnInit and tear it down in ngOnDestroy, handle NgZone and token expiry, and read a server-side integrity report.
How LTI 1.3 connects a proctoring tool to your LMS: the OpenID Connect launch handshake, why it replaces LTI 1.1 shared secrets, how it compares to a Moodle plugin and the browser SDK, and how to read the same server-side integrity report.
A step-by-step guide to adding exam proctoring to an assessment platform you built: map your users, exams, and attempts to a session, mint it on your backend, run the browser SDK in your exam runner, and route the server-side integrity report into your own review workflow.
Your backend mints a session, the loader mounts the enclave, and the camera, token, and capture stay on an origin the candidate cannot reach. Add one line of CSP and run a real attempt before you commit.