proctoring-sdk
v0.2.0
Published
An AI-powered integrity monitoring solution for online assessments. This SDK integrates real-time webcam face-presence detection, screen share verification, browser tab focus tracking, and activity logging directly into your React application.
Readme
Proctoring SDK (proctoring-sdk)
An AI-powered integrity monitoring solution for online assessments. This SDK integrates real-time webcam face-presence detection, screen share verification, browser tab focus tracking, and activity logging directly into your React application.
Features
- Face Presence Monitoring: Detects face presence, face absence, and multi-face conditions.
- Screen Share Tracking: Restricts candidates to sharing their entire monitor and detects when sharing is stopped.
- Tab & Focus Tracking: Logs incidents when the user switches tabs, minimizes the window, or loses focus.
- Copy/Paste Log: Logs clipboard copy, cut, and paste interactions during active assessment sessions.
- Host-Owned Error Recovery: Startup permission/network errors pass rich structured diagnostic data and retry closures to the host application for customized presentation.
- In-Session Overlays & Telemetry: Fullscreen enforcement, screen interruption alerts, multi-monitor warnings, violation toasts, and live face feedback are handled seamlessly inside the SDK.
- Offline Mode: Automatically queues telemetry events locally when connection is lost, using cryptographic obfuscation, and flushes them when online status is restored.
- GDPR-Aligned Data Storage: Ensures all telemetry and screenshots are immediately removed from the candidate's browser local storage after they are uploaded.
Getting Started
- Sign Up: Create your developer account on the Protector Dashboard.
- Get Your API Key: Go to Settings -> API Keys inside your dashboard and copy your secret
Host API Key. This key is used on your backend server to create candidate sessions.
Installation
Install the package and its peer dependencies via npm:
npm install proctoring-sdkNote: Requires React 18 or 19 and react-dom in the host application.
Quick Start Integration
1. Server-Side: Create a Session
To keep your credentials secure, session registration must be done on your backend server. Use createSession with your Host API Key (retrieved from the Developer Dashboard) and return the sessionToken to your browser.
import { createSession } from "proctoring-sdk";
import type { SessionPolicy } from "proctoring-sdk";
export async function startCandidateAttempt(candidateDetails) {
// Define what proctoring metrics to enforce
const policy: SessionPolicy = {
cameraMonitoring: true, // Enforce face presence
screenMonitoring: true, // Enforce screen share
tabSwitching: true, // Enforce tab focus
copyDetection: true, // Track clipboard copy
pasteDetection: true, // Track clipboard paste
fullscreenRequired: true, // Enforce fullscreen mode
captureEvidence: true, // Capture screenshots on incident trigger
multipleMonitorDetection: true, // Warn on multi-monitor setups
};
const session = await createSession(
{
hostApiKey: process.env.PROCTORING_HOST_API_KEY,
},
{
sessionReferenceId: candidateDetails.attemptId,
expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
testDurationMinutes: 120,
candidate: {
fullName: candidateDetails.fullName,
email: candidateDetails.email,
location: candidateDetails.location,
},
job: { position: "Software Engineer" },
policy,
}
);
return {
sessionToken: session.sessionToken,
sessionId: session.sessionId,
};
}2. Client-Side: Mount the Component & Handle Errors
Import the <ProctoringSession> component in your React application. Wrap your assessment cards inside it, passing the sessionToken retrieved from your backend.
When startup or permission issues occur (e.g. camera denied, screen share canceled), the SDK yields full-screen rendering to your host app and invokes onError with structured diagnostics and a retry closure.
"use client";
import React, { useState } from "react";
import { ProctoringSession } from "proctoring-sdk";
import type { IncidentEvent, ProctoringError, SessionCompleteResult } from "proctoring-sdk";
export function AssessmentPortal({ sessionToken }: { sessionToken: string }) {
const [errorState, setErrorState] = useState<ProctoringError | null>(null);
// Host-owned error UI
if (errorState) {
const { diagnosis, retry } = errorState;
return (
<div className="error-card">
<h2>{diagnosis?.title || "Session Setup Issue"}</h2>
<p>{diagnosis?.cause || errorState.message}</p>
{diagnosis?.steps && (
<ol>
{diagnosis.steps.map((step, i) => (
<li key={i}>{step}</li>
))}
</ol>
)}
{diagnosis?.retryable && (
<button
type="button"
onClick={() => {
setErrorState(null);
retry?.();
}}
>
Retry Setup
</button>
)}
</div>
);
}
return (
<ProctoringSession
sessionToken={sessionToken}
options={{ debug: false, fullscreenRequired: true, multipleMonitorCheck: true }}
onReady={() => {
setErrorState(null);
console.log("Proctoring active");
}}
onIncident={(incident: IncidentEvent) => {
if (incident.type === "heartbeat") return;
console.log(`Infraction recorded: ${incident.type} (Severity: ${incident.severity})`);
}}
onComplete={(result: SessionCompleteResult) => {
window.location.href = result.redirectUrl || "/complete";
}}
onError={(error: ProctoringError) => {
console.error("Proctoring error:", error.code, error.diagnosis);
setErrorState(error);
}}
>
{/* Mount your actual exam components inside here */}
<div className="exam-card">
<h2>Assessment Question 1</h2>
<p>Answer the following question...</p>
</div>
</ProctoringSession>
);
}API Reference
<ProctoringSession> Props
| Prop | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| sessionToken | string | Yes | Short-lived authorization token received from your backend createSession call. |
| options | ProctoringSessionOptions | No | Overrides for thresholds, intervals, and debug controls. |
| onReady | () => void | No | Callback triggered when camera, screen, and browser listeners have successfully started. |
| onIncident | (incident: IncidentEvent) => void | No | Callback triggered whenever a monitoring incident is recorded. |
| onComplete | (result: SessionCompleteResult) => void | No | Callback triggered when the session is successfully finalized. |
| onError | (error: ProctoringError) => void | No | Callback triggered on startup, permission, or network failure with diagnosis metadata and retry handler. |
ProctoringError & StartupErrorDiagnosis
When onError fires, it receives a ProctoringError instance:
export interface ProctoringError {
code: string; // Machine-readable code (e.g. camera_permission_denied)
message: string; // Human-readable message
details?: unknown; // Underlying exception or event details
diagnosis?: StartupErrorDiagnosis; // Structured troubleshooting guidance
retry?: () => void; // Closure that resets state and re-runs monitoring startup
}
export interface StartupErrorDiagnosis {
code: string; // Standardized error code
title: string; // Suggested UI heading (e.g. "Camera access is blocked")
cause: string; // Plain-language explanation of what went wrong
steps: string[]; // Numbered step-by-step remediation steps for the candidate
retryable: boolean; // Whether the issue can be resolved with an immediate retry
}ProctoringSessionOptions Configuration
| Option | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| debug | boolean | false | Enables detailed telemetry logs in the browser console. |
| detectionIntervalMs | number | 2000 | Frequency in milliseconds at which the AI models run face presence detection. |
| heartbeatIntervalMs | number | 30000 | Frequency in milliseconds for sending diagnostic checkups to the server. |
| lowEndMode | boolean | Auto-detected | Runs smaller models and throttles intervals on low-resource machines. |
| fullscreenRequired | boolean | false | Shows an in-session modal requiring the user to remain in fullscreen mode. |
| multipleMonitorCheck| boolean | false | Detects extended multi-monitor displays on Chromium browsers. |
Publishing to NPM (Maintainers)
Build and test the package:
npm run build npm run typecheckVerify bundle contents:
npm pack --dry-runAuthenticate & Publish:
npm login npm publish --access public
