This guide adds a ready-made scanner interface to a React application and receives the finished PDF through the saved event. The resulting Blob can be previewed, downloaded or uploaded to your existing backend.
Prerequisites
You need:
- Windows 10 or 11;
- a TWAIN or WIA scanner driver;
- Node.js and an existing React project;
- a ScanBridge trial or paid licence key;
- the ScanBridge helper installed for the Windows user who will scan.
The packages are private tarballs and are not published to the public npm registry.
Install the packages
Install core first and web second in the same command:
npm install https://demo.scanbridge.dev/install-files/scanner-core-0.2.0.tgz https://demo.scanbridge.dev/install-files/scanner-web-0.2.0.tgz
For a reproducible CI install, pin the same URLs in package.json:
{
"dependencies": {
"@scanner/core": "https://demo.scanbridge.dev/install-files/scanner-core-0.2.0.tgz",
"@scanner/web": "https://demo.scanbridge.dev/install-files/scanner-web-0.2.0.tgz"
}
}
Declare the custom element for TypeScript
Create scanner-widget.d.ts if TypeScript reports that scanner-widget is not a known JSX element:
import type { DetailedHTMLProps, HTMLAttributes } from 'react'
declare global {
namespace JSX {
interface IntrinsicElements {
'scanner-widget': DetailedHTMLProps<
HTMLAttributes<HTMLElement> & {
'license-key'?: string
'file-type'?: 'pdf' | 'png' | 'jpg'
lang?: string
open?: boolean
},
HTMLElement
>
}
}
}
Render the widget
Import @scanner/web once, then render the custom element. Replace the example key with the key issued for your organisation and domain.
import '@scanner/web'
export function ScanPage() {
return (
<scanner-widget
license-key="SB-XXXX-XXXX-XXXX"
file-type="pdf"
lang="en"
/>
)
}
The element displays its own scan dialog. If the local helper is missing, it presents the installation path to the user.
Handle the saved PDF
React does not convert custom DOM events into component props automatically, so attach a listener to the element through a ref.
import { useEffect, useRef } from 'react'
import '@scanner/web'
type SavedDetail =
| { fileType: 'pdf'; blob: Blob }
| {
fileType: 'png' | 'jpg'
pages: Array<{
id: string
name: string
url: string
mimeType: string
blob: Blob
}>
}
export function ScanPage() {
const scannerRef = useRef<HTMLElement>(null)
useEffect(() => {
const scanner = scannerRef.current
if (!scanner) return
const handleSaved = async (rawEvent: Event) => {
const event = rawEvent as CustomEvent<SavedDetail>
if (event.detail.fileType !== 'pdf') return
const form = new FormData()
form.append('document', event.detail.blob, 'scan.pdf')
await fetch('/api/documents', {
method: 'POST',
body: form,
})
}
scanner.addEventListener('saved', handleSaved)
return () => scanner.removeEventListener('saved', handleSaved)
}, [])
return (
<scanner-widget
ref={scannerRef}
license-key="SB-XXXX-XXXX-XXXX"
file-type="pdf"
lang="en"
/>
)
}
/api/documents is an example endpoint. Use the route, authentication and metadata required by your application.
Expected result
When the user saves a PDF, the saved event contains:
{
fileType: 'pdf',
blob: Blob // application/pdf
}
For PNG or JPG output, the event contains a pages array with one Blob per page.
Common problems
The widget renders but scanning does not open
Confirm that the license-key attribute contains a valid key issued for the current domain. Every issued key also covers localhost for development.
The helper is not detected
Install it for the same Windows user running the browser, then use the widget's Verify action. Check that local security software has not prevented the helper from starting.
No scanner appears
Verify that Windows can see the device through a TWAIN or WIA driver. A USB connection alone is not enough if the driver exposes neither interface.
The PDF has only one page
Multi-page sessions, ADF and duplex begin with Professional. Starter keeps one page in each saved file.
For all attributes, image outputs and error events, use the complete ScanBridge install and integration guide.