You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

mupdf-webviewer

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mupdf-webviewer

The web viewer SDK using mupdf.js

0.7.0
latest
npmnpm
Version published
Maintainers
1
Created
Source

MuPDF WebViewer

A customizable PDF Viewer Component for the Web.

MuPDF WebViewer is an easy to use drop-in UI component for web pages which allows for in-context PDF viewing, data extraction, customization and more.

Installation

npm install mupdf-webviewer

Get Started with Examples

  • MuPDF WebViewer Vanilla JS Sample
  • MuPDF WebViewer React sample
  • MuPDF WebViewer Angular sample

Documentation

Usage

Note: A license key is required to use MuPDF WebViewer. Please visit MuPDF WebViewer to obtain your license.

License Types:

  • Free License (v0.6.0+): Viewing-only functionality with feature restrictions. Available at webviewer.mupdf.com
  • Trial/Commercial License: Full functionality including editing, annotations, and all features

Important: Free license keys introduced in v0.6.0 will not work with versions below 0.6.0 and will show validation failures. For older versions, you need a trial or commercial license key.

Copy the library assets

cp -r node_modules/mupdf-webviewer/lib/* {YOUR_LIBRARY_PATH}/

If you want to use the library in a web application, you need to copy the library assets to your web application.

Create DOM Element for Viewer

<div id="viewer"></div>

You need to prepare DOM element with id viewer in your html. Initialization function must be called after the DOM element is created.

Initialize Viewer

import { initMuPDFWebViewer } from 'mupdf-webviewer'

initMuPDFWebViewer('#viewer', 'sample.pdf', {
  libraryPath: 'YOUR_LIBRARY_PATH',
  licenseKey: 'YOUR_LICENSE_KEY',
})
  .then(mupdf => {
    /* API */
    mupdf.toast.show({ type: 'success', content: 'Opened' });
  })
  .catch(err => {
    /* Error handling */
  });

TypeScript Definition

export function initMuPDFWebViewer(
  selector: string,
  docURL: string,
  options?: {
    licenseKey: string; 
    libraryPath?: string;
    filename?: string;
    standalone?: boolean;
    withoutLoader?: boolean;
  }
): Promise<MuPDFWebViewer>;

Reference Variables

MuPDF WebViewer provides reference variables for API calls.

Example

mupdf.refs.icon.SHARE

See the references page for full details.

Saving Documents

MuPDF WebViewer provides two primary methods for saving documents:

1. Save as Binary

mupdf.document.export()
  .then(buffer => {
    const blob = new Blob([ buffer ], { type: 'application/pdf' });
    const objUrl = URL.createObjectURL(blob);
    window.open(objUrl);
    /* or anything you want */
});

2. Save as File (Download)

mupdf.document.download();

3. Saving Annotations Separately

For sharing annotations without the full document:

// Get annotations only
async function getAnnotationsAsJSON() {
  const annotations = await mupdf.annotation.get();
  return JSON.stringify(annotations);
}

// Save annotations to local storage
async function saveAnnotationsLocally() {
  const annotations = await mupdf.annotation.get();
  localStorage.setItem('pdfAnnotations', JSON.stringify(annotations));
  mupdf.toast.show({
    type: 'success',
    content: 'Annotations saved locally'
  });
}

// Load annotations from local storage
async function loadLocalAnnotations() {
  const savedAnnotations = JSON.parse(localStorage.getItem('pdfAnnotations') ?? '{ "annotations": [] }');
  if (savedAnnotations?.annotations.length > 0) {
    await mupdf.annotation.add(savedAnnotations);
    mupdf.toast.show({
      type: 'notification',
      content: 'Annotations loaded'
    });
  }
}

See the annotations guide for more.

Customizing the Viewer

1. Display/Hide UI

You can display/hide the UI of the viewer using viewer.setViewVisibility() function. For example, if you want to hide the toolbar, you can do the following:

mupdf.viewer.setViewVisibility({
  view: mupdf.refs.visibility.view.TOOLBAR,
  visibility: false,
});

2. Add Buttons to Toolbar

You can add buttons to the toolbar using viewer.addButton() function. For example, if you want to add a button to the toolbar to enter fullscreen, you can do the following:

mupdf.viewer.addButton({
  buttons: [
    {
      position: 'TOOLBAR.LEFT_SECTION.FIRST',
      icon: mupdf.refs.icon.ENTER_FULLSCREEN,
      label: 'Enter fullscreen',
      onclick: () => {
        document.body.requestFullscreen();
      },
    },
  ],
});

3. Add Context Menu

You can add context menu to the viewer using viewer.addContextMenu() function. For example, if you want to add a context menu to the viewer to rotate the page clockwise, you can do the following:

mupdf.viewer.addContextMenu({
  menus: [
    {
      type: 'MENU',
      position: 'FIRST',
      icon: mupdf.refs.icon.ROTATE_CLOCKWISE,
      label: 'Rotate Clockwise',
      onclick: () => {
        mupdf.viewer.rotateClockwise();
      },
    },
  ],
});

4. Define Document Panel

You can define document panel using viewer.setDocumentPanel() function. For example, if you want to define document panel to show the bookmark panel, you can do the following:

mupdf.viewer.defineDocumentPanel({
  items: [
    {
      label: 'TOC',
      icon: mupdf.refs.icon.BOOKMARK,
      onclick: () => {
        mupdf.viewer.togglePanel({
          type: mupdf.refs.panel.open.BOOKMARK,
        });
      },
    },
  ],
});

5. Define Annotation Selection Menu

You can define annotation selection menu using viewer.defineAnnotSelectMenu() function. For example, if you want to define annotation selection menu when selecting a highlight annotation, you can do the following:

mupdf.viewer.defineAnnotSelectMenu({
  html: `
    <h1>This is a highlight</h1>
  `,
  tool: mupdf.refs.annotation.tool.HIGHLIGHT,
});

Event System

TypeScript Definition

public addEventListener<T extends keyof EventDataMap>(
  type: T, 
  callback: (event: { type: T; data: EventDataMap[T] }) => void
): void;

Event Types

event: {
  type: {
    SCALE_CHANGE: EventType.SCALE_CHANGE,
    ANNOTATION_TOOL_CHANGE: EventType.ANNOTATION_TOOL_CHANGE,
    CURRENT_PAGE_INDEX_CHANGE: EventType.CURRENT_PAGE_INDEX_CHANGE,
    DOCUMENT_DOWNLOAD: EventType.DOCUMENT_DOWNLOAD,
    SIDE_VIEW_OPEN: EventType.SIDE_VIEW_OPEN,
    SIDE_VIEW_CLOSE: EventType.SIDE_VIEW_CLOSE,
    KEYDOWN: EventType.KEYDOWN,
    KEYUP: EventType.KEYUP,
    SCROLL_POSITION_CHANGE: EventType.SCROLL_POSITION_CHANGE,
    CURRENT_READING_PAGE_CHANGE: EventType.CURRENT_READING_PAGE_CHANGE,
    MOUSEDOWN: EventType.MOUSEDOWN,
    MOUSEUP: EventType.MOUSEUP,
    POINTERDOWN: EventType.POINTERDOWN,
    POINTERUP: EventType.POINTERUP,
    ANNOTATION_CREATE: EventType.ANNOTATION_CREATE,
    ANNOTATION_MODIFY: EventType.ANNOTATION_MODIFY,
    ANNOTATION_REMOVE: EventType.ANNOTATION_REMOVE,
    REDACTION_CREATE: EventType.REDACTION_CREATE,
    REDACTION_MODIFY: EventType.REDACTION_MODIFY,
    REDACTION_REMOVE: EventType.REDACTION_REMOVE,
    CUSTOM_CONTEXT_MENU_EXECUTE: EventType.CUSTOM_CONTEXT_MENU_EXECUTE,
    TEXT_SEARCH_START: EventType.TEXT_SEARCH_START,
    ACTION_HISTORY_CHANGE: EventType.ACTION_HISTORY_CHANGE,
    ANNOTATION_SELECTION_CHANGE: EventType.ANNOTATION_SELECTION_CHANGE,
    TEXT_SELECTION_CHANGE: EventType.TEXT_SELECTION_CHANGE,
  }
}
mupdf.addEventListener(mupdf.refs.event.type.KEYDOWN, (event) => {
  if (event.data.event.ctrlKey && event.data.event.key === 's') {
    mupdf.document.download();
  }
});

See the event listening guide for more.

API

Document API

document.download(config?: { fileName?: string; includeAnnotations?: boolean })

Downloads the PDF file.

  • fileName (optional): Name of the file to download
  • includeAnnotations (optional; default: true): Whether to include annotations

document.getPages(config?: { pageRange?: string })

Gets PDF page information.

  • pageRange (optional; default: 'all'): Page index range (e.g., "1-5, 7, 9-12", "all")

Returns:

{
  pages: {
    pageIndex: number;
    read: boolean;
    isVisible: boolean;
    bbox: {
      width: number;
      height: number;
      x: number;
      y: number;
    }
  }[]
}

document.getPageCount()

Gets the total number of pages in the PDF.

Returns:

{ pageCount: number }

document.open(config: { url: string; filename: string })

Opens a PDF document.

document.close()

Closes the currently opened PDF document.

document.print(config: { pageRange: string })

Prints the PDF.

  • pageRange (required): Page index range to print (e.g., "1-5, 7, 9-12", "all")

Returns:

{ status: 'PRINTED' | 'CANCELLED' }

document.rotatePage(config: { pageRange: string; degree: 0 | 90 | 180 | 270 | 360 })

Rotates pages.

  • pageRange (required): Page index range to rotate (e.g., "1-5, 7, 9-12", "all")
  • degree (required): Rotation angle (0, 90, 180, 270, 360)

document.getText(config?: { pageRange?: string })

Extracts text from the PDF.

  • pageRange (optional; default: 'all'): Page index range to extract text from (e.g., "1-5, 7, 9-12", "all")

Returns:

{
  pageIndex: number;
  text: string;
}[]

document.export(config?: { includeAnnotations?: boolean })

Exports the PDF.

  • includeAnnotations (optional; default: true): Whether to include annotations

Returns: PDF data in Uint8Array format

Viewer API

viewer.toggleDialog(config: { dialogType: refs.dialog.type; visibility?: boolean })

Shows or hides a dialog.

  • dialogType (required): Dialog type (refs.dialog.type: 'PRINT' | 'SEARCH_TOOL')
  • visibility (optional): Whether to show or hide

viewer.getScale()

Gets the current zoom scale.

Returns:

{ scale: number }

viewer.setScale(config: { scale: number })

Sets the zoom scale.

  • scale (required): Zoom scale value

viewer.zoomIn(config?: { increment: number })

Zooms in.

  • increment (required): Zoom increment value

viewer.zoomOut(config?: { decrement: number })

Zooms out.

  • decrement (required): Zoom decrement value

viewer.getCurrentPageIndex()

Gets the current page index.

Returns:

{ currentPageIndex: number }

viewer.getRotation()

Gets the current rotation angle.

Returns:

{ degree: 0 | 90 | 180 | 270 }

viewer.setRotation(config: { degree: 0 | 90 | 180 | 270 | 360 })

Sets the rotation angle.

  • degree (required): Rotation angle (0, 90, 180, 270, 360)

viewer.rotateClockwise()

Rotates clockwise.

viewer.rotateCounterClockwise()

Rotates counter-clockwise.

viewer.setViewMode(config: { viewMode: refs.viewMode; })

Sets the view mode.

  • viewMode (required): View mode (refs.viewMode: 'SINGLE' | 'SINGLE_SCROLL' | 'DOUBLE' | 'DOUBLE_SCROLL')

viewer.fitTo(config: { to: refs.fit.to })

Sets page fitting.

  • to (required): Fit mode (refs.fit.to: 'WIDTH' | 'HEIGHT' | 'PAGE' | 'READ')

viewer.scrollTo(config: { type: refs.scroll.type; value: number; centerPoint?: { x: number; y: number }; select?: boolean; name?: string; pageIndex?: number })

Scrolls to a specific position.

{
  type: 'PAGE';
  value: number;
  centerPoint?: { x: number; y: number };
}
| {
  type: 'ANNOTATION';
  value: number;
  select?: boolean;
}
| {
  type: 'ANNOTATION';
  name: string;
  pageIndex: number;
  select?: boolean;
}
  • type (required): Scroll type (refs.scroll.type: 'PAGE' | 'ANNOTATION')
  • value (required): Scroll value ('PAGE': Page index, 'ANNOTATION': Annotation oid)
  • 'PAGE': centerPoint (optional): Center point of the page
  • 'ANNOTATION': select (optional): Whether to select the annotation
  • 'ANNOTATION': name (optional): Annotation name
  • 'ANNOTATION': pageIndex (optional): Page index

viewer.scrollToNextPage()

Scrolls to the next page.

viewer.scrollToPreviousPage()

Scrolls to the previous page.

viewer.selectAnnotationTool(config: AnnotationTool | AnnotationStampTool)

Selects an annotation tool.

  • tool (required): Annotation tool (refs.annotation.tool: 'HIGHLIGHT' | 'STRIKE' | 'UNDERLINE' | ...)

viewer.toggleAnnotationTool(config: AnnotationTool | AnnotationStampTool)

Toggles an annotation tool.

  • tool (required): Annotation tool (refs.annotation.tool: 'HIGHLIGHT' | 'STRIKE' | 'UNDERLINE' | ...)

viewer.openSideView(config: { type: refs.panel.open })

Opens a side view.

  • type (required): Side view type (refs.panel.open: 'THUMBNAIL' | 'BOOKMARK' | 'ANNOTATION' | 'REDACTION' | 'ANNOTATION_PROPERTY' | 'TEXT_SEARCH')

viewer.closeSideView(config: { type: refs.panel.close })

Closes a side view.

  • type (required): Side view type (refs.panel.close: 'LEFT' | 'RIGHT')

viewer.togglePanel(config: { type: refs.panel.open })

Toggles a panel.

  • type (required): Panel type (refs.panel.open: 'THUMBNAIL' | 'BOOKMARK' | 'ANNOTATION' | 'REDACTION' | 'REDACTION_SEARCHING' | 'ANNOTATION_PROPERTY' | 'TEXT_SEARCH')

viewer.highlight(config: { rects: Array<{ color: string; pageIndex: number; opacity?: number; rect: { top: number; left: number; bottom: number; right: number } }> })

viewer.highlight(config: { keywords: Array<{ keyword: string; color: string; opacity?: number; caseSensitive?: boolean; useRegex?: boolean }> })

Highlights text.

  • rects (required): Array of highlight area information
    • color (required): Highlight color
    • pageIndex (required): Page index
    • opacity (optional): Highlight opacity
    • rect (required): Highlight area (top > bottom, right > left)
  • keywords (required): Array of keyword information
    • keyword (required): Keyword to highlight
    • color (required): Highlight color
    • opacity (optional; default: 0.5): Highlight opacity
    • caseSensitive (optional; default: true): Whether to be case sensitive
    • useRegex (optional; default: false): Whether to use regular expressions

Example:

mupdf.viewer.highlight({ rects: [ { color: '#FF0000', pageIndex: 0, rect: { left: 100, top: 200, right: 200, bottom: 100 } } ] });
mupdf.viewer.highlight({ keywords: [ { keyword: 'keyword', color: '#FF0000' } ] });

Returns:

{
  rects: { id: number }[]
}

viewer.unhighlight(config: { rects: { id: number }[] })

Removes highlights.

  • rects (required): Array of highlight areas to remove

viewer.searchText(config: { keyword: string; caseSensitive?: boolean; useRegex?: boolean; emitEvent?: boolean })

Searches for text in the viewer right panel.

  • keyword (required): Search keyword
  • caseSensitive (optional): Whether to be case sensitive
  • useRegex (optional): Whether to use regular expressions
  • emitEvent (optional): Whether to emit events

viewer.setViewVisibility(config: { view: refs.visibility.view; visibility: boolean })

Sets view visibility.

  • view (required): View type (refs.visibility.view: 'TOOLBAR' | 'FLOATING_NAV' | 'SIDE_VIEW' | 'CONTEXT_MENU' | 'INDICATOR' | ...)
  • visibility (required): Whether to show or hide

viewer.addButton(config: { buttons: Array<{ position: 'TOOLBAR.LEFT_SECTION.FIRST' | 'TOOLBAR.LEFT_SECTION.LAST'; icon: refs.icon; label: string; onclick: Function }> })

Adds a button to the toolbar.

  • buttons (required): Array of button information
    • position (required): Button position
    • icon (required): Button icon (refs.icon: 'SHARE' | 'PENCIL' | 'MAIL' | ...)
    • label (required): Button label
    • onclick (required): Click handler

viewer.openContextMenu()

Opens a context menu.

viewer.addContextMenu(config: { menus: Array<{ type: 'MENU'; position: 'FIRST' | 'LAST'; icon?: refs.icon; label?: string; onclick?: Function }> })

Adds a context menu.

  • menus (required): Array of menu information
    • type (required): Menu type
    • position (required): Menu position
    • icon (optional): Menu icon (refs.icon: 'SHARE' | 'PENCIL' | 'MAIL' | ...)
    • label (optional): Menu label
    • onclick (optional): Click handler

viewer.defineDocumentPanel(config: { items: Array<{ label: string; onclick: Function; icon?: refs.icon }> })

Defines document panel at the left side of the viewer toolbar.

  • items (required): Array of menu item information
    • label (required): Menu label
    • onclick (required): Click handler
    • icon (optional): Menu icon (refs.icon: 'SHARE' | 'PENCIL' | 'MAIL' | ...)

viewer.defineAnnotSelectMenu(config: { html: string; style?: string; script?: string; tool?: refs.annotation.tool})

Defines a menu when selecting an annotation.

  • html (required): HTML content of the menu
  • style (optional): CSS content of the menu
  • script (optional): JavaScript content of the menu
  • tool (optional): Annotation tool that the menu is displayed for (refs.annotation.tool: 'HIGHLIGHT' | 'STRIKE' | 'UNDERLINE' | ...)

NOTE: When using style or script, please consider the following:

  • Style: CSS selectors will apply to all matching elements within the viewer scope.
  • Script: JavaScript code will be executed in the viewer's context with the following limitations:
    • External resources cannot be accessed
    • Variables declared will be in global scope

viewer.setBackgroundColor(config: { color: string })

Sets the background color.

  • color (required): Background color hex code (e.g., '#000000')

viewer.setPageBorderColor(config: { color: string })

Sets the page border color.

  • color (required): Border color hex code (e.g., '#000000')

viewer.setColor(config: { mainColor: string; subColor: string })

Sets main and sub colors.

  • mainColor (required): Main color hex code (e.g., '#000000')
  • subColor (required): Sub color hex code (e.g., '#000000')

viewer.setTheme(config: { type: refs.theme })

Sets the theme.

  • type (required): Theme type (refs.theme: 'LIGHT_MODE' | 'DARK_MODE' | 'SYSTEM_SYNCHRONIZATION')

viewer.setLanguage(config: { key: refs.language })

Sets the language.

  • key (required): Language key (refs.language: 'ko' | 'en' | 'ja')

viewer.getSize()

Gets the viewer size.

Returns:

{ width: number; height: number }

viewer.setLogo(config: { url: string })

Sets the brand logo (maximum size: 100x24px).

It displays the logo in the top center of the viewer.

  • url (required): Logo URL

Watermark API

watermark.create(config: { watermarks: Array<TextWatermark | ImageWatermark> })

Creates watermarks.

  • watermarks (required): Array of text or image watermarks

Text API

text.search(config: { keyword: string; caseSensitive?: boolean; useRegex?: boolean; pageRange?: string })

Searches for text in code.

  • keyword (required): Search keyword
  • caseSensitive (optional): Whether to be case sensitive
  • useRegex (optional): Whether to use regular expressions
  • pageRange (optional): Page index range to search (e.g., "1-5, 7, 9-12", "all")

Returns:

{
  results: {
    words: {
      prefix: string;
      keyword: string;
      suffix: string;
      rects: {
        top: number;
        left: number;
        bottom: number;
        right: number;
      }[];
    }[];
  }[];
}

text.getSelected()

Gets selected text.

Returns:

{
  text: string;
  rect: DOMRect;
}

Annotation API

annotation.remove(config: { annotations: Array<{ name: string; pageIndex: number } | { oid: number; pageIndex: number }>; emitEvent?: boolean })

Removes annotations.

  • annotations (required): Array of annotation information to remove
  • emitEvent (optional): Whether to emit events

annotation.get(config?: { pageIndex: number })

Gets annotations.

  • pageIndex (optional): Page index
  • Returns: Array of annotations

annotation.add(config: { annotations: Annotation[]; emitEvent?: boolean })

Adds annotations.

  • annotations (required): Array of annotations to add
  • emitEvent (optional): Whether to emit events Returns: Array of added annotations

annotation.set(config: { annotations: Annotation[]; emitEvent?: boolean })

Updates annotations.

  • annotations (required): Array of annotations to update
  • emitEvent (optional): Whether to emit events

You need to set oid or name and pageIndex as unique key to annotations property. Then the property will be updated.

annotation.undo()

Undoes annotation operations.

  • Returns: Success status

annotation.redo()

Redoes undone annotation operations.

  • Returns: Success status

Redaction API

redaction.get(config?: { textData: mupdf.refs.redaction.textDataOption })

Gets redactions.

  • textData (required): Text data option (refs.redaction.textDataOption: 'FULL' | 'NONE' | 'TEXT_ONLY')

Returns: Array of redactions

redaction.set(config: { redactions: Redaction[] })

Update redactions.

  • redactions (required): Array of redactions to update

Redaction type:

{
  oid: number;
  pageIndex: number;
  name: string;
  rect?: TRect;
  opacity?: number;
  author?: string;
  canBePrinted?: boolean;
  locked?: boolean;
}
  • oid (required): Object id
  • pageIndex (required): Page index
  • name (required): Unique name in the page
  • rect (optional): Rectangle ({ top: number; left: number; bottom: number; right: number })
  • opacity (optional): Opacity (0.0 ~ 1.0)
  • author (optional): Author
  • canBePrinted (optional): Whether to be printed
  • locked (optional): Whether to be locked

You need to set oid or name and pageIndex as unique key. Then the property will be updated.

redaction.add(config: { redactions: Redaction[] })

Adds redactions.

  • redactions (required): Array of redactions to add

Redaction type:

{
  pageIndex: number;
  rect: TRect;
  oid?: number;
  name?: string;
  opacity?: number;
  author?: string;
  canBePrinted?: boolean;
  locked?: boolean;
}
  • pageIndex (required): Page index
  • rect (required): Rectangle ({ top: number; left: number; bottom: number; right: number })
  • oid (optional): Object id
  • name (optional): Unique name in the page
  • opacity (optional): Opacity (0.0 ~ 1.0)
  • author (optional): Author
  • canBePrinted (optional): Whether to be printed
  • locked (optional): Whether to be locked

redaction.remove(config: { redactions: Redaction[] })

Removes redactions.

  • redactions (required): Array of redactions to remove

Redaction type:

{
  oid: number;
  name: string;
  pageIndex: number;
}
  • oid (required): Object id
  • name (required): Unique name in the page
  • pageIndex (required): Page index

You need to set oid or name and pageIndex as unique key. Then the redaction will be removed.

redaction.apply(config: { redactions: Redaction[] })

Applies redactions.

  • redactions (required): Array of redactions to apply

Redaction type:

{
  oid: number;
  name: string;
  pageIndex: number;
}
  • oid (required): Object id
  • name (required): Unique name in the page
  • pageIndex (required): Page index

You need to set oid or name and pageIndex as unique key. Then the redaction will be applied.

Toast API

toast.show(config: { type: 'success' | 'fail' | 'notification'; content: string; header?: string; timeout?: number })

Shows a toast message.

  • type (required): Toast type ('success' | 'fail' | 'notification')
  • content (required): Toast content
  • header (optional): Toast header
  • timeout (optional): Display duration in milliseconds

Keywords

MuPDF

FAQs

Package last updated on 01 Aug 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts