Compare two versions of a document (PDF, Word .docx, or plain text) in the browser and see every changed word.
The files are processed on your computer and are not uploaded.
docdiff.app (English) · Offline version (single HTML file) · MIT license
- No upload. Files are read and compared inside the browser tab. The page's Content Security Policy (
connect-src 'none') makes the browser block every network connection from the page. - Works offline. The whole app is one HTML file. Download it, disconnect, keep working.
- Nothing stored, nothing shared. No account, no cookies, no tracking, no browser storage. Close the tab and everything is gone.
- Verifiable. The code is open (MIT), and the browser's Network tab shows no request while you compare.
This makes it suitable for confidential contracts and documents with personal data (GDPR): the documents reach no server, neither ours nor anyone else's. Details and limits are under Privacy.
Doc Diff is a small tool for one job: you have an old and a new version of a document, typically a contract or a tender, and you want to know exactly what changed. It is free, has no accounts, no ads and no tracking, and the whole app is a single HTML file you can also run offline.
It was written with German contracts in mind (§ 1, (1), 1.1 clause numbering), and the interface is in German and English.
- Open docdiff.app, or download
DocDiff.htmland open it from disk. - Choose the old version and the new version (file picker, drag and drop, or paste text). There is a built-in example if you just want to look around.
- Go through the changes: removed text is struck through in red, added text is green.
J/Kor the arrows in the top bar jump from change to change; the list on the right shows each change in short form. - Accept or reject each change (
A/R), optionally edit paragraphs of the new version, and export the result.
- Inputs: PDF with a text layer, Word
.docx,.html(text only), and UTF-8/UTF-16 text. Any combination works, e.g. PDF against DOCX. - Paragraph alignment, then word diff: paragraphs of both versions are matched first, then the words inside each matched pair are compared. Inserted and deleted paragraphs show up as such.
- Faithful output: unchanged plus removed parts always reproduce the old text exactly, unchanged plus added parts the new text. Tests enforce this.
- Less noise:
- Running headers, footers and page numbers that repeat on at least half of the pages are hidden (View › "Hide headers & footers"). If a header or footer actually differs between versions, it is shown.
- Renumbering alone (
(1)→(2),§ 4→§ 5) is shown in a muted style and not counted as a change. - Paragraphs that moved unchanged are labelled "Moved" at both positions.
- Hyphenated line breaks in PDFs are joined.
- Views: side by side or one column (default on phones), with or without the original page breaks. An overview bar between the two versions (next to the text in one column) shows where the changes are; click it to jump.
- Review: accept a change (keep the new wording) or reject it (restore the old wording of that paragraph) with the small ✓ / ✗ buttons next to the current paragraph or
A/R; both mark it as reviewed, move on to the next open change and leave a quiet ✓ or ✗ in the margin, with an undo arrow below it. The same header or footer change on several pages is one decision. The list of changes can be filtered by review status or by kind of change. Paragraphs of the new version can also be edited in place. - Export:
- Final version (the new version with your decisions and edits applied, without marks) as a Word
.docxfile — in the original format when the new version is a.docxfile (keeping styles, numbering, links, footnotes, tables and images) — or as PDF or plain text (.txt/ clipboard) - Comparison (old → new with marks) as a Word
.docxfile in which open changes are tracked changes (accept or reject them in Word or LibreOffice) and accepted changes are already applied — also in the original format when the new version is a.docxfile — or as PDF side by side or inline - HTML report (self-contained, read-only) and Markdown report, both with the review status of every change
- Final version (the new version with your decisions and edits applied, without marks) as a Word
- Saved work: you can save the current state (both documents, your edits and the review status) as a
.docdifffile and open it again later. The browser asks before you leave the page with unsaved work.
- No OCR. Scanned PDFs or images without a text layer are rejected with a message.
- No legacy
.docor.rtf. Save them as.docxor PDF first. - Formatting is not compared. Bold, fonts, tables and layout are ignored; only the text is compared. Table cells come through as text in reading order, which can be hard to follow.
- Multi-column PDF layouts are read line by line and can come out in the wrong order.
- Moves are only detected when the moved paragraph is identical. A paragraph that was moved and edited shows as one deletion and one insertion.
- Very large documents take a few seconds. See Performance.
- It is not a legal review tool. It shows differences in the text; whether they matter is up to you.
The documents never leave the browser tab. This is enforced by the browser, not only promised:
- The page sets a Content Security Policy that forbids all network connections from the page (
connect-src 'none',form-action 'none'):<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; font-src data:; img-src 'self' data: blob:; manifest-src 'self'; connect-src 'none'; media-src 'none'; object-src 'none'; child-src 'none'; worker-src blob:; frame-src 'none'; form-action 'none'; base-uri 'none';" />
- All libraries and fonts are inside the HTML file; nothing is loaded from other servers.
- Nothing is stored in the browser (no
localStorage,sessionStorage, IndexedDB or cookies). Closing or reloading the tab discards everything, unless you saved a session file yourself.
You can check this yourself: open the browser's developer tools, switch to the Network tab and compare two files. No request is made. Or use the offline file without an internet connection.
What this does not cover, to be precise:
- Opening docdiff.app is a normal page load from GitHub Pages, which sees your IP address like any web server. The page also loads its own icon and manifest from the same site. The offline file avoids this.
- Browser extensions you have installed can read any page, including this one.
- A
.docdiffsession file and every export contain the document text. Store them as carefully as the documents themselves.
The comparison runs in a background worker, so the page stays usable while it works. Rough numbers measured in Chromium on a laptop-class machine (your results will differ):
| Input | Time to result |
|---|---|
| Two versions of a 10-page contract | well under a second |
| 2,000 paragraphs per side (about 80 pages) | about 0.5 s |
| Two 1,000-page PDFs | about 4 s (mostly reading the PDFs) |
Reading PDFs is the slowest part. Very long single paragraphs (hundreds of thousands of characters) are compared with a bounded algorithm that can show a larger block as replaced instead of word by word.
| Key | Action |
|---|---|
J / K |
Next / previous open change |
A / R |
Accept / reject the current change and move on to the next open one |
E |
Edit the current paragraph |
Enter |
In the list of changes: jump to the change |
/, Ctrl+F / Cmd+F |
Find in document |
Ctrl+Z / Cmd+Z |
Undo |
Ctrl+Y, Shift+Cmd+Z |
Redo |
Esc |
Close menus, search and dialogs |
Single-key shortcuts only work while the document or the list of changes has focus, never while typing. They can be switched off in the help dialog.
The app is plain HTML, CSS and JavaScript without a framework or package manager. The sources are in src/:
src/template.html: page shell and markupsrc/styles.css: stylessrc/js/*.js: application code, concatenated in file-name order into one inline script
python3 scripts/build.py # writes site/index.html, site/en/index.html and DocDiff.html
node scripts/check.mjs # invariants and testsscripts/check.mjs verifies the Content Security Policy, the absence of external URLs and storage APIs, matching German and English strings, the search metadata of both language pages (title, canonical, hreflang, JSON-LD that matches the visible FAQ, sitemap, llms.txt), and runs the unit tests for the diff core (scripts/test-core.mjs) and the export builders (scripts/test-export.mjs). CI runs the same and also checks that the committed bundle is up to date.
Bundled libraries: PDF.js, Mammoth.js, jsdiff, and the Geist fonts. Versions and licenses are listed in THIRD_PARTY_NOTICES.md.
See CONTRIBUTING.md. Please report security issues privately as described in SECURITY.md.
MIT, see LICENSE.