# Detector

> Problems on the Canvas quiz page — the detector not loading, the HTTP 422 theme-file case, the access code not filling, and tools or exit not appearing.

[Canonical HTML page](https://safeonlineexam.com/docs/troubleshooting/detector)

The detector is the script loaded through your Canvas theme that runs on quiz
pages. These symptoms are visible in the browser on a Classic Quiz `/take` page or
a New Quiz assignment route.

## Detector never loads [#detector-never-loads]

**Check, in order:**

<Steps>
  <Step>
    The active account 

    **theme**

     actually includes the loader, and inherited-theme behavior is not overriding it at this account scope.
  </Step>

  <Step>
    The browser 

    **console / CSP**

     is not blocking the script.
  </Step>

  <Step>
    The public detector URL returns JavaScript: 

    `curl -fsS "${TOOL_URL}/js/canvas-seb-detector.js" | head`

    .
  </Step>

  <Step>
    You are on an actual assessment route the loader matches — a Classic Quiz 

    `/take`

     page or a New Quiz assignment route.
  </Step>
</Steps>

Retest after any significant Canvas theme, CSP, or quiz-rendering change. Setup
details are in [Load the detector script](/docs/canvas/detector-script).

## An ordinary Canvas access-code quiz does not show the SEB prompt [#an-ordinary-canvas-access-code-quiz-does-not-show-the-seb-prompt]

This is expected when that Classic Quiz or New Quiz is not enabled in Safe Online
Exam. The detector treats an access-code field only as a challenge signal and
checks the exact course and assessment before prompting. A missing, mismatched,
disabled, malformed, unavailable, or rate-limited requirement check fails safely
to the normal Canvas flow.

If the assessment **should** require SEB, refresh its course data, confirm that
SEB is enabled with a valid effective exit password, and test the current Canvas
assessment route. Do not use the presence of a Canvas access-code field alone as
evidence that Safe Online Exam should launch.

## The launch prompt cannot locate the Canvas course installation [#the-launch-prompt-cannot-locate-the-canvas-course-installation]

The prompt says that Safe Online Exam needs attention and offers **Reload page**
instead of **Open Safe Exam Browser**. The detector could not find a matching
installed LTI tool through Canvas or a usable rendered course-navigation link.
It deliberately does not send the student to the course home as a substitute.

**Check, in order:**

1. Select **Reload page** once and retry from the actual protected assessment.
2. Confirm the external app remains installed in the course or inherited from its
   Canvas account, even if its student navigation item is hidden.
3. Confirm the deployed `LTI_CLIENT_ID` and, in strict mode, the configured
   `LTI_DEPLOYMENT_ID` match the installed Canvas tool. For controlled
   self-service mode, confirm the installed tool uses the configured client ID.
   On a sharded Canvas instance, keep the globally qualified `LTI_CLIENT_ID`:
   Canvas can list its corresponding Developer Key in shard-local form.
4. Ask a Canvas administrator to correct the installation or deployment
   configuration, then repeat the hidden-navigation acceptance test.

See [Install the external app](/docs/canvas/install-app#hiding-the-student-navigation-tab)
for the policy and [Verify the integration](/docs/operate) for the acceptance
sequence.

## HTTP `422` on the theme JavaScript file [#http-422-on-the-theme-javascript-file]

The browser console shows `422` (`ActionController::InvalidCrossOriginRequest`) for
the uploaded theme file. This is a self-hosted Canvas attachment-serving
limitation, not a detector or LTI failure.

<Callout type="warn" title="Do not disable Canvas CSRF protection">
  Do **not** globally disable CSRF protection to work around this.
</Callout>

**Fix:** point the account theme's `js_overrides` at the hosted loader
`${TOOL_URL}/js/canvas-seb-theme-loader.js`, or configure S3-compatible attachment
storage for the durable fix. Full procedure and the one-off recovery command are in
[Detector script → the local-file (422) case](/docs/canvas/detector-script#self-hosted-canvas-the-local-file-http-422-case).

## Access code is not filled in SEB [#access-code-is-not-filled-in-seb]

The detector loaded, but the code did not appear in the Canvas prompt. This means
the release gate did not pass, or the prompt was ambiguous.

**Check:**

* A **fresh** configuration was downloaded (a stale one fails Config Key proof).
* The detector loaded on the **actual** assessment route.
* **Config Key proof succeeded** — if a protected setting changed, the old
  configuration no longer proves; download again.
* The Canvas access-code prompt is unambiguous; the detector only fills a clear
  prompt and never treats page content as authorization.

If proof itself is failing, continue to
[SEB configuration](/docs/troubleshooting/seb-configuration).

## Approved tools are missing, or exit will not trigger [#approved-tools-are-missing-or-exit-will-not-trigger]

* **Tools not showing:** approved tools are only exposed **after** a valid SEB
  proof. Before proof, they are intentionally hidden — this is not a bug. Confirm
  proof succeeded and the tool is enabled for this assessment.
* **A disabled tool still loads:** the detector sidebar is only an affordance; the
  SEB URL filter in the configuration is the control. Confirm the configuration is
  current — a settings change requires a fresh download.
* **Exit does not trigger:** the detector waits for **Canvas-authored** completion —
  a successful Classic Quiz submission result, or the New Quiz authoritative result
  UI. If a submission was cancelled, no exit begins, by design. Unbound manual/auto
  quit routes deliberately return `410`; only a completion-bound exit grant shows
  the quit link.

## Enabling detector diagnostics (non-production) [#enabling-detector-diagnostics-non-production]

On a non-production deployment you can set `APP_DETECTOR_DIAGNOSTICS_ENABLED=true`
to stream sanitized detector detail (URLs, iframe origins, gate decisions) for
debugging. The production profile rejects this — do not enable it on a prod
deployment.