> ## Documentation Index
> Fetch the complete documentation index at: https://docs.talview.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Proview SDK — v7 to v8 Migration Guide

<Note>
  Client-side Proview SDK migration: v7 → v8 · Script: `https://sdk.tlv.cx/session/init.js`

  **Official v8 docs:** [Getting Started](/sdk/proctoring/getting-started) · [Full API Reference](/sdk/proctoring/configuration) · [Session Playback](/sdk/session-playback/getting-started)

  This guide covers migration-specific changes and before/after code only. Refer to the official docs links above for complete API reference, parameter defaults, and current examples.
</Note>

## Breaking changes

All changes below require code modification. Severity indicates what breaks without the fix.

### 🔴 Critical — the integration will not load without these

**Script URL has changed.** Update the loader on every page that runs proctoring.

```html theme={null}
<!-- v7 -->
<script async src="https://cdn.proview.io/client/init.js"></script>

<!-- v8 -->
<script async src="https://sdk.tlv.cx/session/init.js" crossorigin="anonymous"></script>
```

**Global namespace renamed: `ProctorClient3` → `Proview`.** `window.ProctorClient3` no longer exists. All method calls move under `Proview.session.*`.

```js theme={null}
// v7
window.ProctorClient3.start();
window.ProctorClient3.stop();
window.ProctorClient3.on(/* ... */);

// v8
Proview.session.start();
Proview.session.stop();
Proview.session.on(/* ... */);
```

**Authentication credential changed: `proctor_token` → `dsn`.** v7 used a per-session `proctor_token` UUID. v8 uses a project-level Data Source Name (DSN). Contact Talview support to provision your DSN.

**Initialization pattern changed: command queue → `proviewOnLoad` callback.** v7 used a command queue (`window.tv`). v8 requires `window.proviewOnLoad` to be defined **before** the script tag; the `Proview` global is available inside the callback.

```js theme={null}
// v7
window.tv = window.tv || function () { (tv.q = tv.q || []).push(arguments); };

// v8
window.proviewOnLoad = async function () {
  // Proview global is available here
  const success = await Proview.session.init({ /* ... */ });
  if (!success) return;
};
```

### 🟠 High — behavioral breakage

**Session start is now a Promise, not a callback.** `initCallback(err, uuid)` is removed. `session.start()` returns a Promise that resolves with a `SessionOutput`.

```js theme={null}
// v7
tv('init', token, {
  initCallback: function (err, uuid) {
    if (err) return;
    ProctorClient3.start();
  },
});

// v8
const output = await Proview.session.start();
console.log('Session UUID:', output.uuid);
```

**Client-side alert events removed — monitoring is now server-side via webhooks.** v7 fired per-alert events via numeric IDs (`ProctorClient3.on('log:event:type:16', cb)`). v8 has **no client-side alert events**. All monitoring happens server-side and is delivered as structured **incidents** to your registered webhook endpoint. The only suspension signal visible client-side is the `Suspend` hook. See [Webhooks overview](/graph-api-reference/webhooks/overview).

**Error handling is now global, not per-init.** Register `Proview.onError(handler)` once **before** calling `session.init()`. The per-init `errorCallback` is removed.

```js theme={null}
Proview.onError(function (err) {
  // err.code, err.message, err.type: 'warning' | 'critical'
});
```

**Network events are now object-based, not a single callback.** `networkDisconnectionCallback` is removed. Use the `NetworkStatusChanged` hook. The callback receives an object `{ status: 'online' | 'offline' }`, not a string.

```js theme={null}
Proview.session.on('NetworkStatusChanged', function ({ status }) {
  if (status === 'offline') showBanner();
  if (status === 'online') hideBanner();
});
```

**Webhook payload format has changed.** The v7 `rating_callback_url` flat payload is replaced by a typed, versioned JSON envelope. See [Webhooks overview](/graph-api-reference/webhooks/overview) and [Subscribing to webhooks](/graph-api-reference/webhooks/subscribing).

### 🟡 Medium & Low — parameter renames and removals

All renamed and removed parameters are listed in the [Parameter reference](#parameter-reference-v7-v8-changes) table below.

## Before you start

* **DSN** — Contact Talview to provision DSNs for staging and production. Treat it as a secret; never commit it or expose it in source maps.
* **Workflow step identifiers** — Session type is no longer passed in code; it is dashboard-configured. Confirm your `workflow_step.identifier` UUIDs with Talview before writing code.
* **Webhook endpoint** — Provide your HTTPS endpoint URL to Talview support; they configure which event types are delivered. The endpoint must accept `POST`, respond `HTTP 200` within 10 seconds, and be publicly reachable.

## SDK migration

### Script loading

Define `window.proviewOnLoad` before the script tag. The `Proview` global is available inside the callback.

```html theme={null}
<!-- v7 -->
<script>
  window.tv = window.tv || function () { (tv.q = tv.q || []).push(arguments); };
</script>
<script async src="https://cdn.proview.io/client/init.js"></script>

<!-- v8 -->
<script>
  window.proviewOnLoad = async function () {
    // Proview global is ready here
  };
</script>
<script async src="https://sdk.tlv.cx/session/init.js" crossorigin="anonymous"></script>
```

### Initialization

```js theme={null}
// v7
tv('init', 'xxxxxxxx-proctor-token-xxxx', {
  profileId: 'candidate-user-id',
  session: 'session-uuid',
  session_type: 'record_and_review',
  sessionTitle: 'Technical Interview',
  firstName: 'Jane',
  lastName: 'Doe',
  email: 'jane@example.com',
  initCallback: function (err, uuid) {
    if (err) return;
    ProctorClient3.start();
  },
  errorCallback: function (err) { console.error(err); },
  networkDisconnectionCallback: function () { showOfflineBanner(); },
});
```

```js theme={null}
// v8
window.proviewOnLoad = async function () {
  // 1. Register the global error handler before init()
  Proview.onError(function (err) {
    // err.code, err.message, err.type: 'warning' | 'critical'
    console.error('[Proview]', err.code, err.message);
  });

  // 2. Register session hooks before init()
  Proview.session.on('NetworkStatusChanged', function ({ status }) {
    if (status === 'offline') showOfflineBanner();
    if (status === 'online') hideOfflineBanner();
  });

  Proview.session.on('Suspend', function ({ state, reason }) {
    console.log('Session suspended:', reason);
  });

  Proview.session.on('StateChange', function ({ state, reason }) {
    console.log('State →', state, reason);
  });

  // 3. Initialize — returns Promise<boolean>
  const success = await Proview.session.init({
    dsn: 'YOUR_DSN_HERE',
    identifier: 'session-uuid-from-your-backend',
    attendee: {
      identifier: 'candidate-user-id',
      first_name: 'Jane',
      last_name: 'Doe',
      email: 'jane@example.com',
    },
    workflow_step: {
      identifier: 'workflow-step-uuid-from-your-backend',
      name: 'Technical Interview',
      duration: 60,
    },
  });

  if (!success) {
    console.error('Proview failed to initialize');
    return;
  }
};
```

Start the session on a user action (for example, an "Start Exam" button click):

```js theme={null}
// v8 — start on user action
document.getElementById('start-exam').addEventListener('click', async function () {
  try {
    const output = await Proview.session.start();
    // output.uuid, output.state, output.attendee, output.workflow_step
    console.log('Session started:', output.uuid);
  } catch (err) {
    console.error('Unable to start proctoring', err);
  }
});
```

### Stop and complete

```js theme={null}
// Normal completion — candidate reached the end of the assessment
await Proview.session.complete();

// Abnormal stop — timed out, navigated away, or terminated early
await Proview.session.stop();
```

### Pause and resume

<Warning>
  **`reason` is required** for both `pause()` and `resume()`. The SDK throws if the string is empty.
</Warning>

```js theme={null}
// v7
ProctorClient3.pause();
ProctorClient3.resume();

// v8
await Proview.session.pause('Scheduled break');
await Proview.session.resume('Break over');
```

## Session hooks

`Proview.session.on(eventName, callback)` replaces v7's numeric alert IDs. `session.on()` returns an unsubscribe function, or use `session.off(eventName, namedCallback)` to remove a specific listener.

| Event                    | Payload shape                                                                         | When fired                                      |
| ------------------------ | ------------------------------------------------------------------------------------- | ----------------------------------------------- |
| `Suspend`                | `{ state, reason }`                                                                   | Session auto-suspended by the monitoring system |
| `Terminate`              | `{ state, reason }`                                                                   | Session ended by the system due to violations   |
| `Pause`                  | `{ state, reason }`                                                                   | Session paused (mirrors `session.pause()`)      |
| `Resume`                 | `{ state, reason }`                                                                   | Session resumed (mirrors `session.resume()`)    |
| `StateChange`            | `{ state, reason }`                                                                   | Any session state transition                    |
| `NetworkStatusChanged`   | `{ status: 'online' \| 'offline' }`                                                   | Network connectivity changes                    |
| `StreamingStatusChanged` | `{ status: 'connected' \| 'disconnected' \| 'reconnecting' \| 'reconnected', data? }` | Media stream quality changes                    |

<Tip>
  **No client-side alert events in v8.** The v7 numeric alert IDs (`ProctorClient3.on('log:event:type:N', cb)`) do not exist in v8. All monitoring happens server-side and is delivered as structured incidents to your webhook endpoint.
</Tip>

## Session states

`SessionOutput.state` (and the `state` field in hook payloads) uses the SDK `SessionState` enum. These are the same eight uppercase values documented in [Configuration](/sdk/proctoring/configuration).

| State                    | Meaning                                        | How reached                         |
| ------------------------ | ---------------------------------------------- | ----------------------------------- |
| `INITIALISED`            | SDK loaded, before `session.init()` completes  | SDK ready                           |
| `ONBOARDING_IN_PROGRESS` | Candidate is in the precheck / onboarding step | After `session.start()` resolves    |
| `MONITORING_IN_PROGRESS` | Active — candidate is being monitored          | After onboarding completes          |
| `PAUSED`                 | Temporarily halted by your code                | `session.pause(reason)`             |
| `SUSPENDED`              | Auto-paused by monitoring due to a violation   | System — fires the `Suspend` hook   |
| `STOPPED`                | Interrupted before completion                  | `session.stop()`                    |
| `COMPLETED`              | Candidate finished legitimately                | `session.complete()`                |
| `TERMINATED`             | Ended by the system due to violations          | System — fires the `Terminate` hook |

<Note>
  **Webhook `payload.status` is a separate, server-side vocabulary** — `CREATED`, `IN_PROGRESS`, `PAUSED`, `SUSPENDED`, `STOPPED`, `COMPLETED`, `TERMINATED`. It is delivered in webhook events and is **not** the same set as the SDK `state` above (for example, server-side `IN_PROGRESS` corresponds to the SDK's `MONITORING_IN_PROGRESS`). Don't map the two one-to-one. See [Webhooks overview](/graph-api-reference/webhooks/overview).
</Note>

## Parameter reference: v7 → v8 changes

| v7                             | v8                                                | Change                                                                                            |
| ------------------------------ | ------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `proctor_token`                | `dsn`                                             | Renamed + format changed — DSN is project-level, not per-session                                  |
| `session`                      | `identifier`                                      | Renamed only                                                                                      |
| `profileId`                    | `attendee.identifier`                             | Moved into the nested `attendee` object                                                           |
| `firstName` / `lastName`       | `attendee.first_name` / `attendee.last_name`      | Snake\_case + nested in `attendee`                                                                |
| `email`                        | `attendee.email`                                  | Nested in `attendee`                                                                              |
| `session_type`                 | —                                                 | Removed — configure per workflow in the Proview dashboard                                         |
| `sessionTitle`                 | `workflow_step.name`                              | Moved into the `workflow_step` object                                                             |
| `initCallback(err, uuid)`      | `await Proview.session.start()` → `SessionOutput` | Replaced — start is now a separate Promise-based call, not a callback passed to init              |
| `errorCallback(err)`           | `Proview.onError(handler)`                        | Replaced — errors handled via a global `Proview.onError()` call made once before `session.init()` |
| `networkDisconnectionCallback` | `session.on('NetworkStatusChanged', cb)`          | Replaced — network events are a session hook; payload is `{ status }` (object, not string)        |

<Note>
  For the full `session.init()` options and the `attendee`, `workflow_step`, and `SessionOutput` object shapes, see [Configuration](/sdk/proctoring/configuration) and [Types](/sdk/proctoring/types).
</Note>

## Rollout checklist

**Code changes**

* [ ] Script URL updated to `https://sdk.tlv.cx/session/init.js`
* [ ] `window.proviewOnLoad = async function () { ... }` defined before the script tag
* [ ] All `ProctorClient3.*` calls replaced with `Proview.session.*`
* [ ] `Proview.onError(handler)` registered before `session.init()`
* [ ] `session.init()` return value checked: `const success = await Proview.session.init(...); if (!success) return;`
* [ ] `session.on()` listeners use the event names from the [Session hooks](#session-hooks) table
* [ ] `NetworkStatusChanged` handler reads `{ status }` (object, not a string)
* [ ] `pause()` and `resume()` calls pass a non-empty reason string
* [ ] `attendee.first_name` / `attendee.last_name` used (not `name`)
* [ ] Webhook handler updated for the v8 envelope format
* [ ] Session / incident storage updated for v8 fields (`uuid`, `integrity`, `score`)
* [ ] Session playback updated to `Proview.session.playback({ dsn, uuid, root })`

**Staging validation**

* [ ] Full lifecycle: `init()` → `start()` → `complete()` → webhook received
* [ ] Session and incident webhook payloads received and stored correctly
* [ ] `Suspend` hook fires and is handled
* [ ] `NetworkStatusChanged` payload handled as a `{ status }` object
* [ ] Pause / resume tested end-to-end with non-empty reason strings
* [ ] Session playback loads
* [ ] Error handler fires on an invalid DSN
* [ ] Browser console: no CSP violations, no 404s from the old domain

**Production cutover**

* [ ] DSN swapped to the production value
* [ ] CSP updated in production (including `'unsafe-inline'` directives)
* [ ] Webhook endpoint registered for production with Talview support

## Troubleshooting

<AccordionGroup>
  <Accordion title="`Proview` is undefined on page load">
    `proviewOnLoad` was not defined before the script tag, or the SDK script failed to load. Ensure `window.proviewOnLoad = async function () {...}` is in a `<script>` block immediately before the `<script async src="...">` tag. Check the network tab for a 404 or CSP block on `sdk.tlv.cx`.
  </Accordion>

  <Accordion title="CSP violation on sdk.tlv.cx">
    Add `https://sdk.tlv.cx` to `script-src` (with `'unsafe-inline'`) and to `img-src`. Add `https://*.talview.com` and `wss://*.talview.com` to `connect-src`. Keep `https://cdn.proview.io` in your v7 directives until all in-flight v7 sessions have ended, then remove it.
  </Accordion>

  <Accordion title="session.init() resolves false">
    The DSN is invalid or belongs to the wrong environment (for example, a staging DSN used in production), or a required field is missing. Check `Proview.onError()` output for the specific error code, and verify the DSN with your Talview account team.
  </Accordion>

  <Accordion title="session.pause() rejects: 'Pause reason is required'">
    The `reason` argument is empty or whitespace. Pass a non-empty string: `session.pause('Scheduled break')`.
  </Accordion>

  <Accordion title="Webhooks not arriving at my endpoint">
    Confirm the endpoint is registered with Talview support, returns `HTTP 200` within 10 seconds, and is publicly reachable over HTTPS. Webhooks may be retried, so implement idempotent upsert logic keyed on `payload.uuid` with an `updated_at` guard.
  </Accordion>
</AccordionGroup>

For general SDK troubleshooting, see [Troubleshooting](/sdk/proctoring/troubleshooting). For integration issues not covered here, contact Talview support and include the session UUID, browser console output, and network requests to `sdk.tlv.cx`.
