Merger · No upload
Merge PDF files into one on your device
Add PDFs, drag their rows into order and download one merged file, with no page rasterized.
The list, top to bottom, is the page order Merge writes. Drag a row to move it, or use its ↑ and ↓ buttons from the keyboard.
Refused by name: protected files (this page does not open protected files), cross-reference or object streams under other filters (only Flate is read), no %PDF header or no readable page tree, past 50 files, 128 MB or 20,000 pages. Bookmarks are chained, dead internal links are dropped and counted on the row, signatures do not carry over, and tagging, the attachments panel and page labels are not carried. Takes .pdf.
How this merger works
The browser's File API reads each file you add into memory, and the page's PDF reader walks its header and page tree. The row then shows a page count and size, or the filename and the reason it was refused. Merge writes one new PDF in the order shown in the list. Every page goes in with its content, fonts and images copied byte for byte and their /Filter untouched, so nothing is decompressed, rendered or re-encoded, and a scan stays that scan. Form fields and annotations are carried too, but as dictionaries rewritten to the merged file's object numbers. The structure around them is rewritten as well, because two files' object numbers collide and a merged file needs one page tree. The header takes the highest version any source declared, floored at 1.4, the trailer gets a fresh /ID, and there is no /Info dictionary and no document metadata stream, so nothing at the document level names a producer, author or date.
To watch the network yourself, open the Network panel in a desktop browser's developer tools and merge your files. On a first visit, you may see the site's pages and code being cached for offline use; those requests do not carry your PDFs. Merging itself runs locally and needs no extra converter library. This route is first-party throughout and works offline from the first page load. Other ways to check, and what each one covers, are on the methodology page.
A file that carries an encryption dictionary is refused by name as soon as you add it, including one a viewer would open without asking you anything. A damaged file whose compressed object streams cannot be read is refused the same way, because this page cannot tell ciphertext from damage and does not rebuild either into pages. A damaged cross-reference is a different case: it is not encrypted, and the reader can rebuild it when the underlying objects are readable. The reader inflates only Flate, so a cross-reference or object stream under any other filter (LZW, ASCII85, a chain of filters, a TIFF predictor) is refused by name, since the reader has to decode these maps to find the pages. So is a file with no %PDF header in its first 1,024 bytes, no readable page tree or no pages. When colliding field names are grouped under the file's name, a script in one form that names a renamed field may stop working. Named destinations are resolved, and a page whose content or resources point at nothing is counted and reported. The caps of 50 files, 128 MB and 20,000 pages, each refused by name, exist because the whole merge sits in this tab's memory: measured in Chrome 151, thirty copies of a 4.4 MB, 126-page booklet (127 MB in, 3,780 pages) peaked at 455 MB of JavaScript heap and 849 MB of renderer memory with the finished file held for download.