Skip to main content


We are proud to release version 2.0 of WebViewer collaboration!

This release was focused on improving compatibility with existing systems - including a brand new client side API. We also added some cool new features for working with custom data and implementing versioning!

We also released a brand new module, a resolver generator for SQL-like databases! This package is a utility that can be used to generate resolvers for you, instead of you having to manually write them yourself. This makes implementing collaboration even faster and easier!

Breaking changes#

New client API#

We have learned a lot the last few months about how customers are using the product and how WebViewer Collaboration fits into certain workflows. As a result, we have made some major changes to the client side API to make it easier to use and understand.

All of the existing functionality still exists, however it is laid out much differently.

The new client API separates functionality into classes. Each entity (documents, annotations, users, snapshots, and mentions) each have their own class with their own functionality. This is a big change from the old client API, which was one giant monolith class that contained all functionality.

Methods to log in a user remain the same - loginWithToken, loginWithPassword and loginAnonymously still exist on the base CollaborationClient class. However, these functions now return a User object which is the root class used to interact with the collaboration flow.

Operations like creating documents and fetching documents are now a functionality of the User class. These functions were moved to the User class because we are fetching or creating documents that belong to the logged in User.

Operations like viewing and editing a document are moved to the Document class. When calling one of these functions, the operation will be applied to that specific document.

The rest of the API changes are very similar - functionality has been moved to the corresponding entity class.

For instructions on upgrading, see the migration guide.


In version 1, timestamps passed into your resolvers were always unix timestamps, mostly calculated from However, most databases have a built in mechanism for setting timestamps, usually in the form of a constant like CURRENT_TIMESTAMP.

Because of this, we made some major changes to our internals to make handling timestamps easier for you.

Now, instead of receiving a unix timestamp in your resolvers, you will receive whatever is returned from your getNow() function.

This allows you to use a database constant instead of a JS date for your timestamps! See the timestamps guide for more information.

ID generation#

In version 1, IDs of new entities were generated internally and set to a UUID. However, this method does not work for many databases (for example, a database with auto incrementing integers for IDS).

Version 2 of WebViewer Collaboration removes all internal ID generation and leaves that up to your resolvers and/or database.

Write mutation resolvers will no longer be provided an ID. Instead, rely on your database to generate an ID.

This change also means we removed the idGenerator options from all packages.

See the resolvers guide for more information.

Added annotationId property to Annotation entity#

This release adds an additional required property to the Annotation entity - annotationId.

This property is set to the ID generated by the client when the annotation was created.

This change was made to make managing annotations easier for cross-platform clients (coming soon).

Added isPublic parameter to documents resolver#

The documents resolver now accepts an additional isPublic parameter, used to fetch all public documents.

Please update your resolver code to apply this additional field.

Upgraded to WebViewer 8.0#

This release upgrades the collaboration service to require WebViewer 8.0. This update does not break any collaboration APIs, but may break your code around the collab service.

View the migration guide here.

Custom permissions parameter change#

This release makes a potentially breaking change to the custom roles feature. The second parameter was changed to accept a userId instead of a user entity. If you need access to the entire user entity inside this function, you can fetch it yourself using the userId.

documentId parameter added to annotationMembers query resolver.#

A documentId was added to the annotationMembers resolver. This allows us to fetch all annotation members for a document in a single query.

COLLAB_KEY environment variable now required#

In version 1, the COLLAB_KEY environment variable was only required in certain situations. In version 2.0, it must now always be set.

Read more here.

Migration guide#

For more details on upgrading from v1 to v2, see the migration guide.

SQL Resolver Generator#

Version 2 comes with a major upgrade in the shape of a new utility module. The SQL Resolver Generator is a utility package that generates resolvers for you!

The package accepts a configuration object with information about your database and its table and columns, and spits out resolvers that can be plugged directly in to the Collaboration Server.

For more info on this package, see the get started guide.

New features#

Versioning / Snapshots#

Version 2.0 adds a new data type - Snapshots.

This is an opt-in feature that allows you to create a snapshot of a document at a certain period in time, and revert the document back to that state at a future date. This is useful for implementing versioning features.

Snapshots can be created with the new Document.createSnapshot API, and fetched with the Document.getSnapshotPaginator or Document.getAllSnapshots APIs.

For more information on snapshots, see this guide.


All modules received a major upgrade with our new context feature.

The context feature allows you to easily pass custom data about the user between client/server/database. This is useful for scenarios where you have some custom data that needs to be written to your database that the Collaboration modules are not aware of.

Here is a very basic example:

// Collab client
import { CollabClient } from '@pdftron/collab-client'
const client = new CollabClient({ ...options })
await client.setContext({
projectId: 'abcd'
// Collab server
import CollabServer from '@pdftron/collab-server'
const server = new CollabServer({
resolvers: {
Mutation: {
addDocument: (document, context) => {
console.log(context.projectId) // 'abcd'
// Insert document to DB here

This feature spans across most of the modules. See the guides to get started:



  • Added annotationId property to the annotation entity.
  • Added better error messaging to the testing suite
  • Improved and optimized token based authentication flow
  • Fixed issue where not providing a documentId to loadDocument threw errors
  • Added getNow() parameter
  • Removed ID generation in favour of DB ID generation
    • The idGenerator constructor parameter is no longer supported.
  • Added context feature
  • Mutation resolvers are now required to return the entity that was written.
  • Fixed issue where annotations could still be created without permissions
  • Updated permissions custom roles authFunction parameter user (object) to userId (string)
  • getUserFromToken now has access to request cookies
  • Fixes issue where server could crash every 10 minutes when running memory checks
  • Added authentication specific debug logging
  • Switched from cookie based authentication to header based authentication
  • Removed jwtCookieName option
  • The editMention resolver is no longer required
  • Fixed bug where marking comments as read did not update the UI properly
  • Fixed bug where invites with integer IDs would break
  • The COLLAB_KEY environment variable is now required



  • Added connectionString, ssl, statementTimeout, queryTimeout, and idleInTransactionSessionTimeout options. See here for more info.
  • Added SSL options for connecting to the database.
  • Removed dependency on collab-server. Calling setServer is now no longer required.
  • transform functions now receive context as a second parameter