Skip to content

Building a Vue.js Document Scanner web app with TypeScript and Vite

Kevin April 16, 2025 10 mins read
Web Document Scanner SDK

In this tutorial, we’ll create a web app for scanning documents and exporting them as PDF files using Vue.js. We’ll set up our project with Vite and write the app in TypeScript. For the actual document scanning functionalities and app UI, we’ll use the Scanbot Web Document Scanner SDK.

Using our Vue Document Scanner web app to scan a document and export it as a PDF

We’ll create our app by following these steps:

  1. Setting up the project
  2. Initializing the SDK
  3. Configuring the document scanner
  4. Implementing the PDF export feature

Let’s get started!

Want to see the final code right away? Click here.

App.vue:

<script setup lang="ts">
import { ref, onBeforeMount, type Ref } from "vue";
import ScanbotSDK from "scanbot-web-sdk/ui";
import { DocumentScannerUIResult } from "scanbot-web-sdk/@types/ui2/configuration/document/DocumentScannerUIResult";
import { PdfConfiguration } from "scanbot-web-sdk/@types";

// Reactive variable to hold the scan result
const scanResult: Ref<DocumentScannerUIResult | null> = ref(null);

// Initialize the Scanbot SDK before the component mounts
onBeforeMount(async () => {
    await ScanbotSDK.initialize({
      licenseKey: "", // Leave empty for 60-second trial
      enginePath: "/wasm/"
    });
});

// Function to launch the document scanner UI
const runDocumentScanner = async () => {
    try {
        const config = new ScanbotSDK.UI.Config.DocumentScanningFlow();
        const result = await ScanbotSDK.UI.createDocumentScanner(config);

        if (result) {  
            scanResult.value = result;  
        }

        return;
    } catch (error) {
        console.error("Error during document scanning:", error);
    }
}

// Function to handle the PDF export process
const handleDocumentExport = async () => {  
    if (!scanResult.value) return;

    try {  
        const options: Partial<PdfConfiguration> & { runOcr: boolean } = {  
            pageSize: "A4",  
            pageDirection: "PORTRAIT",  
            pageFit: "FIT_IN",  
            dpi: 72,  
            jpegQuality: 80,
            runOcr: false
        }  

        const document = await scanResult.value.document.createPdf(options);  
        await exportPdf(document);
    } catch (error) {
        console.error("Error exporting PDF:", error);
    }  
}

// Helper function to download the PDF file
const exportPdf = async (documentData: ArrayBuffer) => {  
    const a = document.createElement("a");  
    document.body.appendChild(a);  
    a.style.display = "none";  
    const blob = new Blob([documentData], {type: 'application/pdf'});  
    const url = window.URL.createObjectURL(blob);  
    a.href = url;  
    a.download = 'scanned-document.pdf';  
    a.click();  
    window.URL.revokeObjectURL(url);  
    document.body.removeChild(a);  
}
</script>

<template>
    <div>
        <button @click="runDocumentScanner">Start Scanner</button>
        <button v-if="scanResult" @click="handleDocumentExport">Export PDF</button>
    </div>
</template>

Step 1: Set up the project

We’ll be using Vite to set up our project. Developed by the creator of Vue.js, Vite is a modern build tool optimized for speed and performance.

Open a terminal and create a new Vite-powered Vue project with the following command:

npm create vue@latest

You’ll be asked to name your project. For this tutorial, let’s go with “scanbot-vue-doc-tut”.

Next, you’ll be asked which features to include in your project. For this tutorial, we only need TypeScript.

When your project is ready, cd into the project directory, install the dependencies, and launch the development server:

cd scanbot-vue-doc-tut
npm install
npm run dev

Open the src/App.vue file and replace the file’s contents with the following structure:

<script setup lang="ts">
</script>

<template>
    <div>
    </div>
</template>

We’ll start with the empty Vue component above and build it out further below.

Step 2: Initialize the SDK

Open another terminal, navigate to your project directory, and install the scanbot-web-sdk package with the following command:

npm i scanbot-web-sdk

The SDK contains WebAssembly (WASM) binaries that should be hosted on your server. We ship these binaries with the npm package. Since Node.js doesn’t copy the binaries to the target automatically, you need to manually copy them to the desired destination (we recommend the public asset directory).

You can quickly copy them from node_modules to a folder called wasm in the public asset directory using the following command:

mkdir -p public/wasm && cp -r node_modules/scanbot-web-sdk/bundle/bin/complete/* public/wasm

💡 To ensure these files are always copied to the same directory for all users and updated when the SDK itself is updated, you can add the command as a post-installation script to your package.json:

"postinstall": "mkdir -p public/wasm && cp -r node_modules/scanbot-web-sdk/bundle/bin/complete/* public/wasm"

Back in App.vue, add the code to import ScanbotSDK at the top of your script section:

<script setup lang="ts">
import ScanbotSDK from "scanbot-web-sdk/ui";
</script>

We need to initialize ScanbotSDK within App.vue. You have the option of leaving the licenseKey empty to use a trial mode that works for 60 seconds per session or getting a free 7-day trial by submitting the trial license form on our website.

Your App.vue should now look like this:

<script setup lang="ts">
import { onBeforeMount } from "vue";
import ScanbotSDK from "scanbot-web-sdk/ui";

// Initialize the Scanbot SDK before the component mounts
onBeforeMount(async () => {
    await ScanbotSDK.initialize({
      licenseKey: "",
      enginePath: "/wasm/"
    });
});
</script>

<template>
    <div>
    </div>
</template>

Step 3: Configure the document scanner

First, we’ll need to create the configuration that we’ll use for the document scanner in App.vue.

To do this, we can call a method that returns an instance of the configuration object, which we can then modify as needed.

const config = new ScanbotSDK.UI.Config.DocumentScanningFlow();

This config object will be what we use to make changes to the RTU UI. However, for now, let’s just use it to create our document scanner:

await ScanbotSDK.UI.createDocumentScanner(config);

Now, let’s assign the scanner to a variable and wrap it within an asynchronous function so we can assign it to a button within App.vue. This allows us to easily trigger the scanner with a button press in our application.

Let’s name the variable “result”, since it will store the outcome returned by createDocumentScanner. The scanner will be launched directly from this assignment, so we don’t need to return the result here as we’ll set the actual scan result later with a reactive variable.

const runDocumentScanner = async () => {
    const config = new ScanbotSDK.UI.Config.DocumentScanningFlow();
    const result = await ScanbotSDK.UI.createDocumentScanner(config);

    return;
};

To trigger the scanner with a button press, we add a button to the template section of our Vue component and assign the runDocumentScanner function to its @click event:

<template>
    <div>
        <button @click="runDocumentScanner">Start Scanner</button>
    </div>
</template>

Our App.vue should now look like this:

<script setup lang="ts">
import { onBeforeMount } from "vue";
import ScanbotSDK from "scanbot-web-sdk/ui";

// Initialize the Scanbot SDK before the component mounts
onBeforeMount(async () => {
    await ScanbotSDK.initialize({
      licenseKey: "",
      enginePath: "/wasm/"
    });
});

// Function to launch the document scanner UI
const runDocumentScanner = async () => {
    const config = new ScanbotSDK.UI.Config.DocumentScanningFlow();
    const result = await ScanbotSDK.UI.createDocumentScanner(config);

    return;
};
</script>

<template>
    <div>
        <button @click="runDocumentScanner">Start Scanner</button>
    </div>
</template>

With this setup, we now have a fully functional document scanner!

If you haven’t already, go to the local server running your app and click the “Start Scanner” button to open the scanner and scan a document.

💡 To test your web app on your phone, you have a few options. One option is to use a service like ngrok, which creates a tunnel to one of their SSL-certified domains. Their Quick Start guide will help you get up and running quickly.

Currently, you cannot do anything with the scanned pages, so we’ll now add the ability to export to PDF.

Step 4: Implement the PDF export feature

Let’s start by adding a state called scanResult to store the scanned document.

import { ref, onBeforeMount, type Ref } from "vue";
import ScanbotSDK from "scanbot-web-sdk/ui";
import { DocumentScannerUIResult } from "scanbot-web-sdk/@types/ui2/configuration/document/DocumentScannerUIResult";
import { PdfConfiguration } from "scanbot-web-sdk/@types";

const scanResult: Ref<DocumentScannerUIResult | null> = ref(null);

Then we can set the value of scanResult in our runDocumentScanner function when the scanning results are returned. We’ll also add some basic error handling.

const runDocumentScanner = async () => {
    try {
        const config = new ScanbotSDK.UI.Config.DocumentScanningFlow();
        const result = await ScanbotSDK.UI.createDocumentScanner(config);

        if (result) {  
            scanResult.value = result;  
        }

        return;
    } catch (error) {
        console.error("Error during document scanning:", error);
    }
}

Now that we have our document stored, we can use the SDK’s built-in createPdf method to generate the PDF.

The createPdf method of the SDK allows you to pass options (all of which can be seen here) to customize your PDF. Then, we just need to add a helper function to allow us to download the file.

First, let’s import the necessary PDF configuration type.

import { PdfConfiguration } from "scanbot-web-sdk/@types";

Now, let’s create our export functions.

const handleDocumentExport = async () => {  
    if (!scanResult.value) return;

    try {  
        const options: Partial<PdfConfiguration> & { runOcr: boolean } = {  
            pageSize: "A4",  
            pageDirection: "PORTRAIT",  
            pageFit: "FIT_IN",  
            dpi: 72,  
            jpegQuality: 80,
            runOcr: false  
        }  

        const document = await scanResult.value.document.createPdf(options);  
        await exportPdf(document);
    } catch (error) {
        console.error("Error exporting PDF:", error);
    }
}

const exportPdf = async (documentData: ArrayBuffer) => {  
    const a = document.createElement("a");  
    document.body.appendChild(a);  
    a.style.display = "none";  
    const blob = new Blob([documentData], {type: 'application/pdf'});  
    const url = window.URL.createObjectURL(blob);  
    a.href = url;  
    a.download = 'scanned-document.pdf';  
    a.click();  
    window.URL.revokeObjectURL(url);  
    document.body.removeChild(a);  
}

Finally, we need to add a button to trigger the download to our page. We’ll only show this button once a document has been scanned by using v-if.

<template>
    <div>
        <button @click="runDocumentScanner">Start Scanner</button>
        <button v-if="scanResult" @click="handleDocumentExport">Export PDF</button>
    </div>
</template>

Our final app looks like this:

<script setup lang="ts">
import { ref, onBeforeMount, type Ref } from "vue";
import ScanbotSDK from "scanbot-web-sdk/ui";
import { DocumentScannerUIResult } from "scanbot-web-sdk/@types/ui2/configuration/document/DocumentScannerUIResult";
import { PdfConfiguration } from "scanbot-web-sdk/@types";

// Reactive variable to hold the scan result
const scanResult: Ref<DocumentScannerUIResult | null> = ref(null);

// Initialize the Scanbot SDK before the component mounts
onBeforeMount(async () => {
    await ScanbotSDK.initialize({
      licenseKey: "", // Leave empty for 60-second trial
      enginePath: "/wasm/"
    });
});

// Function to launch the document scanner UI
const runDocumentScanner = async () => {
    try {
        const config = new ScanbotSDK.UI.Config.DocumentScanningFlow();
        const result = await ScanbotSDK.UI.createDocumentScanner(config);

        if (result) {  
            scanResult.value = result;  
        }

        return;
    } catch (error) {
        console.error("Error during document scanning:", error);
    }
}

// Function to handle the PDF export process
const handleDocumentExport = async () => {  
    if (!scanResult.value) return;

    try {  
        const options: Partial<PdfConfiguration> & { runOcr: boolean } = {  
            pageSize: "A4",  
            pageDirection: "PORTRAIT",  
            pageFit: "FIT_IN",  
            dpi: 72,  
            jpegQuality: 80,
            runOcr: false
        }  

        const document = await scanResult.value.document.createPdf(options);  
        await exportPdf(document);
    } catch (error) {
        console.error("Error exporting PDF:", error);
    }  
}

// Helper function to download the PDF file
const exportPdf = async (documentData: ArrayBuffer) => {  
    const a = document.createElement("a");  
    document.body.appendChild(a);  
    a.style.display = "none";  
    const blob = new Blob([documentData], {type: 'application/pdf'});  
    const url = window.URL.createObjectURL(blob);  
    a.href = url;  
    a.download = 'scanned-document.pdf';  
    a.click();  
    window.URL.revokeObjectURL(url);  
    document.body.removeChild(a);  
}
</script>

<template>
    <div>
        <button @click="runDocumentScanner">Start Scanner</button>
        <button v-if="scanResult" @click="handleDocumentExport">Export PDF</button>
    </div>
</template>

Now run the app again to test the PDF export feature and download the scanned pages as a PDF.

Using our Vue Document Scanner web app to scan a document and export it as a PDF

Conclusion

🎉 Congratulations! You can now scan documents from your browser and export them as PDFs!

If this tutorial has piqued your interest in integrating document scanning functionalities into your web app or website, make sure to take a look at our SDK’s other neat features in our documentation – or run our example project for a more hands-on experience.

Should you have questions about this tutorial or run into any issues, we’re happy to help! Just shoot us an email via tutorial-support@scanbot.io.

Happy scanning! 🤳

Related blog posts