Add a Document Scanner to Your Web App with the ScanKit SDK
Your users take photos of documents. Your app needs scans. Between those two things sits the step that decides whether the rest of the pipeline works: turning a phone photo into a flat, readable page with the edges found and the perspective corrected.
The ScanKit SDK is that step as a drop-in widget: camera and file input, live edge detection, a crop UI for corrections, filters, rotation, and a clean image the user can keep. It is framework agnostic, needs no build step, and ships as one stylesheet plus one script.
What the widget handles for you
Most of the work in document capture is not the camera, it is everything after the shutter:
- Input — camera on mobile, file picker on desktop, with the user choosing their own photo.
- Edge detection — the page is found in the frame while the user is still holding the phone, so they can correct the position instead of discovering the problem later.
- Manual crop — when detection picks the wrong corners, the crop UI lets the user drag them. This is the difference between a rejected photo and a usable one.
- Rotation and filters — original, flat or white, whichever suits the document. Rotation is applied to the exported file as well, not only to the preview.
- A clean result — the export is the straightened, cropped page, not the original photo with the desk still in it.
The image processing itself runs on ScanKit's API, hosted in the EU, and uploads are not stored: the image is deleted after processing.
Add it to a page
Two tags and a few lines are enough to get a working scanner on a page:
<link rel="stylesheet" href="https://www.scankit.io/sdk/scankit-sdk.css">
<script src="https://www.scankit.io/sdk/scankit-sdk.min.js"></script>
<div id="scan-area"></div>
<script>
const scanner = new ScanKit({
target: '#scan-area',
apiKey: 'your-api-key', // from your dashboard
buttonText: 'Scan document',
onScanComplete: (result) => {
// result.image is a Blob with the scanned document
console.log(result.image);
},
onScanCancel: () => console.log('cancelled')
});
scanner.init();
</script>
The options you are most likely to touch:
- target — CSS selector or element where the scan button lives. Defaults to
body. - apiKey — sent as the
X-API-Keyheader. Without a key the API answers401 Missing API Key; with a key that does not belong to an active account it answers401 Invalid API Key, so you can tell a configuration mistake from a wrong value. - buttonText / buttonClass — label and styling of the start button, so it fits your design instead of the other way round.
- inputSource —
'photo'for the normal capture flow. - segmentCount — how finely the page is divided for the perspective correction. The default of 9 is a good starting point.
- onScanComplete — receives the result, including the image as a Blob.
- onScanCancel — fires when the user backs out, which is usually where you want to stop a spinner.
Send the result to your backend
result.image is a Blob, so it goes straight into a FormData upload:
onScanComplete: async (result) => {
const form = new FormData();
form.append('file', result.image, 'scan.jpg');
await fetch('/api/documents', { method: 'POST', body: form });
}
You can show the same Blob immediately as a thumbnail with URL.createObjectURL(result.image), so the user sees their scan before the upload finished.
When no document is found in the photo
A photo of an empty desk is not an error the API can fix by guessing. On the image path the response carries the header X-ScanKit-Detected with true or false, and the JSON endpoints return a document_detected field. Treat false as a signal, not a failure: open your own manual crop screen and let the user pick the corners. It is the difference between a dead end and a second attempt.
Before you put it on a public page
- Serve over HTTPS. Browsers only grant camera access on secure origins, so the widget cannot work on plain HTTP.
- Remember the key is visible. An API key used in the browser is readable by anyone who opens the developer tools, which is fine for an internal tool and not fine for a public page. For public pages, use a hosted scanner that keeps the key on the server, or route the upload through your own backend and keep the key there.
- Do not collect what you do not need. If your use case only needs the extracted values, keep the extracted values and let the image go.
- Start on the free tier. 50 credits, no credit card, enough to run the flow through with real documents from your own team before you wire it into production.
The point of the widget is that none of this requires a decision about your frontend stack. It runs where the button is, and the rest of your app keeps working the way it does today.
Ready to get started with ScanKit?
Start building powerful document scanning features into your applications today.