GET /api/seb/tools/:courseId/:quizId) is documented on the SEB Student Routes page.
Detector Script Delivery
GET /js/canvas-seb-detector.js
The stable, canonical URL for the SEB detector script. Canvas theme loaders andjs_overrides configurations should always point to this path.
The server injects deployment-specific values into the script at response time: the application base URL, the LTI client ID, the LTI deployment ID list, and the debug/diagnostics flags. In production mode with a configured base URL the injected response is cached in-process for identical configuration tuples, and the same cached bytes are served to every subsequent request with the same parameters. Debug and diagnostics modes serve a non-cached, human-readable version of the script so issues can be diagnosed without a deployment rebuild.
Authentication: None. This is a public, unauthenticated endpoint.
Cache behaviour
The cache-control response header depends on the deployment mode:
The response also sets
pragma: no-cache, expires: 0, and vary: Origin, X-Forwarded-Host, X-Forwarded-Proto, X-Forwarded-Port so reverse proxies and CDNs do not cache the injected deployment constants across different origins.
Response
GET /api/seb/canvas-detector.js
A stable compatibility alias for/js/canvas-seb-detector.js. Canvas theme loaders that were configured before the primary URL was established continue to work without reconfiguration.
This route is handled by the same controller method and produces identical output to /js/canvas-seb-detector.js — same injection, same cache headers, same vary directive. No request is ever redirected; the alias is a true second route on the same handler.
New Canvas theme loader configurations should use
/js/canvas-seb-detector.js. The compatibility alias at /api/seb/canvas-detector.js is maintained for existing deployments.GET /js/canvas-seb-theme-loader.js
A minimal Canvas theme loader hosted by the application rather than uploaded to Canvas Files. Some self-hosted Canvas deployments reject locally stored theme JavaScript with Rails’InvalidCrossOriginRequest protection. Pointing Canvas’s js_overrides theme setting at this endpoint avoids that rejection while retaining the quiz-page-only detector loading behaviour.
Authentication: None. Public endpoint.
What the loader does
The loader is a self-invoking function that runs on every Canvas page load:
- Matches the current path against Classic Quiz take routes (
/courses/:courseId/quizzes/:quizId/take) and New Quiz assignment routes (/courses/:courseId/assignments/:assignmentId). It exits immediately on non-quiz pages and on New Quiz authoring paths (build, settings, moderate, reports, exports). - Constructs the canonical content ID —
classicquiz_{quizId}for Classic Quizzes ornewquiz:{courseId}:{assignmentId}for New Quizzes. - Calls
GET /api/seb/requirement/:courseId/:contentIdwithcredentials: omitandcache: no-store. If the response is not{ success: true, sebRequired: true }, it exits without loading the detector. - If the requirement check confirms SEB is required and no detector script tag is already present, it dynamically appends a
<script>element pointing to/js/canvas-seb-detector.js.
no-cache, must-revalidate in normal mode; no-cache, no-store, must-revalidate when debug is enabled.
What the Detector Does on Canvas Quiz Pages
Once loaded, the detector:- Reads
SafeExamBrowser.security.configKeyHashand the currentwindow.location.hreffrom the SEB JavaScript API. - Calls
POST /api/seb/access-proof/:courseId/:quizIdwith the Config Key hash and URL as the request body. - If the proof request succeeds, immediately calls
POST /api/seb/access-code/:courseId/:quizIdwith theproofTokenin thex-seb-proof-tokenrequest header. - Fills the Canvas access-code input when — and only when — Canvas presents an unambiguous access-code prompt, and the server returned a valid access code. The detector does not treat DOM content as authorisation; it fills a field only when the server has already validated SEB’s identity.
- Displays approved exam tools from the
toolsarray in the access-code response. - Waits for Canvas-authored completion evidence (Classic Quiz: successful final submission with a matching Canvas result structure; New Quiz: the authoritative result UI) before using the exit grant to display the settings-bound quit link.
SafeExamBrowser.security.configKeyHash is absent. The detector calls GET /api/seb/requirement/:courseId/:quizId first and shows the SEB-required prompt only when the server confirms SEB is needed — it never shows the prompt based on DOM inspection alone.
Why the Detector Is One Script
The public detector is served as a single JavaScript response. Its maintainable source is broken into modules assembled inmanifest.json order during development, tests, and the build. At runtime:
- The Canvas theme loader already limits detector loading to supported assessment routes where the requirement check returns
sebRequired: true. Splitting the detector into multiple browser requests would lose cross-fragment HTTP compression and introduce startup-ordering risk if a later fragment depends on state set by an earlier one. - The in-process cache for production responses means all concurrent students on the same page receive the same compressed bytes without additional database or filesystem reads.
- Diagnostics mode serves the readable, unminified assembly so issues can be traced in the browser console without a source map.
Requirement Check Caching
GET /api/seb/requirement/:courseId/:quizId performs one exact primary-key lookup against the assessments table and coalesces concurrent requests for the same assessment through a short, bounded in-process promise cache. The cache is stored per (courseId, canonicalContentId) tuple. All concurrent checks for the same assessment join the same pending promise instead of issuing parallel database reads.
The response always carries cache-control: private, no-store, max-age=0. Browsers and proxies must not cache the requirement result; staleness could cause the detector to show or hide the SEB-required prompt incorrectly after an instructor changes the assessment policy.
Debug Trace Endpoint
POST /api/debug/canvas-detector-trace
Accepts sanitised diagnostic events from the detector when the deployment has debug or diagnostics mode enabled.This endpoint is disabled in all normal production deployments. It returns
{ "enabled": false } immediately — without logging anything — unless both SEB_DEBUG_ENABLED or SEB_DETECTOR_DIAGNOSTICS_ENABLED is set and the TESTBED_ENABLED flag is active. Never enable the testbed flag in production; it is intended only for controlled non-production test environments.- Both
debugEnabled(ordetectorDiagnosticsEnabled) andtestbed.enabledmust betruein the application configuration. - The
Originheader must exactly match the configured Canvas domain origin. Requests from any other origin return{ "enabled": false }without recording. - A per-origin rolling window rate limit of 120 requests per 60 seconds is enforced. Exceeding it returns
429.
DetectorTraceService sanitises and records the payload. When detectorDiagnosticsEnabled is true, additional detail fields are recorded; when only debugEnabled is true, the recorded payload is reduced.
Success response — 200
429 is the only non-200 response, and only when the rate limit is exceeded on an otherwise-enabled endpoint.
Approved Tools Under Proof/Session Boundary
The detector callsGET /api/seb/tools/:courseId/:quizId to refresh the approved exam tool list after an access-code redemption, without re-running the full proof cycle. This endpoint is documented in full on the SEB Student Routes page, which covers all student-facing SEB endpoints including the tools route.
Server-Owned YouTube Player
GET /seb/tool/youtube/:videoId
Renders a server-owned single-video YouTube player page. Instructors can create a dedicated YouTube video tool that accepts a watch, share, Shorts, or embed link; the server converts the accepted formats into this endpoint with the canonical YouTube video ID. YouTube requires a valid embedding identity (a stable HTTPS origin in the embed URL’sorigin parameter). Because SEB opens tools in a separate window, the player page is the embedding document, and the server supplies that stable origin rather than relying on the SEB window’s origin.
Authentication: None. Public endpoint.
Path parameters
string
required
An 11-character YouTube video ID. Must match
[A-Za-z0-9_-]{11}. Any other value returns 404.YouTube URL formats the tool creation flow accepts
YouTube URL formats the tool creation flow accepts
- YouTube browsing (
www.youtube.comnavigation, channel pages, search) is not available from this page. - Google sign-in flows are blocked; the page does not include
accounts.google.comin any allow-list. - No scripts, images, or styles other than inline
<style>are permitted. - No
<form>submissions and no<base>element are allowed.
<iframe> pointing to https://www.youtube.com/embed/<videoId>?rel=0&origin=<applicationOrigin>.
Error response