# embedpdf: a PDFium fork behind tree-shakable plugins, with a v3 line still in pre-release

> A framework-agnostic PDF viewer for JavaScript projects, rendering through EmbedPDF Runtime, a fork of PDFium, with plugins you can tree-shake. Two things complicate adoption: the stable line lives on the v2 branch rather than on the main branch, and the self-hostable server is Fair Source rather than Apache-2.0.

**embedpdf/embed-pdf-viewer** — A PDF viewer that seamlessly integrates with any JavaScript project

- Repository: https://github.com/embedpdf/embed-pdf-viewer
- Website: https://www.embedpdf.com
- Stars: 4,527 · Forks: 319
- Language: TypeScript
- License: NOASSERTION
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/embedpdf-embed-pdf-viewer

## The stable build lives on the v2 branch, not on main

The first thing the documentation puts in front of you is a warning, not a feature list. EmbedPDF v3 is under active development and is not yet recommended for production use, and for the current stable release you are pointed at the v2 branch. That single line reshapes how you read the release list. The two most recent tags are v3.0.0-next.14 from 2026-09-20 and v3.0.0-next.13 from 2026-09-16, both pre-release versions, while v2.15.1 from 2026-09-16 is the one carrying a plain version number.

The practical consequence is that the default branch is where the churn is. If you clone main, add the dependency at whatever version resolves, and ship, you have picked the line the project itself steers you away from. Pinning to v2.15.1 or to the v2 branch is the conservative move, at the cost of not getting v3 work. What you cannot do is treat the next.* tags as ordinary releases, because a pre-release tag is a moving target by definition.

## The renderer is a PDFium fork, so engine updates arrive through the fork

EmbedPDF does not build PDFium directly. The engine is EmbedPDF Runtime, described as a fork of PDFium, which is itself licensed under the Apache License 2.0. The project adds a note that PDFium is a Google project and that EmbedPDF is not affiliated with or endorsed by Google.

That fork relationship has a maintenance shape. Upstream PDFium moves on its own schedule, and changes reach you only when someone lands them in the fork, which means your engine version is a function of EmbedPDF's release cadence rather than PDFium's. The repository layout supports that reading: there is a patches/ directory at the root and a .gitmodules file, plus a dedicated workspace script named verify:engine-runtime-packages whose entire job is to check that the engine runtime packages line up. If you are auditing a build for supply chain reasons, that script and that directory are where the engine story lives, and neither is something a plain dependency install surfaces to you.

## Plugins are tree-shakable, and a boundary check runs in the repository

The advertised architecture is pluggable and tree-shakable, which is the claim that matters for a viewer embedded in someone else's bundle. You import the plugins you use and the rest is supposed to fall out at build time. Nothing in the viewer is mandatory beyond the core, so the cost of adding annotation support is not the whole library.

The repository enforces that rather than merely claiming it. A root script named check:plugin-boundaries runs node tooling/build/src/check-plugin-boundaries.mjs, and there is a separate tooling/ directory to house it. Boundary checks in a monorepo exist because plugin packages otherwise reach sideways into each other's internals and quietly become impossible to split. If you fork or vendor this, that script is the thing to keep. The rest of the root scripts follow the same shape, delegating to turbo across packages/: build runs turbo run build, typecheck runs turbo run typecheck, test runs turbo run test, and dev runs turbo run dev --parallel.

Here is what the repository itself runs, which is also the closest thing to a first-use recipe it ships:

```json
    "dev": "turbo run dev --parallel",
    "build": "turbo run build",
    "typecheck": "turbo run typecheck",
    "test": "turbo run test",
```

The repository publishes no consumer install command. Installation guides, API reference and examples live on the documentation site, and there is a live demo you can open a PDF in.

## Redaction removes the content instead of painting over it

Two of the five listed features are the ones that separate this from a canvas wrapper. The first is true redaction, and the project's own gloss is that the content is actually removed. That distinction is the whole point: a black rectangle drawn over a page is a visual edit that leaves the underlying text selectable, searchable and copyable, which is the opposite of what a redaction is supposed to do.

The second is annotations, covering highlight, sticky notes, free text and ink. Four annotation kinds across a scrollable, virtualized page view is a meaningful surface, and it is also where the maturity question sits. The examples directory contains a directory named annotation-spike, which is the name you would give to exploratory work rather than to a finished feature, and the v3 line is the one carrying the annotation work forward.

The rest of the feature list is the expected viewer core: search, text selection, zoom, rotation, and smooth virtualized scrolling. Virtualized scrolling matters more than it sounds in an embedded viewer, because it is what keeps a several-hundred-page document from mounting every page into your component tree.

## The self-hostable server is Fair Source, and reading its source is not permission to run it

The licensing is not uniform, and the exception is the part worth reading twice. Everything in the repository is under the Apache License 2.0 with one exception: the self-hostable CloudPDF server at cloudpdf/server is Fair Source under the Fair Core License, FCL-1.0-ALv2.

The terms are specific. Its source may be inspected, copied and modified for purposes the FCL permits. Running or self-hosting it is a different question: while a release remains under the FCL, that requires a valid CloudPDF license, which is a license key for a connected deployment or a signed certificate for an air-gapped one. You may not move, change, disable or circumvent the license-key functionality, you may not enable protected functionality without a valid license, and you may not remove protected functionality. Competing Uses as the FCL defines them are prohibited. Each release automatically becomes Apache-2.0 two years after publication, and LICENSING.md holds the full map, including website content.

So the viewer library and the server have genuinely different terms. If your requirement is self-hosting, that is a purchase decision, not an open source one.

## The root package.json is workspace scaffolding, not the artifact you install

Read the manifest before you read the badges, because the root one will mislead you. It declares the name embedpdf, sets private to true, pins the version at 0.0.0, lists the license as MIT, and names pnpm@10.34.0 as the package manager. None of those describe the package a consumer installs. The 0.0.0 version exists because this is a workspace root that is never published, and the MIT field sits there next to an Apache-2.0 README because the field describes the manifest, not the licensing of every package beneath it.

The rest of the root tells you what kind of repository this is. There is pnpm-workspace.yaml and pnpm-lock.yaml, turbo.json for task orchestration, a .changeset/ directory for release notes, a .husky/ directory for git hooks, and separate api/, types/, docs/, fern/, website/ and scripts/ directories. That is a monorepo with generated documentation and a generated SDK pipeline, not a single-library repository with a flat build.

If you are evaluating the project, read the per-package manifests under packages/ instead. The root one will tell you about the build system and nothing about the API you would consume.

## The examples directory covers React and Angular, and names no Vue, Svelte or Preact example

The README lists React, Vue, Svelte, Preact and vanilla JavaScript as supported build targets. The examples directory contains seven entries: angular/, annotation-spike/, cloud-dashboard/, engine-runtime-demo/, react/, snippet-react/ and viewer-react/.

Read those two lists side by side and the gap is obvious. There is an Angular example and three React ones, plus directories for annotation work, the cloud dashboard and the engine runtime. There is no vue/, svelte/ or preact/ directory. That does not mean those frameworks are unsupported, since the README says so plainly and the viewer is described as framework-agnostic. It means the copy-and-adapt starting point you get on GitHub covers a different set of frameworks than the compatibility sentence advertises.

For Vue, Svelte or Preact the documentation site is the source. The snippet site at snippet.embedpdf.com is the other place to look, and viewer-react/ plus snippet-react/ in the repository are the two directories that most closely correspond to it. Plan for a day of reading the API reference rather than a half hour of copying an example.

## Version bumps run through changesets and a generated TypeScript SDK

The release pipeline is visible in the root scripts, and it explains why v3 changes can touch files you did not write. The ci:version script runs changeset version, then emits an OpenAPI contract for the CloudPDF package, then calls cloudpdf:sdk:generate, which runs node fern/scripts/generate-sdks.mjs with the flags --only typescript --force, then continues into website metadata and package steps. The api:sync script follows the same path, and it ends with an api:check pass.

What that means concretely is that part of the TypeScript surface in v3 is generated from an API description rather than hand-written, and that a version bump regenerates it. There is a verify:consume script that runs against tooling-consume fixtures, which is the shape you would expect from a repository that wants to catch a broken publish before users do.

For an adopter this cuts two ways. Generated SDK code means the API can change shape between pre-release tags without a hand-written deprecation note, which is another reason to pin. It also means a broken release is caught by the project's own checks rather than by your users, provided you consume the published packages rather than pointing at a pre-release tag on the main branch.

## Conclusion

EmbedPDF fits a team that already renders PDFs inside a JavaScript app, wants annotation and real redaction rather than a bare canvas, and can live with a pinned dependency. It does not fit a project that needs the self-hostable CloudPDF server without buying a license, and it does not fit anyone who needs Vue, Svelte or Preact examples to copy from, because the examples directory covers none of those three. Before you commit, check four things. Which branch you are on, since v3 is flagged as not yet recommended for production use and the stable release sits on v2. Whether you need the server component at all, because running it under the Fair Core License requires a valid license key or a signed certificate. Which engine build you are consuming, given that the renderer is a fork rather than upstream PDFium. And how you will handle the next.* tags, which are pre-release versions and will move.

## FAQ

### How can I embed a PDF viewer in HTML with embedpdf?

EmbedPDF is a framework-agnostic PDF viewer meant to drop into a JavaScript project, with support claimed for React, Vue, Svelte, Preact and vanilla JS. The repository publishes no install command itself: installation guides, the API reference and examples are on the documentation site at embedpdf.com, with a live demo at app.embedpdf.com and a snippet site at snippet.embedpdf.com.

### Which branch of embed-pdf-viewer should I use for production?

The project states that EmbedPDF v3 is under active development and is not yet recommended for production use, and points you at the v2 branch for the current stable release. The recent tags include v3.0.0-next.14 and v3.0.0-next.13 as pre-releases alongside v2.15.1, so pinning to a v2 version is the conservative choice.

### Can I self-host the CloudPDF server for free?

No. The self-hostable CloudPDF server is Fair Source under the Fair Core License FCL-1.0-ALv2 rather than Apache-2.0, and while a release remains under that license, running or self-hosting it requires a valid CloudPDF license, either a license key for a connected deployment or a signed certificate for an air-gapped one. Each release automatically becomes Apache-2.0 two years after publication.

### Does embedpdf ship examples for Vue and Svelte?

The examples directory holds angular/, annotation-spike/, cloud-dashboard/, engine-runtime-demo/, react/, snippet-react/ and viewer-react/, with no vue/, svelte/ or preact/ entry. The README still names Vue, Svelte and Preact as supported targets, so for those frameworks the documentation site is where you start rather than a repository example.

## Sources

- [embedpdf/embed-pdf-viewer on GitHub](https://github.com/embedpdf/embed-pdf-viewer)
- [Issues](https://github.com/embedpdf/embed-pdf-viewer/issues)
- [Project website](https://www.embedpdf.com)
- [README](https://github.com/embedpdf/embed-pdf-viewer/blob/main/README.md)
- [Releases](https://github.com/embedpdf/embed-pdf-viewer/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/embedpdf-embed-pdf-viewer
