Introduction
Welcome to the AutoProctor SDK! AutoProctor is an automated tool which ensures that users do not cheat while taking online exams. It tracks their environment and actions using data from sources like their mic and camera. It monitors these data and detects anomalous events.
With our JavaScript SDK, you can enable AutoProctor on your own site. You can view code examples in the dark area to the right.
Authentication
Key Pair
AutoProctor uses a pair of API keys to authorize requests. There is a public CLIENT_ID
key and a secret CLIENT_SECRET
key. You can get your key pair by registering on our developer portal.
HMAC
AutoProctor uses HMAC with SHA256 for Authentication. Your CLIENT_SECRET
is the key for HMAC, and the relevant parameter is the message. Also, every request must carry your CLIENT_ID
. Therefore, every request will carry the CLIENT_ID
, the message and the HMAC of the message.
For instance, if you want to check that your key pair is valid, you may make a request to https://autoproctor.co/api/validate/?client_id=<client_id>&client_secret=<client_secret>
as shown in the code. If you receive a response with the same message as in the query parameter, it means that your key pair is valid.
To verify if your key pair is valid
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
const CLIENT_ID = "Hdy13o87";
const CLIENT_SECRET = "Jbso5da3H86m";
const message = "Hello";
const hmacMessage = CryptoJS.HmacSHA256(message, CLIENT_SECRET).toString(CryptoJS.enc.Hex);
const searchParams = new URLSearchParams({
"client_id": PUBLIC_KEY,
"message": message,
"hmac_message": hmacMessage
});
let url = "https://autoproctor.co/api/validate/";
url.search = searchParams;
await fetch(url);
Make sure to replace CLIENT_ID and CLIENT_SECRET with your values
Initialization
Test Attempt ID
AutoProctor doesn't need details of your users, or the test they attempted, and so on. It identifies each test attempt by a testAttemptId
. This is a unique ID that your own platform generates. For example, if User 4 attempted Quiz 3 twice, your platform must be able to generate two testAttemptId
s. It is this testAttemptId
that you will use to identify sessions on AutoProctor.
Including JS Library
On the webpage where you want to enable AutoProctor, you include our JS library and initialise it as shown in the code. The last part of the code must load after the DOM has loaded. So, wait for the window.onload
event. apOptions
is a dictionary object with the following mandatory keys:
To initialize, first include these two JS files in your
<head>
tag
<script src='https://ap-statics.s3.ap-south-1.amazonaws.com/autoproctor.2.5.min.js'></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
const CLIENT_ID = "Hdy13o87";
const CLIENT_SECRET = "Jbso5da3H86m";
const testAttemptId = CryptoJS.lib.WordArray.random(8).toString(CryptoJS.enc.Hex);
const hashedTestAttemptId = CryptoJS.HmacSHA256(testAttemptId, CLIENT_SECRET).toString(CryptoJS.enc.Hex);
const trackingOptions = {"audio": false, "numFaces": false};
const apOptions = {
'clientId': CLIENT_ID,
'testAttemptId': testAttemptId,
'hashedTestAttemptId': hashedTestAttemptId,
'trackingOptions': trackingOptions
}
Then, within
$(document).ready
orwindow.onload
, have the following line
autoProctorInstance = await initAutoProctor(apOptions);
apOptions
Parameter | Properties | Description |
---|---|---|
clientId | string, required | Your CLIENT_ID that identifies you as the sender of the data |
testAttemptId | string, required | The unique identifier for the test attempt |
hashedTestAttemptId | string, required | The SHA-256 HMAC of the testAttemptId with your CLIENT_SECRET |
trackingOptions | dictionary | What AutoProctor will track and record. Described below |
trackingOptions
These are the main parameters that would be part of your trackingOptions
dictionary. There are a few additional parameters that are mentioned in the next Section.
Parameter | Datatype | Default | Description |
---|---|---|---|
audio | bool | true | Track Audio? |
numHumans | bool | true | Check only one face looking at camera |
tabSwitch | bool | true | Detect if user switched tabs/application |
photosAtRandom | bool | true | Take photos randomly throughout the test |
numPhotosAtRandom | int | 5 | How many random photos to take |
userScreen | bool | true | Capture screenshot if user switches tab |
captureSwitchedTab | bool | true | Capture screenshot if user switches tab |
preventMultipleScreens | bool | true | Detect multiple monitors (browser-dependent) |
Additional Tracking Options
Apart from the parameters mentioned above, you may add the following parameters too:
Parameter | Datatype | Default | Description |
---|---|---|---|
informUser | bool | true | Should the user get notified of the violations? |
restrictConsole | bool | false | If true then nobody will be able to use the console once the test starts. This option is recommended for Production |
userDetails | dict | {} | Any additional information about the user that you share, so that you can later search by the user |
evidencePushInterval | int | 15 | Frequency (in seconds) at which violation data are pushed to the server |
Results
Get Attempt Result
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
const CLIENT_ID = "Hdy13o87";
const CLIENT_SECRET = "Jbso5da3H86m";
const testAttemptId = //Insert Test Attempt ID//;
const hashedTestAttemptId = CryptoJS.HmacSHA256(testAttemptId, CLIENT_SECRET).toString(CryptoJS.enc.Hex);
const searchParams = new URLSearchParams({
"hashedTestAttemptId": hashedTestAttemptId
});
let url = "https://www.autoproctor.co/tenant/" + clientId + "/test-attempts/id/ "+ testAttemptId;
url.search = searchParams;
await fetch(url);
The above command returns JSON structured like this:
{
"attemptDetails": {
"startedAt": "2021-05-11T17:27:28+0000",
"finishedAt": "2021-05-11T18:15:28+0000",
"trustScore": 0.83,
"device": "Mobile",
},
"proctorSettings": {
"track": {"audio": false, "numFaces": false},
"parameters": {}
},
"evidence": [
["no-face-looking-at-camera", "2021-05-11T17:32:18+0000", true, "sampleevidenceurl.com"],
["noise-detected", "2021-05-11T17:42:28+0000", true, "sampleevidenceurl.com"],
["random-photo", "2021-05-11T18:02:22+0000", false, "sampleevidenceurl.com"],
["tab-focus-lost", "2021-05-11T18:12:39+0000", true, null]
]
}
This endpoint retrieves the results of a given Test Attempt. It contains details like the Trust Score and a list of all the violations, their evidence, etc.
HTTP Request
GET https://www.autoproctor.co/tenant/<client_id>/test-attempts/id/<test_attempt_id>/
Query Parameters
Parameter | Description |
---|---|
clientId | CLIENT_ID |
hashedTestAttemptId | The SHA-256 HMAC of the testAttemptId with your CLIENT_SECRET |
Response
Parameter | Type | Description |
---|---|---|
evidence | list | [evidence_label, evidence_iso_datetime, is_violation?, evidence_url] |
Customising SDK Behaviour
Introduction
Most of AutoProctor’s functionality is driven by JavaScript’s Custom Events. For instance, if the SDK detects that there are multiple faces detected by the camera, it emits an event, with a specific event code. The SDK then handles the event, based on the event code. This is the default behaviour.
Event Types
There are three events that the SDK emits:
Type | Description |
---|---|
autoproctorStatusEvent |
Emitted as the SDK loads and starts tracking the user. Each event is a ‘good’ event, in that every time an event is emitted, it means that the SDK has finished the current stage of loading, and is proceeding to the next stage. |
autoproctorErrorEvent |
Occurs when there is an issue loading the SDK or starting the proctoring. For example, if a user denies access to her camera, this event is triggered. |
autoproctorEvidenceEvent |
Occurs after the proctoring has started. Each violation is an event. |
For example, the multiple faces detected is an autoproctorEvidenceEvent
. The event code for the event is 5002. So, if you want to stop the test if multiple faces are detected, you listen to the autoproctorEvidenceEvent and if the code is 5002, you can stop showing the test, say. Look at the sample code for a simple implementation.
If you want to extend the functionality, you would add something like this
window.addEventListener("autoproctorErrorEvent", (e) => {
const { errorCode, errorDetails } = e.detail;
if (errorCode === 5002) {
alert(“You cannot proceed with the test.”);
}
}
Event Codes
Code | Violation? | Event Type | Explanation |
---|---|---|---|
2001 | - | autoproctorStatusEvent |
Browser is compatible. User has granted permissions |
2003 | - | autoproctorStatusEvent |
Video and ML model loaded. Ready to start face detection |
4001 | - | autoproctorErrorEvent |
Incompatible Browser. Doesn't pass checkBrowserCompatiblity() |
4002 | - | autoproctorErrorEvent |
From permissions API, user has already blocked access to camera |
4003 | - | autoproctorErrorEvent |
From permissions API, user has already blocked access to microphone |
4004 | - | autoproctorErrorEvent |
User has proactively declined access to camera/microphone. Or, the page is being loaded within an insecure context. |
4005 | - | autoproctorErrorEvent |
Hardware error, insecure context, or some other error. |
4006 | - | autoproctorErrorEvent |
From permissions API, user has already blocked access to camera and mic |
4007 | - | autoproctorErrorEvent |
Audio Not Readable Error in getUserMedia |
4008 | - | autoproctorErrorEvent |
Video Not Readable Error in getUserMedia |
4007 | - | autoproctorErrorEvent |
Mic Not Found in getUserMedia |
4008 | - | autoproctorErrorEvent |
Camera Not Found in getUserMedia |
4009 | - | autoproctorErrorEvent |
We weren't able to find a microphone on your device. You need to enable your microphone, or use another device that has a microphone to take this test. |
4010 | - | autoproctorErrorEvent |
We weren't able to find a camera (or webcam) on your device. You need to enable your camera, or use another device that has a camera to take this test. |
4011 | - | autoproctorErrorEvent |
Permission to access a screen area was denied by the user, or the current browsing instance is not permitted access to screen sharing. Please reload the page to provide the access. |
4012 | - | autoproctorErrorEvent |
The user selected a screen, window, tab, or other source of screen data, but a hardware or operating system level error or lockout occurred, preventing the sharing of the selected source. |
4013 | - | autoproctorErrorEvent |
No sources of screen video are available for capture. |
4014 | - | autoproctorErrorEvent |
You must share your entire screen in order to proceed with the test. Please reload the page to select again. |
4015 | - | autoproctorErrorEvent |
We have detected multiple monitors. Please disconnect the extra monitor (or displays like Chromecast). If you continue without disconnecting, your teacher will be informed of multiple monitors. |
4016 | - | autoproctorErrorEvent |
Use latest version of Safari on iPhone or iPad. Else, use Chrome |
4017 | - | autoproctorErrorEvent |
Please use Chrome or Firefox, if you want to procced with the test. (if forceCaptureSwitchedTab is true) |
5001 | Yes | autoproctorEvidenceEvent |
No one looking at camera Yes |
5002 | Yes | autoproctorEvidenceEvent |
More than 1 Person in Video |
5003 | No | autoproctorEvidenceEvent |
Random photo taken No |
5004 | Yes | autoproctorEvidenceEvent |
Audio above background levels Yes |
5005 | Yes | autoproctorEvidenceEvent |
User switched away from current tab to another tab or application Yes |
5006 | No | autoproctorEvidenceEvent |
User returned to test tab from another tab or application No |
5007 | - | autoproctorEvidenceEvent |
Multiple Monitors detected |