> For the complete documentation index, see [llms.txt](https://docs.wproofreader.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.wproofreader.com/integrations/learnosity.md).

# Learnosity

## WProofreader for Learnosity

WProofreader is a real-time spelling, grammar, and style checker for editor content in Learnosity. It is wired into Learnosity's rich-text widgets across the Questions API, Items API, and Author API with a single function call.

### Prerequisites

Before integrating, make sure you have:

* **A WProofreader service ID.** To obtain a license for the WProofreader SDK, [sign up for one of the paid plans](https://wproofreader.com/sdk#pricing) (which differ by the word package included) or [contact us](https://wproofreader.com/contact-us) for Enterprise pricing with self-hosted deployment. Service IDs are domain-locked: whitelist your production and development origins in the WebSpellChecker dashboard.
* **A Learnosity account.** You should already have a consumer key, consumer secret, and a working signed-request flow on your server.

### Installation

The plugin offers two install paths. The runtime API is identical, `LearnosityWProofreader.init({...})`, in both.

#### Via npm (Node host apps)

```bash
npm install @webspellchecker/wproofreader-learnosity
```

```js
import LearnosityWProofreader from '@webspellchecker/wproofreader-learnosity';

LearnosityWProofreader.init({
  wproofreader: { serviceId: 'YOUR_WPROOFREADER_SERVICE_ID' }
});
```

Use **Node 18 or newer** when installing via npm. If your host app uses CommonJS or no bundler at all, use the CDN script-tag path below instead.

#### Via `<script>` tag (non-Node host apps)

For host apps without a bundler (classic HTML, PHP, Python, Java, ASP.NET, Ruby), load the plugin from jsDelivr:

```html
<script src="https://cdn.jsdelivr.net/npm/@webspellchecker/wproofreader-learnosity@latest/dist/wproofreader-learnosity.min.js"></script>
<script>
  LearnosityWProofreader.init({
    wproofreader: { serviceId: 'YOUR_WPROOFREADER_SERVICE_ID' }
  });
</script>
```

The bundle exposes a single global, `window.LearnosityWProofreader`, with the same `init` method. The WProofreader SDK is bundled in, so there is nothing else to load.

### Quick start

Initialize the plugin before Learnosity's player renders, then initialize Learnosity as normal:

```js
import LearnosityWProofreader from '@webspellchecker/wproofreader-learnosity';

// 1. Wire up the plugin once, before Learnosity widgets render.
LearnosityWProofreader.init({
  wproofreader: { serviceId: 'YOUR_WPROOFREADER_SERVICE_ID' }
});

// 2. Initialize Learnosity Questions API with the signed request from your server.
LearnosityApp.init(signedRequest, {
  readyListener() { console.log('Learnosity ready'); },
  errorListener(err) { console.error(err); }
});
```

`init()` is idempotent: calling it again updates the live configuration without reloading the WProofreader bundle.

### Configuration

`init()` takes a single options object with two groups: a nested `wproofreader` sub-object (forwarded to WProofreader unchanged) and plugin-only fields at the top level.

| Option            | Default      | Notes                                                                                                                                                                                                                                                                                                                                                   |
| ----------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `surfaces`        | `['author']` | Subset of `['questions','items','author']`. Per-editor filter applied during the DOM ancestry walk. Default is Author only, for assessment integrity.                                                                                                                                                                                                   |
| `enableShorttext` | `false`      | Also attach to `shorttext` inputs (`<input type="text">`) inside Learnosity scope. Off by default because plain text inputs are usually short and proofreading them is noisy.                                                                                                                                                                           |
| `customSelectors` | `[]`         | Extra ancestor CSS selectors that count as "inside Learnosity scope" for unusual host apps. Each entry is matched via `element.matches`.                                                                                                                                                                                                                |
| `wproofreader`    | –            | WProofreader runtime options, forwarded to the SDK unchanged. At least one of `wproofreader.serviceId` or `wproofreader.serviceHost` must be set, otherwise `init()` no-ops with a console warning. Common keys are listed below; the full set is in the [WProofreader options reference](https://webspellchecker.com/docs/api/wscbundle/Options.html). |

Frequently-used keys under `wproofreader`:

| Key                                                               | Default                               | Notes                                                                                        |
| ----------------------------------------------------------------- | ------------------------------------- | -------------------------------------------------------------------------------------------- |
| `serviceId`                                                       | *none*                                | WProofreader Cloud service ID. Domain-locked server-side. Required for the Cloud path.       |
| `serviceProtocol` / `serviceHost` / `servicePort` / `servicePath` | *none*                                | Self-hosted connection details (see Self-hosted WProofreader).                               |
| `srcUrl`                                                          | *SDK default (cloud CDN)*             | Where to load `wscbundle.js` from. Override for a self-hosted deployment or non-default CDN. |
| `enableGrammar`                                                   | `true`                                | Grammar checking on top of spell checking.                                                   |
| `autocorrect`                                                     | `true`                                | Suggested replacement on typo accept.                                                        |
| `lang`                                                            | host page's `<html lang>`, or `en_US` | See Locale-aware default language.                                                           |

### Supported surfaces

| Learnosity API | Surface                        |
| -------------- | ------------------------------ |
| Questions API  | `longtextV2` (rich-text essay) |
| Author API     | All rich-text fields           |
| Items API      | `assess` rendering type        |

By default, only Author API surfaces are proofread. This is a safety default for assessment integrity: students taking an assessment via the Questions or Items API should not get spelling help unless the host app explicitly opts in based on server-side activity metadata.

On pages that host widgets from more than one Learnosity API (for example, an Author UI rendered alongside a Questions essay), the plugin classifies each editor individually, so a single `init()` call proofreads only the editors whose surface is in the allowed list.

To enable proofreading across all three surfaces:

```js
LearnosityWProofreader.init({
  wproofreader: { serviceId: '...' },
  surfaces: ['questions', 'items', 'author']
});
```

### Self-hosted WProofreader

For customers running the [WProofreader Server](https://hub.docker.com/r/webspellchecker/wproofreader) on their own infrastructure (Docker, Helm, on-prem), pass the service connection options under `wproofreader` instead of a `serviceId`, along with `srcUrl` for the self-hosted bundle:

```js
LearnosityWProofreader.init({
  wproofreader: {
    serviceProtocol: 'https',
    serviceHost: 'your-wproofreader-host.example.com',
    servicePort: 443,
    servicePath: '/wscservice/api',
    srcUrl: 'https://your-wproofreader-host.example.com/wscservice/wscbundle/wscbundle.js'
  }
});
```

Either `wproofreader.serviceId` or `wproofreader.serviceHost` must be set; otherwise `init()` no-ops with a console warning.

### Advanced

#### customSelectors

If your host app wraps Learnosity inside a container with class names that don't start with `lrn`, use the `customSelectors` option, which extends the "inside Learnosity" check with extra CSS selectors:

```js
LearnosityWProofreader.init({
  wproofreader: { serviceId: '...' },
  customSelectors: ['.my-host-app-learnosity-region']
});
```

#### enableShorttext

By default, the plugin attaches only to rich-text editors (`contenteditable`) and iframes (CKEditor classic). Opt in to plain text inputs with:

```js
LearnosityWProofreader.init({
  wproofreader: { serviceId: '...' },
  enableShorttext: true
});
```

#### Locale-aware default language

The plugin reads `<html lang>` from the host page and forwards it to WProofreader as the `lang` option, normalizing `-` to `_` (e.g. `en-US` becomes `en_US`). This means a French-language page proofreads in French without extra configuration.

WProofreader requires region-qualified language codes. If `<html lang>` is missing or set to a bare un-regioned code like `en` or `fr`, the plugin falls back to `en_US`. Override explicitly with `wproofreader.lang` if needed.

### Examples

```js
// Authoring-only (the default). No-ops on assessment pages.
LearnosityWProofreader.init({
  wproofreader: { serviceId: '...' }
});

// All three surfaces, including assessment. Derive this from server-side
// activity metadata so it cannot be flipped from the browser console.
LearnosityWProofreader.init({
  wproofreader: { serviceId: '...' },
  surfaces: ['questions', 'items', 'author']
});

// Unusual host app that wraps Learnosity inside its own container class.
LearnosityWProofreader.init({
  wproofreader: { serviceId: '...' },
  customSelectors: ['.my-host-app-learnosity-region']
});

// Self-hosted WProofreader, no service ID, all surfaces.
LearnosityWProofreader.init({
  wproofreader: {
    serviceProtocol: 'https',
    serviceHost: 'wproofreader.internal.example.com',
    servicePort: 443,
    servicePath: '/wscservice/api',
    srcUrl: 'https://wproofreader.internal.example.com/wscservice/wscbundle/wscbundle.js'
  },
  surfaces: ['questions', 'items', 'author']
});
```

### FAQ and troubleshooting

#### WProofreader doesn't appear in my editors

Walk through these in order:

1. **Check the console.** A missing `serviceId` or `serviceHost` logs a warning and the plugin no-ops by design.
2. **Check the Network tab in DevTools.** Spell-check requests to `svc.webspellchecker.net` returning 403 mean your service ID is domain-locked and the current origin is not whitelisted. Add it in the WebSpellChecker dashboard.
3. **Check `surfaces`.** The default is Author only. On a Questions API or Items API page, explicitly opt in with `surfaces: ['questions', 'items', 'author']`.
4. **Check the call order.** `LearnosityWProofreader.init({...})` must be called before `LearnosityApp.init(...)` / `LearnosityItems.init(...)` / `LearnosityAuthor.init(...)`.

#### WProofreader proofreads things outside Learnosity

The plugin scopes attachment via an ancestry walk for any class starting with `lrn`, plus your `customSelectors`. If your host app uses class names that happen to start with `lrn` outside Learnosity contexts, the plugin might match them. Either rename the classes or open an issue with a reproduction case.

#### I'm using a single-page app that rebuilds Learnosity widgets

The plugin observes `document.body` for `childList` and `attributes` mutations, and destroys WProofreader instances when their host editors leave the DOM. No leak should occur across navigations. If you see one, please open an issue.

### License and trademark

The plugin is licensed under Apache-2.0. Learnosity is a trademark of Learnosity Ltd; this plugin is an independent third-party integration and is not affiliated with or endorsed by Learnosity Ltd.
