---
title: "1.25 release notes"
canonical_url: "https://www.nutrient.io/guides/web/release-notes/1-25/"
md_url: "https://www.nutrient.io/guides/web/release-notes/1-25.md"
last_updated: "2026-11-02T00:00:00.000Z"
description: "Nutrient Web SDK 1.25 fixes security issues, removes most deprecated collection methods, makes models stricter, and supports PDF layers with Document Engine."
---

Nutrient Web SDK 1.25 fixes three security vulnerabilities and a redaction leak, and it can break code that uses the SDK’s collections and models. The SDK no longer includes Immutable.js. `List`, `Map`, `Set`, `OrderedMap`, and `OrderedSet` are now the SDK’s own classes, and most of the collection methods deprecated in 1.22 and 1.23 are gone. Assigning a field of a model, such as an annotation, now throws a `TypeError`. On models, `equals()` is deprecated in favor of the new `isEqual()` method. With Document Engine 1.20.0 or later, you can view and toggle PDF layers in server-backed mode. Links added in the comment link dialog without a protocol now get an `https://` prefix. Overlapping form field changes in standalone mode are fast again and now settle together. The WebAssembly PDF engine is about 10 percent smaller. See the [changelog](https://www.nutrient.io/guides/web/changelog.md#1.25.0) for full details.

### Security fixes

The fixes themselves don’t need code changes, but 1.25 also has breaking changes, so read the sections below before you upgrade.

- **CVE-2026-111497:** A specially crafted PDF that uses Brotli compression could trigger an out-of-bounds write in the bundled Brotli decoder. Such a PDF could also make PDF processing hang. The decoder is now version 1.1.1 instead of 1.1.0. In server-backed mode, Document Engine also decodes PDFs, so update Document Engine to 1.19.1 or later as well.

- **CVE-2026-111768:** A single oversized AI Assistant tool request could use up the browser tab’s memory. Web SDK’s AI Assistant integration now uses `@modelcontextprotocol/sdk` 1.32.1 instead of 1.27.1 and rejects oversized tool requests. This release doesn’t change the AI Assistant server, which has its own releases. If you don’t use AI Assistant, you aren’t affected.

- **CVE-2026-111758:** Crafted Markdown in an AI Assistant chat message could take a very long time to render. The bundled `markdown-it` is now version 14.3.3 instead of 14.2.0. If you don’t use AI Assistant, you aren’t affected.

- **Redacted form field values:** Redacting a form field nested under another field could leave its value in the PDF’s form data. Tools that read form fields could recover it. Redaction now removes the value, its default, and its appearance. Documents redacted with earlier versions can still contain these values.

If you load Web SDK from Document Engine with `<script src="https://<document_engine_url>/nutrient-viewer.js">`, you get the Web SDK version that shipped with that Document Engine. That version doesn’t have these fixes. Document Engine 1.20.0, for example, serves Web SDK 1.24. Load Web SDK 1.25 from the CDN or npm instead. Set `serverUrl` in `NutrientViewer.load()`, because the SDK can no longer infer the Document Engine URL from the script’s source.

### Before you upgrade

Check your code for the following. Each item is explained in its own section below:

- Calls to removed collection and model methods, such as `keySeq()` or `toSeq()`. Plain JavaScript gets no warning before they throw.

- Assignments to model fields, such as `annotation.opacity = 0.5`, which now throw.

- SDK collections and models passed to your own copy of Immutable.js.

- Models compared with helpers that compare objects key by key, such as React Redux’s `shallowEqual`. These fail silently.

- TypeScript code that reads form field or annotation properties without narrowing the type first.

- Error handling around overlapping `instance.create()`, `instance.update()`, or `instance.delete()` calls in standalone mode.

- In server-backed mode, your Document Engine version: 1.19.1 or later for the Brotli fix, and 1.20.0 or later for layers.

### Removed collection methods

Most of the collection methods deprecated in 1.22 and 1.23 are gone, along with four methods on models. The SDK’s collections are now its own classes instead of Immutable.js collections. `NutrientViewer.Immutable.List`, `Map`, and `Set` still exist, so code that creates collections with them keeps working. Calling a removed method throws a `TypeError`, such as `TypeError: list.keySeq is not a function`, and TypeScript flags the call as an error. Before this release, the deprecations appeared only in the type declarations, the API reference, and the 1.22 and 1.23 release notes. Plain JavaScript code got no warning at runtime.

| Removed from        | Methods                                                                                                                                                                                                                                                     |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `List`              | `keySeq()`, `valueSeq()`, `entrySeq()`, `toSeq()`, `toKeyedSeq()`, `toIndexedSeq()`, `toSetSeq()`, `toStack()`, `findKey()`, `findEntry()`, `fromEntrySeq()`, `asMutable()`, `asImmutable()`, `wasAltered()`, `setSize()`, `zip()`, `zipAll()`, `zipWith()` |
| `Map`, `OrderedMap` | `keySeq()`, `valueSeq()`, `entrySeq()`, `toSeq()`, `toKeyedSeq()`, `toIndexedSeq()`, `toSetSeq()`, `toStack()`, `findKey()`, `findEntry()`, `asMutable()`, `asImmutable()`, `wasAltered()`                                                                  |
| `Set`, `OrderedSet` | `keySeq()`, `valueSeq()`, `entrySeq()`, `toSeq()`, `toKeyedSeq()`, `toIndexedSeq()`, `toSetSeq()`, `toStack()`, `findKey()`, `findEntry()`, `asMutable()`, `asImmutable()`, `wasAltered()`                                                                  |
| `OrderedSet` only   | `zip()`, `zipAll()`, `zipWith()`                                                                                                                                                                                                                            |
| Models              | `toSeq()`, `asMutable()`, `asImmutable()`, `wasAltered()`                                                                                                                                                                                                   |

A few Immutable.js methods that were never part of the SDK’s types are gone too: `chain()`, `inspect()`, and `toSource()` from all five collections, and `fromEntrySeq()` from `Map`, `OrderedMap`, `Set`, and `OrderedSet`.

The [1.22](https://www.nutrient.io/guides/web/release-notes/1-22.md) and [1.23](https://www.nutrient.io/guides/web/release-notes/1-23.md) release notes list a replacement for each deprecated method. These are the most common:

```js

const map = NutrientViewer.Immutable.Map({ a: 1, b: 2 });

// `keySeq()`, `valueSeq()`, and `entrySeq()` → `keys()`, `values()`, and `entries()`.
// The new methods return iterators. To get a `List`, wrap the iterator in `NutrientViewer.Immutable.List()`.
const keys = NutrientViewer.Immutable.List(map.keys());

// `toStack()` → `toList()`.
const list = map.toList();

// `asMutable()` and `asImmutable()` → `withMutations()`.
const updated = map.withMutations((m) => {
  m.set("a", 2).set("b", 3);
});

// `wasAltered()` → compare the result with the original, using `!==` or `equals()`.
// `withMutations()` returns the original if the callback changed nothing.
const changed = updated!== map;

```

If you replace `toStack()` with `toList()`, also replace the stack methods. A stack adds and removes values at the front, so use `unshift()` instead of `push()`, `shift()` instead of `pop()`, and `first()` instead of `peek()`.

These methods are no longer deprecated: `hashCode()` on collections and models, `union()` and `subtract()` on `Set` and `OrderedSet`, and `Map.of()`. On annotations, geometry, and actions, `hashCode()` is now in the type declarations too. If you replaced `hashCode()` or `wasAltered()` with `equals()`, as the 1.22 and 1.23 release notes advised, that still works on collections. On models, use `isEqual()` instead. For the methods each collection supports, refer to the [`NutrientViewer.Immutable.List`](https://www.nutrient.io/api/web/NutrientViewer.Immutable.List.html) API reference.

### Using SDK values with your own Immutable.js

If your app has its own copy of Immutable.js, check where SDK collections and models reach it. Before 1.25, they were Immutable.js objects and worked everywhere. Now your copy only accepts them where it expects the same kind of collection. The details below are for Immutable.js 4 and 5, and version 3 throws in fewer of these cases:

- Given an SDK collection of exactly their own type, `List()`, `Map()`, `Set()`, `OrderedMap()`, and `OrderedSet()` return it unchanged instead of copying it. So do `concat()`, `union()`, `merge()`, and `mergeDeep()` on an empty collection, and `fromJS()` with any SDK value. The result is still the SDK object, so a later call to a removed method, such as `toSeq()`, throws.

- `Map()` and `Set()` copy an ordered SDK collection, such as the result of `sort()`, and `OrderedMap()` and `OrderedSet()` copy an unordered one. `concat()`, `union()`, and `merge()` on a non-empty collection copy an SDK collection of the same kind. The copy is shallow, so models inside it are still SDK objects.

In most other places, your copy can throw a `TypeError` saying that a method such as `toSeq` isn’t a function. TypeScript doesn’t catch most of these calls. Storing SDK values in your collections and reading them back still works, and so do `Immutable.is()`, `equals()`, and checks such as `Immutable.isList()`.

In the examples below, `Immutable` is your copy of Immutable.js, and names that start with `my` are your own collections. `annotation` is an annotation, `annotations` is the `List` that `instance.getAnnotations()` returns, and names that start with `sdk` are other SDK collections. These calls throw:

```js

// `toJS()` on your collection while it holds a model, such as an annotation or a `Rect`, at any depth.
Immutable.List([annotation]).toJS();

// `Map()` or `merge()` with a model.
Immutable.Map(annotation);
myImmutableMap.merge(annotation);

// `Map()` or `OrderedMap()` with an SDK `List` of [key, value] entries.
Immutable.Map(sdkEntries);

// `mergeDeep()` when both sides hold a collection, object, or model under the same key
// and one of them is an SDK value, including an SDK collection your map already holds.
myImmutableMap.mergeDeep(sdkMap);

// `Seq()` with an SDK collection.
Immutable.Seq(sdkMap);

// `concat()` on a list with an SDK set or map.
myImmutableList.concat(sdkSet);

// `Set.fromKeys()` with an SDK collection.
Immutable.Set.fromKeys(sdkMap);

// `List()`, `Set()`, or `OrderedSet()` with another kind of SDK collection.
Immutable.Set(sdkList);

```

Convert SDK values to plain values first. `toArray()` and `toObject()` only convert one level, so use `toJS()` for models and for collections that contain them. Like `toObject()`, `toJS()` turns number keys into strings:

```js

Immutable.fromJS(annotation.toJS());
Immutable.List(annotations.toJS());
Immutable.Map(annotations.map((a) => [a.id, a.toJS()]).toArray());
Immutable.Map(sdkMap.toArray()); // Unlike `toObject()`, this keeps number keys.
myImmutableList.concat(sdkSet.toArray());
myImmutableMap.mergeDeep(Immutable.fromJS(sdkMap.toJS()));

```

In the other direction, build the collections you pass to models with `NutrientViewer.Immutable.List`, not with your own copy. For example, if you build an ink annotation’s `lines` with your own `List`, that list holds SDK `DrawingPoint` models. The annotation’s `toJS()` then throws a `TypeError`.

### Models are stricter

The changes below apply to annotations, geometry, actions, form fields, and other models, such as `Color`, `Comment`, and `ViewState`.

**Assigning a field throws.** In 1.24, assigning a field of an annotation, action, form field, `FormFieldValue`, `Point`, or `Rect` did nothing. On `Size`, `Color`, `Comment`, `ViewState`, and most other models, the same assignment threw a plain `Error`. Every model now throws a `TypeError` that names the field. Because many of these assignments had no effect in 1.24, check what the code was meant to do before you replace it. If the app works as it is, delete the assignment. If the change should happen, use `set()`, which returns an updated copy:

```js

// 1.24: ignored. 1.25: `TypeError`: Cannot set opacity on an immutable record.
// annotation.opacity = 0.5;

// If the change should happen, create an updated copy and apply it.
const updated = annotation.set("opacity", 0.5);
await instance.update(updated);

```

**A constructor always returns a new instance of its own class.** In 1.24, a constructor that received another model could return it unchanged. For example, `new Rect(point)` returned the `Point`, and `new Rect(rect)` returned the same `rect`. Now `new Rect(point)` returns a new `Rect` with default values, because a `Rect` and a `Point` have no fields in common. This doesn’t throw, so search for code that passes one model to another model’s constructor rather than waiting for an error. To place a `Rect` at a point, pass the coordinates:

```js

const point = new NutrientViewer.Geometry.Point({ x: 5, y: 7 });
const rect = new NutrientViewer.Geometry.Rect({ left: point.x, top: point.y });

```

**`equals()` is deprecated on models in favor of `isEqual()`.** `equals()` only compares field names and values, so two models of different classes with the same fields and values are equal. `isEqual()` also checks that both have the same class. `equals()` still works, and as with the collection methods, only the type declarations and the API reference mark it as deprecated:

```js

const { UnderlineAnnotation, SquiggleAnnotation } = NutrientViewer.Annotations;
const props = { pageIndex: 0, color: NutrientViewer.Color.BLACK };

new UnderlineAnnotation(props).equals(new SquiggleAnnotation(props)); // true
new UnderlineAnnotation(props).isEqual(new SquiggleAnnotation(props)); // false

```

Lookups in SDK collections, such as `has()` on a `Set`, still compare by value and ignore the class. `Immutable.is()` in your own copy of Immutable.js does the same. If you keep different annotation types in one `Set` or as `Map` keys, key them by `id` instead. `equals()` on `Color` isn’t deprecated, and unlike `isEqual()`, it still accepts a plain `{ r, g, b, transparent }` object.

**`Object.keys()` returns an empty array for a model.** Helpers that compare objects key by key, such as React Redux’s `shallowEqual`, now treat any two models as equal. A `useSelector()` call that returns an annotation and passes `shallowEqual` no longer rerenders the component when the annotation changes. Compare models by reference or with `isEqual()` instead.

**The TypeScript declarations are stricter.** Code that compiled against 1.24 can fail against 1.25:

- Fields of annotations, actions, form fields, and other models are read-only, like geometry fields since 1.20.

- `get()`, `set()`, `update()`, `merge()`, and similar methods only accept the keys a model defines, and annotation constructors reject unknown properties.

- On an `AnnotationsUnion`, such as the annotations that `instance.getAnnotations()` returns, these methods only accept fields that every annotation type has. To read or change another field, such as `strokeColor`, narrow the type first — for example, with `annotation instanceof NutrientViewer.Annotations.InkAnnotation`.

- TypeScript no longer lets you read properties that `FormField` doesn’t declare, such as `value` or `options`. To read them from a field that `instance.getFormFields()` returns, narrow the type first — for example, with `field instanceof NutrientViewer.FormFields.ChoiceFormField` — before reading `options`.

- `FormField` is now abstract in the types too. Constructing it always threw at runtime, so create a concrete type, such as `NutrientViewer.FormFields.TextFormField`.

One related fix: `FormFieldValue` no longer loses `optionIndexes` when you call `set()`, `merge()`, or another method that returns a changed copy, and `set("optionIndexes", …)` now works. `has()`, `toObject()`, `toJS()`, `equals()`, and `hashCode()` now include `optionIndexes` too. For more information, refer to the [geometry primitives](https://www.nutrient.io/guides/web/annotations/geometry.md) and [view state](https://www.nutrient.io/guides/web/customizing-the-interface/viewstate.md) guides.

### Comment links and pasted mentions

Links entered without a protocol in the comment editor’s link dialog, such as `www.example.com`, now get an `https://` prefix when saved. Links typed directly into a comment already did. In the comment text that `instance.getComments()` returns, you’ll see `href="https://www.example.com"` instead of `href="www.example.com"`. Relative links that start with `/` or `.`, and links with another protocol, such as `mailto:`, are saved as entered. Comments saved before 1.25 keep their stored links, which still work. If your code parses or compares stored comment HTML, expect the prefix on new links.

When a user pastes text that contains a mention, such as one copied from another comment, the SDK now checks the mention against your mentionable users. You set these with the `mentionableUsers` configuration option or `instance.setMentionableUsers()`. If the mentioned user is on that list, the mention shows their display name. If not, it becomes plain `@Name` text, and the comment’s `getMentionedUserIds()` doesn’t include that user. For more information, refer to the [comments](https://www.nutrient.io/guides/web/annotations/comments-and-replies/comments.md) guide.

### Overlapping form field changes share one batch

Since 1.18, changing many form fields at once with separate `instance.create()`, `instance.update()`, or `instance.delete()` calls was slow in standalone mode. Calls that overlap now share one batch, which is applied once, so each call resolves only after every call in the batch has finished. If applying the batch fails, every call in it rejects with that error, including calls whose own changes worked.

### PDF layers in server-backed mode

With Document Engine 1.20.0 or later, the layers sidebar, `getLayersVisibilityState()`, and `setLayersVisibilityState()` now work in server-backed mode. PDF layers are also called optional content groups (OCGs). In 1.24, the layers button was hidden in this mode. Both methods rejected with an error such as “`instance.getLayersVisibilityState()` is only available in Standalone mode.” The layers button (`sidebar-layers`, part of the default toolbar) now appears for documents that have layers, without any configuration. To keep it hidden, remove it from the toolbar:

```js

instance.setToolbarItems((items) => items.filter((item) => item.type!== "sidebar-layers"));

```

A document opens with the layer visibility saved in the PDF. When a user shows or hides a layer, Document Engine renders the pages again. In both modes, pages and thumbnails now keep their content while a layer change renders, instead of going blank. Some PDFs, such as some CAD drawings, also have layers that aren’t in the document’s layer list. The sidebar doesn’t show these, and they keep the visibility the PDF defines. A user’s choice only affects their own viewer; it isn’t saved to the document or shared with other users. It resets to the PDF’s defaults when the document reloads, including after redaction, signing, saving in the Content Editor, or applying document operations.

For example, this code hides every layer and then shows the original ones again:

```js

// Remember which layers are visible when the document opens.
const initialState = await instance.getLayersVisibilityState();
console.log(initialState.visibleLayerIds); // The IDs of the visible layers, in no guaranteed order.

// Hide every layer in the document’s layer list.
await instance.setLayersVisibilityState({ visibleLayerIds: [] });

// Show the original layers again.
await instance.setLayersVisibilityState(initialState);

```

In server-backed mode, a few things work differently from standalone mode:

- `setLayersVisibilityState()` rejects layer IDs that aren’t in the document’s layer list. Layer IDs can change when Document Engine replaces the document, so read them again instead of reusing stored IDs.

- Printing, exporting, and downloading use the layer visibility saved in the PDF, not the user’s choice.

- Text in a hidden layer can still be selected.

- You can only create layers with `createLayer()` in standalone mode.

This feature needs Web SDK 1.25 and Document Engine 1.20.0 or later. With an older Document Engine, the layers button stays hidden. A layers sidebar opened through `ViewState` keeps showing a loading indicator. Both methods reject with “OCG layers require Document Engine version 1.20.0 or later.” If you load Web SDK from Document Engine, switch to the CDN or npm, as described in the [security fixes](#security-fixes) section. When it loads a document, the viewer also sends `GET` requests to the document’s `ocg-layers` and `ocg-layers-state` endpoints. These use the same `/i/d/` path as the viewer’s other requests for that document. If a proxy in front of Document Engine only allows specific paths, allow these two as well. If they’re blocked, the document still opens, but the layers button stays hidden and the browser console shows an error. For more information, refer to the [layer visibility](https://www.nutrient.io/guides/web/layers/visibility.md) and [layers sidebar](https://www.nutrient.io/guides/web/user-interface/sidebar/layers.md) guides.

Document Engine 1.5.6 or later can run this release. In server-backed mode, using `SearchType.WORD_BASED`, removing password protection during PDF export, and removing annotation notes after an XFDF roundtrip require Document Engine 1.16.0 or later. Document-defined annotation tab order, `Annotation.createdBy`, `overprintPreview`, and `blackRendering` require Document Engine 1.18.0 or later. In server-backed mode, viewing and toggling PDF layers requires Document Engine 1.20.0 or later. Compound measurements are standalone mode only and are ignored by Document Engine. See the [Web SDK and Document Engine compatibility requirements](https://www.nutrient.io/guides/document-engine/viewer/client-integration/web.md#version-compatibility).

For a complete list of changes, bug fixes, and improvements, refer to the [changelog](https://www.nutrient.io/guides/web/changelog.md#1.25.0). For previous release notes, refer to the [Web SDK 1.24 release notes](https://www.nutrient.io/guides/web/release-notes/1-24.md).
---

## Related pages

- [1 0](/guides/web/release-notes/1-0.md)
- [1 1](/guides/web/release-notes/1-1.md)
- [1 10](/guides/web/release-notes/1-10.md)
- [1 11](/guides/web/release-notes/1-11.md)
- [1 12](/guides/web/release-notes/1-12.md)
- [1 13 1](/guides/web/release-notes/1-13-1.md)
- [1 13](/guides/web/release-notes/1-13.md)
- [1 14](/guides/web/release-notes/1-14.md)
- [1 15](/guides/web/release-notes/1-15.md)
- [1 16](/guides/web/release-notes/1-16.md)
- [1 17](/guides/web/release-notes/1-17.md)
- [1 18](/guides/web/release-notes/1-18.md)
- [1 19](/guides/web/release-notes/1-19.md)
- [1 2](/guides/web/release-notes/1-2.md)
- [1 20](/guides/web/release-notes/1-20.md)
- [1 21](/guides/web/release-notes/1-21.md)
- [1 22](/guides/web/release-notes/1-22.md)
- [1 23](/guides/web/release-notes/1-23.md)
- [1 24](/guides/web/release-notes/1-24.md)
- [1 3](/guides/web/release-notes/1-3.md)
- [1 4](/guides/web/release-notes/1-4.md)
- [1 5](/guides/web/release-notes/1-5.md)
- [1 6](/guides/web/release-notes/1-6.md)
- [1 7](/guides/web/release-notes/1-7.md)
- [1 8](/guides/web/release-notes/1-8.md)
- [1 9](/guides/web/release-notes/1-9.md)
- [2017 3](/guides/web/release-notes/2017-3.md)
- [2017 6](/guides/web/release-notes/2017-6.md)
- [Update your PSPDFKit for Web to version 2017.7](/guides/web/release-notes/2017-7.md)
- [Upgrade annotations in PSPDFKit Web 2017.8](/guides/web/release-notes/2017-8.md)
- [Explore new features in PSPDFKit for Web 2017.9](/guides/web/release-notes/2017-9.md)
- [New features in the 2018.1 migration guide](/guides/web/release-notes/2018-1.md)
- [PSPDFKit for Web 2018.2 migration insights](/guides/web/release-notes/2018-2.md)
- [Discover the new features in PSPDFKit for Web 2018.3](/guides/web/release-notes/2018-3.md)
- [Explore PSPDFKit for Web 2018.4 features](/guides/web/release-notes/2018-4.md)
- [Explore new features in PSPDFKit 2018.5](/guides/web/release-notes/2018-5.md)
- [Explore PSPDFKit for Web 2018.6 enhancements](/guides/web/release-notes/2018-6.md)
- [Explore the new features in PSPDFKit 2018.7](/guides/web/release-notes/2018-7.md)
- [Key updates in PSPDFKit for Web 2019.1](/guides/web/release-notes/2019-1.md)
- [2019 2](/guides/web/release-notes/2019-2.md)
- [PSPDFKit for Web 2019.3 migration highlights](/guides/web/release-notes/2019-3.md)
- [Essential updates in PSPDFKit for Web 2019.4](/guides/web/release-notes/2019-4.md)
- [PSPDFKit for Web 2019.5 migration insights](/guides/web/release-notes/2019-5.md)
- [Key changes in PSPDFKit for Web 2020.1](/guides/web/release-notes/2020-1.md)
- [Seamless migration to PSPDFKit for Web 2020.2](/guides/web/release-notes/2020-2.md)
- [Upgrade to PSPDFKit Web 2020.3 seamlessly](/guides/web/release-notes/2020-3.md)
- [PSPDFKit Web and Server 2020.4 migration update](/guides/web/release-notes/2020-4.md)
- [Unified CRUD API enhancements for easy migration](/guides/web/release-notes/2020-5.md)
- [PSPDFKit Web 2020.6 migration insights](/guides/web/release-notes/2020-6.md)
- [Upgrade to PSPDFKit for Web 2021.1 with ease](/guides/web/release-notes/2021-1.md)
- [Seamlessly migrate to PSPDFKit for Web 2021.2](/guides/web/release-notes/2021-2.md)
- [2021 3](/guides/web/release-notes/2021-3.md)
- [PSPDFKit 2021.4 migration guide for seamless updates](/guides/web/release-notes/2021-4.md)
- [Migration guide for PSPDFKit 2021.5](/guides/web/release-notes/2021-5.md)
- [2021 6](/guides/web/release-notes/2021-6.md)
- [PSPDFKit 2022.1.1 migration changes](/guides/web/release-notes/2022-1.md)
- [Enhancements in PSPDFKit for Web 2022.2](/guides/web/release-notes/2022-2.md)
- [Explore the new features of PSPDFKit for Web 2022.3](/guides/web/release-notes/2022-3.md)
- [PSPDFKit for Web 2022.4 migration overview](/guides/web/release-notes/2022-4.md)
- [Key improvements in PSPDFKit for Web 2022.5](/guides/web/release-notes/2022-5.md)
- [Discover the key updates in PSPDFKit for Web 2023.1](/guides/web/release-notes/2023-1.md)
- [PSPDFKit 2023.2 migration and updates](/guides/web/release-notes/2023-2.md)
- [Key updates in PSPDFKit for Web 2023.3](/guides/web/release-notes/2023-3.md)
- [Explore key updates in PSPDFKit for Web 2023.4](/guides/web/release-notes/2023-4.md)
- [Key updates in PSPDFKit for Web 2023.5](/guides/web/release-notes/2023-5.md)
- [Essential Nutrient Web SDK 2024.1 migration tips](/guides/web/release-notes/2024-1.md)
- [2024 2](/guides/web/release-notes/2024-2.md)
- [2024 3](/guides/web/release-notes/2024-3.md)
- [2024 4](/guides/web/release-notes/2024-4.md)
- [2024 5](/guides/web/release-notes/2024-5.md)
- [2024 7](/guides/web/release-notes/2024-7.md)
- [2024 8](/guides/web/release-notes/2024-8.md)
- [Upgrading Nutrient Web SDK](/guides/web/release-notes/upgrading.md)

