A lightweight PDF viewer and annotator with synced side-by-side view. Built for QC, translation checks, and version comparison. You can use it on your browser or download it.
- Instant web access.
- Private and local.
- Open source and ad free.
- Side by side: Compare two PDFs in the same viewer
- Synced view: Simultaneous scroll, zoom, and page navigation
- Search: Find and navigate to any string
- Bookmarks sidebar: Browse and create custom bookmarks and ToC outline
- Annotations sidebar: View all sticky notes, comments, and highlights
- View modes: Switch between page-by-page rendering or continuous scroll
- Session recovery: Comments get autosaved and restored when you come back
- Accessibility: Show alt text on hover, with an optional visual indicator
- Automation friendly: Load remote and local PDFs on the web version like this:
?a=doc1.pdf&b=doc2.pdfor use command line arguments with the desktop app
- Sticky notes: Double click to add comments anywhere on the page
- Text annotations: Select text to highlight or add comments
- Custom author: Change your name so your comments are easily identifiable
- Export: Download annotated PDFs with your changes
Twice PDF is available as a native Windows application powered by Tauri.
- CLI Support: Open PDFs via command line:
Twice-PDF.exe doc1.pdf doc2.pdf - Native I/O: Direct file access including "save to source" functionality with configurable naming patterns
- Fully offline: No online capabilities necessary to view and save PDFs
- Minimal footprint: Tauri uses the OS native web viewer, avoiding Electron-like embedding for a 95% smaller bundle size, 60-90% less memory usage, and automatic engine updates. The full Windows app is under 12Β MB!
| Lightweight | ~150KB gzipped. Minimal dependencies. |
| Flexible | URL and CLI parameters, env configs, extensible architecture. |
| Bespoke | Modern, sleek UI. Flat design. Easily themed. |
| Scalable | Lazy rendering with IntersectionObserver. Handles large documents. |
| Robust | Multi-proxy CORS fallback, SSRF protection, DNS pinning. |
| Secure | Private IP filtering, path traversal protection, feature flags. |
| Modular | 25+ focused modules: SearchPanel, AnnotationOverlay, useAnnotations, pdfExport, etc. |
- React 19 + Vite 7: Modern stack with fast HMR and optimized builds
- PDF.js Bundled Locally: No CDN callsβfaster, private, offline-ready
- Smooth Zoom Engine: CSS transform for instant feedback + debounced re-render
- RAF-Throttled Sync:
requestAnimationFramescroll handling prevents flooding - Memory Management: Off-screen page unloading
- Canvas Size Guard: Prevents browser crashes on oversized pages
- Error Boundary: Graceful error handling with retry UI
.env in the app directory:
| Variable | Default | Description |
|---|---|---|
VITE_ENABLE_REMOTE_PDFS |
true |
Disable to block external URL loading |
VITE_ENABLE_LOCAL_BRIDGE |
true |
Disable to block local file access via dev bridge |
- SSRF Protection: IP filtering, DNS pinning, redirect validation
- Private IP Blocking: Rejects 127.x, 10.x, 172.16-31.x, 192.168.x, 169.254.x
- Path Traversal Protection: Local bridge restricted to
public/samples - Network Exposure Warning: Console alert if dev server exposed to LAN
- Auto-generate comparison views for QC processes
- Add custom action buttons (e.g., database operations)
- Autosave with preset naming patterns
- URL parameter API for programmatic loading
Remote PDFs use a fallback chain of public proxies:
- Direct fetch β 2. AllOrigins β 3. CORS.lol β 4. corsproxy.io
When direct fetch fails due to a CORS error, "Load from URL" will pass the PDF through third-party proxies. For sensitive documents, download and upload manually.
- Node.js (v16+)
git clone https://github.com/PlusKits/Twice-PDF.git
cd Twice-PDF/app
npm install
npm run devOpen http://localhost:5173 in your browser.
npm run tauri:dev # Debug mode
npm run tauri:build # Release buildOr download our GitHub release.
http://localhost:5173/?a=file1.pdf&b=file2.pdf
NOTE: The Vite local bridge only serves files from
app/public/samplesfor security. The base path can be configured.
Deploy as a static site on GitHub Pages, Vercel, or Netlify. Deploy as a standalone app via our GitHub releases.
NOTE: Local path functionality is only available through the Vite dev server and desktop app due to browser security restrictions.
GNU Affero General Public License v3.0 (AGPLv3)
- β Free to use for personal or internal purposes
- β Modify and distribute with source code disclosure
β οΈ SaaS usage requires source code release under the same license
Want different terms?
If you are an open source developer, I will gladly help. Even if you don't need a license, if you are working on a PDF viewer I would love to chat! If you are a business, we can talk too.
Contact: pluskittydev [at] gmail [dot] com
See LICENSE for full details.
See CHANGELOG.md for complete version history.
Latest Updates (January 2026):
- Desktop Support: Native Windows app with Tauri (CLI args, native file access)
- Accessibility: Alt text extraction, visualization, and fallback heuristics
- Architecture: Major refactor into 25+ modular components
- Panels: New Bookmarks and Annotations sidebars
Add comments and highlights
View existing comments
Search and explore





