The integration of the proctoring system with the Canvas LMS is done using the Learning Tools Interoperability (LTI) and the Supervisor SDK (JavaScript proctoring library). First, you need to place the custom SDK code on one of the HTML pages in the LMS, and then configure the LTI in the course module to access proctoring through the LMS.
Go to your course and open your quiz in preview mode. Copy the quiz URL from your browser's address bar to use later as the “url” custom parameter from Section 4. To prevent the quiz from being opened without proctoring you should set up access restrictions to the quiz by code. To do this, you need to enable the "Access code required" option in the quiz element settings:
When running an assessment under proctoring, which is limited by an access code, the code will be automatically inserted into the input field and the participant will be able to start the assessment. In addition, you can restrict access to the quiz without proctoring after the access code is entered correctly the first time. To do this, just add the word “proctoring” to the quiz title. Note that this only works if you upload the proctoring script using the Theme Editor (see Section 3.1).
For proctoring to work, you need to place the SDK code on the Canvas LMS page with the same domain as the quiz. This is required for opening the quiz in IFRAME within the proctoring session without cross-origin issues.
You can use the Theme Editor in Canvas LMS to inject the proctoring code into all pages in the LMS. This method is described in this guide. To do this, follow these steps:
JavaScript
(function (host) {
if (window.self === window.parent) {
if (window.ENV && window.ENV.current_user_roles.includes('student')) {
if (/^\/courses\/\d+\/quizzes\/\d+/.test(location.pathname)) {
var title = document.getElementById('quiz_title');
if (title && /proctoring/.test(title.innerText)) {
var block = document.getElementById('not_right_side');
if (block) block.innerHTML = '<h1>Access Denied</h1>';
}
}
}
var params = new URLSearchParams(location.search);
if (params.get('token')) {
var script = document.createElement('script');
script.setAttribute('src', `https://${host}/sdk/supervisor.js`);
script.onload = function () {
var supervisor = new window.Supervisor({ url: `https://${host}` });
supervisor.on(['fail', 'stop'], function () {
supervisor.logout({ redirect: true });
});
supervisor.sync({ token: params.get('token') }).then(function () {
return supervisor.start();
});
};
document.head.appendChild(script);
}
}
else {
$(document).on('submit', function (e) {
var form = e.target;
if (/post/i.test(form.method)) {
var url = new URL(form.action);
var xhr = new XMLHttpRequest();
xhr.open('POST', form.action);
xhr.addEventListener('load', function () {
location.href = url.searchParams.get('next_question_path') || url.href;
});
xhr.send(new FormData(form));
e.preventDefault();
}
});
}
})('demo.proctoring.app');
NOTE: you need to replace "demo.proctoring.app" with the domain of your proctoring server in the script code.
Enable the ability to load custom JavaScript in "Admin" → "Settings" → "Features" → "Custom CSS/JavaScript overrides"
.
Open the current theme in the theme editor "Admin" → "Themes" → "Open in Theme Editor"
and upload the file "proctoring.js" section of the editor "Upload" → "JavaScript file"
.
Save your changes by clicking the “Preview Your Changes”, then the “Save theme” and "Apply theme" buttons.
Use this URL in the Launch URL from Section 4 in the “redirect” parameter:
https://demo.proctoring.app/api/auth/canvas?redirect=https://your-canvas-server
NOTE: you need to replace "demo.proctoring.app" with the domain of your proctoring server and “your-canvas-server” with your Canvas server domain.
If the previous method does not work, you can upload the proctoring script as an HTML file and use a link to the file in the LTI Tool URL with the redirect parameter. To do this, follow these steps:
JavaScript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Proctoring</title>
</head>
<body>
<p>There is nothing here. This is a service page for proctoring.</p>
<script src="//demo.proctoring.app/sdk/supervisor.js" data-supervisor="sync"></script>
<script>
if (window.supervisor) {
supervisor.on('load', function (iframe) {
var { contentDocument, contentWindow } = iframe;
contentWindow.$(contentDocument).on('submit', function (e) {
var form = e.target;
if (/post/i.test(form.method)) {
var action = form.action;
var url = new URL(action);
var xhr = new XMLHttpRequest();
xhr.open('POST', action);
xhr.addEventListener('load', function () {
contentWindow.location.href = url.searchParams.get('next_question_path') || url.href;
});
xhr.send(new FormData(form));
e.preventDefault();
}
});
});
}
</script>
</body>
</html>
NOTE: you need to replace "demo.proctoring.app" with the domain of your proctoring server in the script code
Example of the URL: https://your-canvas-server/courses/1/files?preview=2
/courses/<course_id>/files?preview=<file_id>
/courses/<course_id>/files/<file_id>/preview
Use this URL in the Launch URL from Section 4 in the “redirect” parameter:
https://demo.proctoring.app/api/auth/canvas?redirect=https://your-canvas-server/courses/1/files/2/preview
NOTE: you need to replace "demo.proctoring.app" with the domain of your proctoring server and “your-canvas-server” with your Canvas server domain.
Sometimes it does not work because the domain for uploading files is different from the quiz domain (e.g. the Instructure.com cloud). In this case, you should try the next method.
First, you need to add a new application to your course settings (or entire Canvas instance settings). To do this, go to "Settings" → "Apps" → "Add App"
and in the window that opens, fill in the fields according to the following sample:
this key for your proctoring server is issued by the manager
this key for your proctoring server is issued by the manager
https://demo.proctoring.app/api/auth/canvas?redirect=<sdk_page>
the demo.proctoring.app
is used as an example only, please specify the address of your proctoring server instead; <sdk_page>
is a page with the proctoring script code, or the Canvas home page if you used the Theme Editor.
the demo.proctoring.app
is used as an example only, please specify the address of your proctoring server instead
url=<quiz_url>
(format "/courses/<course_id>/quizzes/<quiz_id>/take
")
code=<quiz_password>
Colored fields should be replaced with your values. You can specify additional parameters in the KEY=VALUE format in the custom fields, if necessary. These are the parameters that will be sent to the proctoring system when the test-taker starts the application. In the “url” parameter you should specify the URL to the quiz in Canvas LMS. In the “code” parameter you should specify the access code to the quiz.
Now you need to add a new course element to a specific module. To do this, go to "Modules" → "[+] Add Item". In the window that opens, select "External Tool" and highlight the added application in the previous step. The fields "URL" and "Page Name" are filled in automatically, and the checkbox "Load in a new tab" must be checked manually.
If you want to add an LTI app to an entire instance of Canvas and use it in any course, you can do this without specifying LTI custom fields such as "url" or "template". Instead, you can bypass the "url" or "template" parameter in the URL field when adding the application to the course module.
The URL looks like this:
https://demo.proctoring.app/api/auth/canvas?redirect=https://your-canvas-server&template=quiz1&url=/courses/<course_id>/quizzes/<quiz_id>/take
Now, when a test-taker navigates through the proctoring link, they will begin to take an associated quiz according to the proctoring workflow. Clicking on the proctoring link takes an administrator or teacher to the proctoring interface, where they can access all sessions and their reports created by that link.
To connect the integration API with Canvas LMS, you need to load the following config with integration parameters under the proctoring system manager:
JSON
{
"id": "<Host_ID>",
"key": "<License_Key>",
"params": {
"webhooks": {
"canvas": {
"authorizer": "lti",
"integrator": "lti",
"consumerKey": "demo",
"consumerSecret": "secret",
"callbackURL": "query.redirect",
"profile": {
"username": "payload.user_id",
"role": "payload.roles.find(v=>/Instructor/.test(v))?'proctor':'student'",
"nickname": "payload.lis_person_name_full",
"lang": "(payload.launch_presentation_locale||'').slice(0,2)",
"group": "['G',payload.context_id,payload.resource_link_id].join('-')",
"referrer": "payload.launch_presentation_return_url",
"labels": "payload.lis_person_contact_email_primary"
},
"register": {
"identifier": "[payload.user_id,payload.context_id,payload.resource_link_id].join('-').replace(/[^A-Za-z0-9_-]+/g,'_')",
"template": "query.template||payload.custom_template",
"subject": "payload.resource_link_title",
"members": "payload.custom_members==='@'?user.group:payload.custom_members",
"url": "query.url||payload.custom_url",
"code": "payload.custom_code",
"tags": "payload.lis_person_contact_email_primary"
},
"start": true,
"stop": true,
"pause": true,
"submit": true
}
}
}
}
NOTE: the fields
consumerKey
andconsumerSecret
need to be replaced with a randomly generated sequence of characters (Latin letters of different case and numbers, the recommended length is 24 characters);id
is the ID of the host (if you do not specify it, a new host will be created);key
is the license key of this host.