Search Inside PDFs Without Uploading Them: Browser-Based RAG
Find passages in a 200-page contract or a stack of research papers by meaning, not by keyword. How pdf.js text extraction, all-MiniLM-L6-v2 embeddings, and cosine similarity search work together entirely on your device.
You have a PDF. It might be a hundred-page contract, a research paper, a technical manual, or a legal filing. You know the answer is in there somewhere, but you do not know the exact words to search for. Ctrl+F finds keywords; it does not find meaning. A search for “termination conditions” will miss a passage that says “either party may end this agreement”.
Semantic search — the “R” in RAG (Retrieval-Augmented Generation) — solves this by embedding both the document and your query into a shared meaning space, then finding the closest passages by vector distance rather than string matching. And the entire pipeline now runs in a browser tab, on your device, with no upload.
The pipeline: extract, chunk, embed, search
Building a semantic search index over a document is a four-stage pipeline. Each stage has a specific failure mode, and knowing which stage failed turns “it returned nothing” into a two-minute fix.
Stage 1: extraction — the step that decides everything
The document is parsed page by page using pdf.js, the same open-source renderer Firefox uses to display PDFs. It reads the PDF’s text layer: the actual character data embedded in the file, not a rendering of the page.
Here is the failure mode that accounts for most “it returned nothing” reports: a scanned PDF has no text layer. To pdf.js, it is a stack of pictures. There is nothing to extract, so extraction returns nothing, so the index is empty, so every search returns nothing. The model is not broken and the file is not corrupt — it is an image.
The fix is OCR first: run the pages through an OCR tool to produce text, then search that text. Word processors, LaTeX, and exported documents almost always embed a real text layer; scanners almost never do. If your PDF came out of a scanner, a fax, or a phone camera, start with OCR.
Stage 2: chunking — 150 words with 30-word overlap
Once the text is extracted, it is split into chunks of 150 words, with a 30-word overlap between consecutive chunks. Both numbers matter.
The chunk size of 150 words is chosen to be small enough that each chunk covers roughly one idea or paragraph, but large enough that the embedding model has enough context to produce a meaningful vector. A chunk that is too small (a single sentence) produces an embedding that lacks context; a chunk that is too large (a full page) produces an embedding that blurs multiple ideas together, so a search for any one of those ideas returns a weak match.
The 30-word overlap prevents a relevant passage from being split across two chunks. If a key sentence straddles the boundary between chunk N and chunk N+1, the overlap means it appears in full in at least one of them. Without overlap, a passage that happens to fall at a chunk boundary would be represented by two partial fragments, neither of which is coherent enough to match a query well.
Each chunk also remembers its page number, so search results can point you to the exact page in the original document.
Stage 3: embedding — all-MiniLM-L6-v2
Each chunk is passed through all-MiniLM-L6-v2, a compact sentence embedding model that produces a 384-dimensional vector per chunk. The model runs through Transformers.js on WebGPU where available, with a WebAssembly fallback on older browsers.
The embedding process has two key parameters:
- Pooling: mean. The model produces a token-level representation for every word in the chunk. Mean pooling averages those into a single vector that represents the chunk as a whole.
- Normalize: true. The resulting vector is length-normalized — scaled so its Euclidean length is 1. This is not cosmetic: it makes the search step dramatically faster.
Chunks are embedded in batches of 16 at a time, which is the sweet spot for the WebGPU/WASM execution backend: large enough to amortize the per-batch overhead, small enough to fit in the device’s memory without triggering garbage collection pauses.
The model is small — roughly 25–90 MB depending on the quantization path — and downloads once, then is cached by the browser. After the first document, indexing subsequent PDFs is fast: only the extraction and embedding work needs to run.
Stage 4: search — dot products on normalized vectors
When you type a query, it is embedded with the same model and the same parameters. The result is a 384-dimensional query vector. The search then computes the dot product between the query vector and every chunk vector, sorts by score, and returns the top 5 results with their page numbers and similarity scores.
Here is why the normalize: true parameter from Stage 3 matters. Cosine similarity — the standard measure of how “close” two embeddings are — is defined as the dot product divided by the product of the two vectors’ lengths. But if both vectors are already length-normalized (length = 1), the denominator is 1, and cosine similarity equals the dot product. That means the search step is a simple multiply-and-add for each pair, with no division — fast enough to search thousands of chunks in milliseconds, entirely in JavaScript, with no database or server.
The in-memory vector store is just two arrays: the chunk texts and their embeddings. No external database, no index file, no server-side storage. When you close the tab, the index is gone — which is exactly what you want for confidential documents.
Why semantic search beats keyword search
Consider a contract with this clause: “Either party may terminate this agreement upon 30 days’ written notice.”
- A keyword search for “termination” would miss it — the word used is “terminate”, not “termination”.
- A keyword search for “end” would miss it — the word is “terminate”, not “end”.
- A semantic search for “how can this contract be ended?” would find it — because the embedding of the query and the embedding of the clause are close in meaning space, even though they share no words.
This is the advantage of semantic search: it matches intent, not strings. For documents where you know the content exists but not the exact wording — contracts, research papers, manuals, legal filings — it finds passages that keyword search simply cannot.
What it cannot do
- Scanned PDFs need OCR first. If the PDF has no text layer, the tool tells you plainly rather than pretending to search empty content. Run it through OCR, then search the resulting text.
- Tables and figures are largely invisible. Text extraction captures prose. The meaning locked inside a chart, a table, or a diagram is not recovered unless the table is encoded as text in the PDF structure.
- It is search, not question answering. The tool returns the passages most semantically similar to your query. It does not synthesize an answer from those passages — for that, you need a language model, which is what the PDF summarizer does. The two tools are complementary: search to find the right passage, then ask a model to answer from it.
- Very large documents scale with RAM. The embeddings live in memory. A 500-page document produces thousands of 384-dimensional float vectors, which is manageable; a 5000-page document may strain a low-RAM device. There is no hard file-size cap, but there is a practical memory ceiling.
Recipes
Contract review
Load the contract and search for concepts, not terms: How can this agreement be ended? Who is liable for data loss? What are the payment deadlines? The results point you to the exact pages, and the similarity scores tell you which passages are most relevant. Read those pages; the search has done the finding for you.
Research literature triage
Load a batch of papers one at a time and search each for the questions that matter to your work. A paper that returns a strong match on sample size limitations is worth reading in full; one that returns nothing on your specific question may not be, even if the title looked promising.
Finding the answer in a manual
“How do I reset the admin password?” — without knowing whether the manual calls it “reset”, “change”, “restore”, or “recover”. Semantic search finds the passage regardless of the word choice.
Privacy, and the thing to check
Documents people need to search are disproportionately documents that must not be uploaded: contracts under negotiation, medical records, personnel files, unpublished research, legal filings, anything under an NDA. Cloud “chat with your PDF” services receive the full document, process it on their servers, and retain at least an index of its content.
Running locally, the PDF is parsed in the browser’s memory, the embeddings are computed on your hardware, and the index lives only for as long as the tab is open. The model downloads once from the open-source model hub; after that, indexing and search are entirely local. Close the tab and the index is gone — no copy of your document exists anywhere except on your own machine.
You can verify this in DevTools: open the Network tab, load a PDF, and confirm that after the one-time model download, no request containing your document’s text appears. The only traffic is the model fetch — everything else stays on your device.
Try it with the document RAG search — start with a document you have already read, so you can judge the search results against knowledge you already have. Ask a question whose answer you know the location of, and see whether the tool finds the right passage. That is the fastest way to calibrate how much to trust the results.
Try the tools
Everything described here runs for free in your browser — no sign-up, no uploads. Explore the full matrix of on-device AI tools from the homepage, or read the end-to-end workflows.
Back to the matrix