---
title: "Reviewer-isolated layers"
canonical_url: "https://www.nutrient.io/guides/dws-viewer/developer-guides/reviewer-isolated-layers/"
md_url: "https://www.nutrient.io/guides/dws-viewer/developer-guides/reviewer-isolated-layers.md"
last_updated: "2026-06-05T20:16:40.202Z"
description: "Learn how to keep each reviewer’s comments separate by creating a dedicated DWS Viewer layer, generating a layer-scoped session, and exporting that reviewed layer as a PDF."
---

# Reviewer-isolated layers

Use reviewer-isolated layers when multiple reviewers need to work on the same document without seeing or modifying one another’s review state.

In this workflow, you upload the PDF once, create one layer per reviewer, add comments to that reviewer’s layer, generate a session token scoped to that layer, and export that layer as a PDF when the review is complete.

For this workflow, store reviewer state in DWS Viewer layers rather than managing Instant JSON yourself.

## Workflow overview

1. Upload the shared document once.

2. Create one DWS Viewer layer per reviewer, or let Web SDK create it on first write.

3. Add comments in that reviewer’s layer.

4. Generate a session token scoped to that document and layer.

5. Open the document in Nutrient Web SDK with that session token.

6. Export the reviewed layer as a PDF with comments.

## 1. Create a reviewer layer

Create a dedicated layer for each reviewer with [`POST /viewer/documents/{documentId}/layers`](https://www.nutrient.io/api/reference/viewer/public/#tag/Layers/operation/create-new-layer):

```shell

curl -X POST "https://api.nutrient.io/viewer/documents/<document_id>/layers" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <api_key>" \
  --fail \
  -d '{
    "name": "reviewer-alice"
  }'

```

Response:

```json

{
  "data": {
    "name": "reviewer-alice",
    "errors": []
  }
}

```

Use a stable layer name for each reviewer — for example, `reviewer-alice`, `reviewer-bob`, or an internal reviewer ID.

### Optional: Let Web SDK create the layer on first write

If you don’t need to seed a reviewer’s layer from your backend before they start reviewing, you can skip explicit layer creation and mint a session token scoped to that layer name instead.

DWS Viewer layers use copy-on-write semantics — a layer is created on a reviewer’s first write through Web SDK, not when you mint the session token. See [open a document in Web SDK](https://www.nutrient.io/guides/dws-viewer/developer-guides/open-a-document-in-web.md) for how to load the document with their session. This can be useful when you assign many potential reviewer layers but expect only a subset of reviewers to actually make changes.

## 2. Create comments in that layer

To create a new comment thread inside the reviewer’s layer, add the root annotation and the first comment together with [`POST /viewer/documents/{documentId}/layers/{layerName}/comments`](https://www.nutrient.io/api/reference/viewer/public/#tag/Comments/operation/create-document-layer-comments):

```shell

curl -X POST "https://api.nutrient.io/viewer/documents/<document_id>/layers/reviewer-alice/comments" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <api_key>" \
  --fail \
  -d '{
    "annotation": {
      "content": {
        "v": 2,
        "type": "pspdfkit/comment-marker",
        "pageIndex": 0,
        "bbox": [72, 72, 32, 32],
        "icon": "comment",
        "text": "Please verify clause 4.2",
        "isCommentThreadRoot": true
      }
    },
    "comments": [
      {
        "content": {
          "text": "Please verify clause 4.2",
          "creatorName": "Alice Reviewer"
        }
      }
    ]
  }'

```

Response:

```json

{
  "data": {
    "annotation": {
      "id": "<root_annotation_id>"
    },
    "comments": [
      {
        "id": "<comment_id>"
      }
    ]
  }
}

```

If you want to add another reply to the same thread later, use [`POST /viewer/documents/{documentId}/layers/{layerName}/annotations/{annotationId}/comments`](https://www.nutrient.io/api/reference/viewer/public/#tag/Comments/operation/create-document-layer-annotation-comments):

```shell

curl -X POST "https://api.nutrient.io/viewer/documents/<document_id>/layers/reviewer-alice/annotations/<root_annotation_id>/comments" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <api_key>" \
  --fail \
  -d '{
    "comments": [
      {
        "content": {
          "text": "Flagging this for legal review.",
          "creatorName": "Alice Reviewer"
        }
      }
    ]
  }'

```

## 3. Generate a layer-scoped session token

Generate the reviewer’s session token with [`POST /viewer/sessions`](https://www.nutrient.io/api/reference/viewer/public/#tag/Authorization/operation/generate-session-token). Set both `document_id` and `layer` in `allowed_documents`. The `layer` value restricts access to that reviewer’s layer:

A reviewer-specific browser session should be scoped with `allowed_documents[].layer`. Otherwise, the reviewer won’t be restricted to the intended layer.

```shell

curl -X POST https://api.nutrient.io/viewer/sessions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <api_key>" \
  --fail \
  -d '{
    "allowed_documents": [
      {
        "document_id": "<document_id>",
        "layer": "reviewer-alice",
        "permissions": ["read", "write", "download"]
      }
    ],
    "exp": 1793769299
  }'

```

Response:

```json

{
  "jwt": "<reviewer_layer_session_token>"
}

```

## 4. Open the reviewer layer in Nutrient Web SDK

Pass the returned top-level `jwt` value to `NutrientViewer.load()`:

```js

await NutrientViewer.load({
  container: document.querySelector("#viewer-container"),

  session: "<reviewer_layer_session_token>",
});

```

## 5. Export the reviewed layer as a PDF with comments

When the reviewer is done, export that layer as a PDF with comments using [`GET /viewer/documents/{documentId}/layers/{layerName}/pdf`](https://www.nutrient.io/api/reference/viewer/public/#tag/Layers/operation/download-document-layer-pdf):

```shell

curl -L "https://api.nutrient.io/viewer/documents/<document_id>/layers/reviewer-alice/pdf?comments=true" \
  -H "Authorization: Bearer <api_key>" \
  --fail \
  -o reviewer-alice.pdf

```

If you want a PDF/A export instead, add `type=pdfa` and a `conformance` value supported by the endpoint.

## End-to-end Node.js example

Below is an end-to-end example of the workflow above in Node.js. It uses `node-fetch` to make API requests, but you can use any HTTP client library.

```js

const apiKey = process.env.NUTRIENT_DWS_VIEWER_API_KEY;
const documentId = "<document_id>";
const layerName = "reviewer-alice";

const headers = {
  "Content-Type": "application/json",
  Authorization: `Bearer ${apiKey}`,
};

// 1. Create the reviewer layer.
await fetch(`https://api.nutrient.io/viewer/documents/${documentId}/layers`, {
  method: "POST",
  headers,
  body: JSON.stringify({ name: layerName }),
});

// 2. Create a comment thread in that layer.
const commentResponse = await fetch(
  `https://api.nutrient.io/viewer/documents/${documentId}/layers/${layerName}/comments`,
  {
    method: "POST",
    headers,
    body: JSON.stringify({
      annotation: {
        content: {
          v: 2,
          type: "pspdfkit/comment-marker",
          pageIndex: 0,
          bbox: [72, 72, 32, 32],
          icon: "comment",
          text: "Please verify clause 4.2",
          isCommentThreadRoot: true,
        },
      },
      comments: [
        {
          content: {
            text: "Please verify clause 4.2",
            creatorName: "Alice Reviewer",
          },
        },
      ],
    }),
  },
);

const commentResult = await commentResponse.json();
const rootAnnotationId = commentResult.data.annotation.id;

// 3. Add another reply in the same layer.
await fetch(
  `https://api.nutrient.io/viewer/documents/${documentId}/layers/${layerName}/annotations/${rootAnnotationId}/comments`,
  {
    method: "POST",
    headers,
    body: JSON.stringify({
      comments: [
        {
          content: {
            text: "Flagging this for legal review.",
            creatorName: "Alice Reviewer",
          },
        },
      ],
    }),
  },
);

// 4. Generate a layer-scoped browser session.
const sessionResponse = await fetch("https://api.nutrient.io/viewer/sessions", {
  method: "POST",
  headers,
  body: JSON.stringify({
    allowed_documents: [
      {
        document_id: documentId,
        layer: layerName,                     // Restricts access to only this layer
        permissions: ["read", "write", "download"],
      },
    ],
    exp: Math.floor(Date.now() / 1000) + 60 * 60,
  }),
});

const { jwt } = await sessionResponse.json();
console.log("Session token:", jwt);

// 5. Export the reviewed layer as PDF with comments.
const pdfResponse = await fetch(
  `https://api.nutrient.io/viewer/documents/${documentId}/layers/${layerName}/pdf?comments=true`,
  {
    headers: {
      Authorization: `Bearer ${apiKey}`,
    },
  },
);

const pdfBuffer = Buffer.from(await pdfResponse.arrayBuffer());

```

## Related guides

- [Generate a session token](https://www.nutrient.io/guides/dws-viewer/developer-guides/generate-a-session-token.md)

- [Open a document in Web SDK](https://www.nutrient.io/guides/dws-viewer/developer-guides/open-a-document-in-web.md)

- [Node.js integration example](https://www.nutrient.io/guides/dws-viewer/examples/nodejs-integration-example.md)

- [Collaboration permissions overview](https://www.nutrient.io/guides/document-engine/instant-synchronization/permissions/overview.md)
---

## Related pages

- [DWS Viewer API backend authentication](/guides/dws-viewer/developer-guides/backend-authentication.md)
- [Architecture of DWS Viewer API integration](/guides/dws-viewer/developer-guides/architecture.md)
- [Deployment options](/guides/dws-viewer/developer-guides/deployment-options.md)
- [Dashboard](/guides/dws-viewer/developer-guides/dashboard.md)
- [DWS Viewer API client authentication flow](/guides/dws-viewer/developer-guides/client-authentication-flow.md)
- [DWS Viewer API developer guides](/guides/dws-viewer/developer-guides.md)
- [Open a document in Web SDK](/guides/dws-viewer/developer-guides/open-a-document-in-web.md)
- [Generate a session token](/guides/dws-viewer/developer-guides/generate-a-session-token.md)
- [Integrate DWS Viewer API with your own backend](/guides/dws-viewer/developer-guides/use-with-your-backend.md)
- [Upload documents](/guides/dws-viewer/developer-guides/upload-documents.md)

