Free tools Windows power users keep installed
One-click scans. No signup required.
Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Render TeX or MathML before calling pdf.create. Generate static KaTeX HTML or MathJax SVG/MathML on the server, include the renderer’s CSS and font files, make every asset URL resolvable to PhantomJS, and wait for any remaining browser-side typesetting to finish. This avoids missing equations, square boxes, and fonts that work on a laptop but fail in production. The html-pdf package (version 3.0.1 in its npm listing) is deprecated, so use this pipeline for an existing system while evaluating Puppeteer or another maintained Chromium renderer for new work.
What node-html-pdf actually captures
node-html-pdf sends your HTML to PhantomJS and creates a PDF from the rendered page. It does not understand TeX commands such as frac{a}{b} by itself. If the source HTML still contains TeX when PhantomJS takes its snapshot, the PDF will show the raw command, an empty region, or a missing glyph.
There are two reliable pipelines:
- Server-side conversion: turn TeX into static HTML/CSS with KaTeX, or into SVG/MathML with MathJax-node, then pass the finished markup to
pdf.create. - Browser-side conversion: leave a math script in the page, but delay PDF capture until that script has inserted its final markup and styles.
The first pipeline is more deterministic because the PDF renderer receives final content. A delay is only a synchronization aid; it cannot repair a failed script, an unavailable font, or a wrong asset path.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Choose an output format for your equations
| Renderer | Input | Output you place in the HTML | Practical implication |
|---|---|---|---|
| KaTeX | TeX | HTML elements plus KaTeX CSS | Fast server rendering; bundle the CSS and KaTeX fonts with the document. |
| MathJax-node | TeX, inline TeX, or MathML | HTML, SVG, or MathML | Useful when MathML input or SVG isolation is important; configure its webfont URLs when using HTML output. |
| Unicode text | Individual Unicode symbols | Normal text glyphs | Only safe when the selected font contains the glyph; unsupported characters can fall back to a system font and shift vertically. |
For symbols that must look identical on every machine, prefer a supported TeX command over a literal Unicode character. KaTeX supports many mathematical Unicode alphanumeric symbols, but its documented fallback behavior means unrecognized characters may use system fonts with different metrics.
#1 Best Overall
- Convert your PDF files into Word, Excel & Co. the easy way
- Convert scanned documents thanks to our new 2022 OCR technology
- Adjustable conversion settings
- No subscription! Lifetime license!
- Compatible with Windows 11, 10, 8.1, 7 - Internet connection required
Complete KaTeX and node-html-pdf example
Install the packages
- Use a supported Node.js runtime and create a project directory.
- Install the converter and renderer:
npm install html-pdf katex. - Keep the KaTeX package’s
dist/fontsdirectory in the deployment artifact. The CSS references those files.
Render TeX before creating the PDF
The following script renders a display equation and an inline expression before PhantomJS sees the document. It resolves the CSS through an absolute file:// URL and sets a base directory for other relative resources.
const fs = require('fs');
const path = require('path');
const katex = require('katex');
const pdf = require('html-pdf');
const cssPath = require.resolve('katex/dist/katex.min.css');
const cssUrl = 'file://' + cssPath;
const baseDir = path.resolve(__dirname);
const displayMath = katex.renderToString(
String.raw`int_0^1 x^2,dx = frac{1}{3}`,
{ displayMode: true, throwOnError: false }
);
const inlineMath = katex.renderToString(
String.raw`e^{ipi}+1=0`,
{ displayMode: false, throwOnError: false }
);
const html = `<!doctype html>
<html>
<head>
<meta charset='utf-8'>
<link rel='stylesheet' href='${cssUrl}'>
<style>
@page { margin: 24mm 18mm; }
body { font-family: Arial, sans-serif; font-size: 11pt; }
.katex-display { margin: 1em 0; }
</style>
</head>
<body>
<h1>A short derivation</h1>
<p>Euler's identity is ${inlineMath}.</p>
<div>${displayMath}</div>
</body>
</html>`;
const options = {
format: 'A4',
orientation: 'portrait',
base: `file://${baseDir}/`,
localUrlAccess: true,
timeout: 60000,
renderDelay: 0
};
pdf.create(html, options).toFile('./equations.pdf', (err, result) => {
if (err) throw err;
console.log(`Wrote ${result.filename}`);
});
renderToString is synchronous, so renderDelay: 0 is appropriate here: the equations already exist in the HTML string. Set throwOnError: true in a build that should fail on invalid TeX; keeping it false lets you produce a PDF while visibly marking an unsupported expression.
Why the CSS and fonts are mandatory
KaTeX’s server-rendering documentation notes that generated markup still depends on its CSS and font files. Copying only the HTML fragment produces missing radicals, incorrect spacing, or fallback text. In a container or CI job, verify that the installed package contains dist/katex.min.css and dist/fonts, and that the process user can read them. If you bundle assets yourself, preserve the relative directory layout expected by the CSS.
Using MathJax-node instead
MathJax-node accepts TeX, inline TeX, or MathML and can return HTML, SVG, or MathML. SVG is often convenient for PDF output because each equation carries its own geometry; HTML output requires MathJax’s configured webfont URLs.
Rank #2
- Convert over 50 document file formats.
- Preview your files from Doxillion before converting them.
- Use batch conversion to convert thousands of files at once.
- Enjoy an easy-to-use, intuitive interface with a Drag and Drop file option.
- Burn your converted or original files directly to disc.
const fs = require('fs');
const pdf = require('html-pdf');
const mj = require('mathjax-node');
mj.start();
function texToSvg(math) {
return new Promise((resolve, reject) => {
mj.typeset({ math, format: 'TeX', svg: true }, data => {
if (data.errors) return reject(new Error(data.errors.join('; ')));
resolve(data.svg);
});
});
}
(async () => {
const svg = await texToSvg(String.raw`sum_{n=1}^{infty} 1/2^n = 1`);
const html = `<html><head><meta charset='utf-8'></head><body>${svg}</body></html>`;
pdf.create(html, {
format: 'A4',
timeout: 60000,
renderDelay: 0
}).toFile('./mathjax-equation.pdf', err => {
if (err) throw err;
});
})();
When accepting MathML from users, sanitize the surrounding HTML before inserting it into a document. MathJax conversion does not make unrelated HTML safe. Also decide whether your chosen MathJax configuration embeds SVG styles or references external resources; external references must be available to PhantomJS at capture time.
Make local resources resolvable to PhantomJS
Set a real base path
A browser page served from https://example.test may resolve /css/site.css from a web server. An HTML string passed to html-pdf commonly runs under file://, where that same URL does not point to your project directory. Use the package’s base option (or absolute URLs) so relative stylesheet, image, and font references map to actual files.
Understand localUrlAccess
localUrlAccess controls whether PhantomJS may read local resources. Enabling it is necessary for a local KaTeX stylesheet in many deployments, but it is security-sensitive. Never combine unrestricted local access with untrusted HTML. Prefer a dedicated working directory containing only the assets required for the PDF, and reject paths that escape that directory.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Allow every font file
Check the browser network log or PhantomJS debug output for each .woff, .woff2, or .ttf request. A CSS file that loads while its fonts fail still yields boxes or visibly different operators. Do not rely on fonts installed interactively on a developer workstation.
Rank #3
- EDIT text, images & designs in PDF documents. ORGANIZE PDFs. Convert PDFs to Word, Excel & ePub.
- READ and Comment PDFs – Intuitive reading modes & document commenting and mark up.
- CREATE, COMBINE, SCAN and COMPRESS PDFs
- FILL forms & Digitally Sign PDFs. PROTECT and Encrypt PDFs
- 1 Year License for 1 Windows & 2 Mobile (Android and/or iOS) devices.
When client-side MathJax or KaTeX remains in the page
If you cannot pre-render, expose an explicit completion signal. Have the page set a flag only after typesetting succeeds, then wait for that flag before creating the PDF. A fixed delay can be a fallback for a known, stable page but is not proof that equations finished.
<script>
window.mathReady = false;
MathJax.typesetPromise().then(() => {
window.mathReady = true;
}).catch(() => {
window.mathReady = 'error';
});
</script>
The html-pdf README documents renderDelay values, including waiting for a render event and waiting a specified number of milliseconds. Use the event-style completion mechanism when your page can provide one; otherwise choose a measured delay, keep it bounded, and fail the job if the flag never becomes true. A delay cannot fix a 404 stylesheet, a JavaScript exception, or a blocked font.
Fonts, operating systems, and reproducible builds
Reports for this project describe custom-font failures and different output on Windows and Linux. Treat the renderer runtime and font set as build inputs: pin the Node and PhantomJS versions, use the same container image in development and production, install the same system fonts, and keep KaTeX or MathJax assets inside your application artifact. Compare generated PDFs in CI after dependency updates rather than assuming a successful exit code means identical typography.
For Unicode-heavy documents, declare a font stack that actually contains the required ranges. A missing glyph may appear as a square even when Latin text looks normal. For deterministic mathematical symbols, TeX commands rendered by KaTeX or SVG from MathJax avoid many system-font substitutions.
Rank #4
- Perfect Adobe Acrobat Pro alternative – lifetime license for Windows 10 and 11.
- EDIT text, images, pages, hyperlinks, designs in PDF documents. ORGANIZE PDFs.
- READ and Comment on PDFs – Intuitive reading modes & document commenting and mark up tools!
- CREATE, COMBINE, SCAN and COMPRESS PDFs.
- FILL forms & Digitally Sign PDFs. Work with Digital certificates
Useful node-html-pdf options for equation-heavy documents
phantomPath: point to the PhantomJS binary shipped with your deployment instead of a developer-only installation.base: set the filesystem or URL base used by relative assets.localUrlAccess: permit local CSS and fonts only when the input is trusted and the asset directory is constrained.timeout: bound page loading and script execution; increase it for large documents, but keep a job-level deadline.renderDelay: wait for asynchronous typesetting when pre-rendering is impossible; prefer a completion signal.format,orientation, and margins: choose a page geometry that does not clip wide display equations.zoomFactoror equivalent scaling settings: change only after checking clipping and line breaks, because scaling can alter pagination.
Troubleshooting missing symbols and broken PDFs
| Symptom | Likely cause | Fix |
|---|---|---|
Raw alpha or frac appears |
TeX was never converted | Call KaTeX renderToString or MathJax-node before pdf.create. |
| Boxes or blank operators | Math fonts are missing or unreadable | Ship the renderer font directory, inspect URLs, and verify file permissions. |
| Math works in a browser but not in the PDF | PhantomJS captured before asynchronous typesetting or blocked a resource | Use static server output, then check renderDelay, completion signaling, and network paths. |
| Styles work locally but disappear in production | Relative URLs resolve differently under file:// |
Set base or use absolute local URLs; test inside the production image. |
| Only some Unicode symbols differ | Unsupported characters fell back to a system font | Replace them with supported TeX commands or install and explicitly select a font containing the glyph. |
| PDF creation times out | Slow scripts, remote assets, or a page waiting forever | Pre-render equations, self-host assets, set a finite timeout, and abort on a failed readiness signal. |
| Output differs by host OS | Different PhantomJS libraries or installed fonts | Pin the runtime image and compare PDFs in continuous integration. |
Performance, reliability, and maintenance
Server-side KaTeX avoids running a browser typesetter for every job and makes failures visible before PDF creation. Cache rendered equation fragments when the same TeX appears repeatedly, but include the renderer version and options in the cache key. For very large documents, assemble one HTML string and render once rather than launching PhantomJS per equation.
Keep remote images, stylesheets, and fonts out of the critical path where possible. A network timeout can leave a mathematically correct page looking incomplete. Record the source document identifier, renderer version, asset errors, and final PDF size so a production failure can be reproduced.
The npm listing marks html-pdf deprecated and includes the maintainer message, “Please migrate your projects to a newer library like puppeteer.” New systems should compare Puppeteer or Playwright with this PhantomJS pipeline. A migration is especially sensible when you need current JavaScript, modern CSS, reliable webfont loading, or browser automation maintained by an active project. If you must remain on node-html-pdf, isolate it behind a service and pin every dependency.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsOr skip the browser setup
If your math page is already hosted and its equations typeset correctly in a normal browser, ScreenshotNeo can fetch the URL and return a screenshot or PDF without you maintaining PhantomJS. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the page and billing result in X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.
One request is enough for a hosted PDF (replace the example URL with your page):
Best Value
- Convert over 50 document file formats.
- Preview your files from Doxillion before converting them.
- Use batch conversion to convert thousands of files at once.
- Enjoy an easy-to-use, intuitive interface with a Drag and Drop file option.
- Burn your converted or original files directly to disc.
curl -G 'https://api.screenshotneo.com/v1/shot' -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for PDF parameters, viewport and device settings, custom CSS or JavaScript, wait conditions, cookies, headers, geolocation, caching, signed links, asynchronous jobs, bulk capture, and usage reporting. The same service supports full-page captures with lazy images loaded, element selectors, dark mode, retina scale, transparent backgrounds, request blocking, and HTML/CSS-to-image workflows.
import requests
r = requests.get('https://api.screenshotneo.com/v1/shot', params={'access_key': 'YOUR_API_KEY', 'url': 'https://stripe.com'}, timeout=90)
r.raise_for_status()
open('shot.webp', 'wb').write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('shot.webp', data);
Every feature is included on every plan. The Free plan provides 1,000 shots per month with no card; paid plans are Starter ($5 for 3,000), Growth ($15 for 15,000), Pro ($39 for 60,000), Scale ($99 for 250,000), and Business ($249 for 1,000,000). Yearly billing gives two months free. If you want to try it, create a free ScreenshotNeo account with 1,000 screenshots a month and no card.
Frequently Asked Questions
Can node-html-pdf embed MathML directly?
PhantomJS can display MathML only to the extent its engine and fonts support it. Converting MathML with MathJax-node to SVG or well-formed HTML before capture is more predictable.
Should I use a longer renderDelay to fix intermittent equations?
No. First verify that conversion completed and every CSS/font URL loads. Use a completion signal when possible; a longer fixed delay only masks timing problems and increases job time.
What is the safest way to process user-supplied formulas?
Parse and render the formula with a restricted TeX/MathML configuration, sanitize surrounding HTML, and run PDF generation in an isolated worker with constrained local-file access.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

