Nutrient

SDK

Cloud

Low-Code

Workflow

Node.js PDF API [JavaScript] — Getting started

With Nutrient’s Node.js PDF API, you can quickly process your documents by making HTTP requests to one of our 50+ API tools. You can make a single request to one tool or combine API actions to generate, edit, OCR, and convert your document (1 document can have multiple API actions).

Using our TypeScript/JavaScript SDK

For the best developer experience, we recommend using our official TypeScript/JavaScript SDK library:

Nutrient DWS TypeScript Client

Installation

Shell
npm install @nutrient-sdk/dws-client-typescript

# Enable enhanced code completion and documentation for Claude Code using the Nutrient DWS SDK
npx dws-add-claude-code-rule

# Enable enhanced code completion and documentation for GitHub Copilot using the Nutrient DWS SDK
npx dws-add-github-copilot-rule

# Enable enhanced code completion and documentation for Junie (Jetbrains) using the Nutrient DWS SDK
npx dws-add-junie-rule

# Enable enhanced code completion and documentation for Cursor using the Nutrient DWS SDK
npx dws-add-cursor-rule

# Enable enhanced code completion and documentation for Windsurf using the Nutrient DWS SDK
npx dws-add-windsurf-rule

Quick example

JavaScript
import { NutrientClient } from '@nutrient-sdk/dws-client-typescript';
import fs from 'fs';

const client = new NutrientClient({
  apiKey: 'your_api_key_here',
});

// Add an image watermark to a document.
const imageResult = await client.watermarkImage('./document.pdf', './logo.png', {
  width: { value: 50, unit: '%' }
});

fs.writeFileSync('./watermarked-document.pdf', Buffer.from(imageResult.buffer));

// Redact and archive a document set using chained workflow.
const archivedResult = await client
  .workflow()
  // Add documents from multiple formats (PDF, DOCX, PNG).
  .addFilePart("./form.docx")
  .addFilePart("./policy.pdf")
  .addFilePart("./image.png")
  // Apply multiple actions: watermark and redactions using `applyActions`.
  .applyActions([
    BuildActions.createRedactionsPreset('email-address'),
    BuildActions.createRedactionsPreset('international-phone-number'),
    BuildActions.createRedactionsPreset('north-american-phone-number'),
    BuildActions.applyRedactions(),
    BuildActions.watermarkText('ARCHIVED', {
      opacity: 0.45,
      fontSize: 32,
      fontColor: '#FF0000',
      rotation: 45,
      fontStyle: ['bold']
    }),
  ])
  // Output as PDF/A format.
  .outputPdfA({
    conformance: 'pdfa-2b',
    vectorization: true,
    metadata: {
      title: 'Multi-Format Merged Document',
      author: 'Archive.org',
    },
    optimize: {
      mrcCompression: true,
      imageOptimizationQuality: 3
    }
  })
  // Tracking progress.
  .execute({
    onProgress: (current: number, total: number) => {
      console.log(`Processing step ${current} of ${total}`);
    }
  });

fs.writeFileSync('./archived-document.pdf', Buffer.from(archivedResult.buffer));

Alternative: Using raw HTTP requests

If you prefer to use raw HTTP requests or want to understand the underlying API calls, you can also interact with the API directly using any HTTP client.

Nutrient DWS API is designed to be used from a server and not a browser, so this guide will show you how to use Node.js and the axios HTTP library to use Nutrient DWS API. Keep in mind that you can use any HTTP client you want; this example simply uses axios to demonstrate the principles of interacting with Nutrient DWS API.

Raw HTTP request example

This section will demonstrate how you can use JavaScript to make HTTP requests with our API by:

  1. 1
    Installing the required dependencies
  2. 2
    Preparing the payload
  3. 3
    Making the request

Installing the required dependencies

The first thing you need to do is to create a new Node.js app and install the dependencies.

For the npm init call, you can press return for all of the questions to accept their defaults:

Shell
npm init
npm install axios
npm install form-data

You’ll also need to add document.pdf and logo.png files to the root of your Node.js project (the same folder you’ll be creating the index.js file in). You can use the sample files provided by us — document.pdf and logo.png — or use your own.

Now that you have your dependencies and assets set up, you’re ready to start making requests to Nutrient DWS API.

First, create an index.js file, which will contain your code to call Nutrient DWS API. You can immediately import your dependencies as well:

JavaScript
const axios = require('axios')
const FormData = require('form-data')
const fs = require('fs')

Next, you’ll prepare the payload.

Preparing the payload

You can create your FormData object, which contains the instructions and all the files sent to the API. You’ll start with the instructions object:

JavaScript
const formData = new FormData()
formData.append('instructions', JSON.stringify({
  parts: [
    {
      file: "document"
    }
  ],
  actions: [
    {
      type: "watermark",
      image: "company-logo",
      width: "50%"
    },
    {
      type: "watermark",
      text: "Property of Nutrient",
      width: 150,
      height: 20,
      left: 0,
      bottom: "100%"
    }
  ]
}))

Here, you add your instructions JSON to your FormData object. In this example, you’ll be adding an image watermark. For more details on the available options specifically related to watermarking, refer to our watermarking guide.

Next, you need to include your source assets, document.pdf and logo.png, with your request:

JavaScript
formData.append('document', fs.createReadStream('document.pdf'))
formData.append('company-logo', fs.createReadStream('logo.png'))

Now, you’ll make the request.

Making the request

With your FormData object being populated, you can now send the actual request. Make sure to replace the your_api_key_here placeholder with your actual API key if it hasn’t yet been replaced:

JavaScript
axios.post('https://api.nutrient.io/build', formData, {
  headers: formData.getHeaders({
    'Authorization': 'Bearer your_api_key_here'
  }),
  responseType: "stream"
})
  .then(function (response) {
    response.data.pipe(fs.createWriteStream("result.pdf"))
  })
  .catch(async function (e) {
    console.log(e)
    const errorString = await streamToString(e.response.data)
    console.log(errorString)
  })

function streamToString(stream) {
  const chunks = []
  return new Promise((resolve, reject) => {
    stream.on("data", (chunk) => chunks.push(Buffer.from(chunk)))
    stream.on("error", (err) => reject(err))
    stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")))
  })
}

Here, you’re setting the responseType to stream to make sure the resulting PDF isn’t loaded entirely into memory. You also write the final result to result.pdf. And with that, you’re done. You can now run your code using node index.js, and result.pdf should be created.

While this example made use of our watermarking API, this same approach can be used for all our available API tools.

ℹ️ Note: streamToString only exists to format any errors you might receive, as you can’t print the stream directly.

Full code

For your convenience, here’s the whole code. Just copy it and run it:

JavaScript
const axios = require('axios')
const FormData = require('form-data')
const fs = require('fs')

const formData = new FormData()
formData.append('instructions', JSON.stringify({
  parts: [
    {
      file: "document"
    }
  ],
  actions: [
    {
      type: "watermark",
      image: "company-logo",
      width: "50%"
    },
    {
      type: "watermark",
      text: "Property of Nutrient",
      width: 150,
      height: 20,
      left: 0,
      bottom: "100%"
    }
  ]
}))

formData.append('document', fs.createReadStream('document.pdf'))
formData.append('company-logo', fs.createReadStream('logo.png'))

axios.post('https://api.nutrient.io/build', formData, {
  headers: formData.getHeaders({
    'Authorization': 'Bearer your_api_key_here'
  }),
  responseType: "stream"
})
  .then(function (response) {
    response.data.pipe(fs.createWriteStream("result.pdf"))
  })
  .catch(async function (e) {
    console.log(e)
    const errorString = await streamToString(e.response.data)
    console.log(errorString)
  })

function streamToString(stream) {
  const chunks = []
  return new Promise((resolve, reject) => {
    stream.on("data", (chunk) => chunks.push(Buffer.from(chunk)))
    stream.on("error", (err) => reject(err))
    stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")))
  })
}