Node.js rendering and font diagnostics
This example shows how to collect the most useful diagnostics for rendering and font investigations in DWS Viewer API.
The script fetches:
- Document fonts
- Global fonts
- Global font substitutions
- Document information
- Document properties
- A rendered preview image for one page
It then saves the results locally so they can be attached to a support ticket or compared across environments.
Prerequisites
- A DWS Viewer API key in
NUTRIENT_DWS_VIEWER_API_KEY - A
documentIdfor the file you want to investigate - Node.js 18 or later
Complete example
The following code is a complete example. You can copy and paste it into a file named diagnostics.mjs and run it with Node.js:
import { mkdir, writeFile } from "node:fs/promises";import path from "node:path";
const apiKey = process.env.NUTRIENT_DWS_VIEWER_API_KEY;const documentId = process.argv[2];const pageIndex = Number(process.argv[3] ?? 0);const outputDir = path.resolve(process.argv[4] ?? `./dws-diagnostics-${documentId}`);
if (!apiKey) { throw new Error("Missing NUTRIENT_DWS_VIEWER_API_KEY");}
if (!documentId) { throw new Error("Usage: node diagnostics.mjs <documentId> [pageIndex] [outputDir]");}
await mkdir(outputDir, { recursive: true });
const requestJson = async (pathname) => { const response = await fetch(`https://api.nutrient.io${pathname}`, { headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json", }, });
if (!response.ok) { const errorText = await response.text(); throw new Error(`${pathname} failed: ${response.status} ${errorText}`); }
return response.json();};
const requestBinary = async (pathname, accept) => { const response = await fetch(`https://api.nutrient.io${pathname}`, { headers: { Authorization: `Bearer ${apiKey}`, Accept: accept, }, });
if (!response.ok) { const errorText = await response.text(); throw new Error(`${pathname} failed: ${response.status} ${errorText}`); }
return Buffer.from(await response.arrayBuffer());};
const diagnostics = { documentFonts: await requestJson(`/viewer/documents/${documentId}/fonts`), globalFonts: await requestJson("/viewer/fonts"), fontSubstitutions: await requestJson("/viewer/font_substitutions"), documentInfo: await requestJson(`/viewer/documents/${documentId}/document_info`), documentProperties: await requestJson(`/viewer/documents/${documentId}/properties`),};
const previewImage = await requestBinary( `/viewer/documents/${documentId}/pages/${pageIndex}/image?width=1600`, "image/png",);
await Promise.all([ writeFile( path.join(outputDir, "document-fonts.json"), JSON.stringify(diagnostics.documentFonts, null, 2), ), writeFile( path.join(outputDir, "global-fonts.json"), JSON.stringify(diagnostics.globalFonts, null, 2), ), writeFile( path.join(outputDir, "font-substitutions.json"), JSON.stringify(diagnostics.fontSubstitutions, null, 2), ), writeFile( path.join(outputDir, "document-info.json"), JSON.stringify(diagnostics.documentInfo, null, 2), ), writeFile( path.join(outputDir, "document-properties.json"), JSON.stringify(diagnostics.documentProperties, null, 2), ), writeFile(path.join(outputDir, `page-${pageIndex}.png`), previewImage),]);
console.log(`Saved diagnostics to ${outputDir}`);Run the script
Run the script with your API key and a document ID. Optionally, specify a page index (default 0) and an output directory (default ./dws-diagnostics-<documentId>):
export NUTRIENT_DWS_VIEWER_API_KEY=your_api_key_herenode diagnostics.mjs <document_id> 0Example output directory:
./dws-diagnostics-<document_id>/├── document-fonts.json├── document-info.json├── document-properties.json├── font-substitutions.json├── global-fonts.json└── page-0.pngHow to read the output
document-fonts.json— Font faces referenced by the documentglobal-fonts.json— Font faces globally available in DWS Viewer APIfont-substitutions.json— Configured replacement patterns for missing fontsdocument-info.json— Page count, page sizes, metadata, and permissionsdocument-properties.json— File properties such as byte size, SHA-256, storage type, and password-protection statuspage-0.png— A server-rendered preview you can compare with what you see in the browser