fast, high quality, no service

Leaks of personal data in Russia beat all records. Over two years, their total number has grown – just think about it 40 once. In 2021, there were only such incidents fourin 2022 – over 140and for the first seven months of 2023 – already 150.

One of the possible leak paths is transfer of personal data for processing by a third party. In fact, the company transfers images of identification documents (passports or any other) of its customers to strangers, and what happens next with the data is unknown.

Meanwhile, there is another way to enter data from documents − directly on the device, without the need to send a picture somewhere. It completely eliminates the risk of any leakage. This is our mobile SDK for passport recognition. Read about how we implemented our SDK in PWA (progressive web app) under the cut.


Progressive Web Applications is a technology that allows a website in your smartphone browser to become like a native application. Have an icon on the smartphone screen after installation, have comparable interface responsiveness, store cache and “heavy” resources in terms of download speed from the server directly on the client device and due to this work offline, have access to hardware and its computing power. A special advantage of PWA is that it eliminates the need to be placed in application stores: if Android allows you to download an apk file from any source, then in the case of iOS, you can only install an application from the official store, and PWAs allow you not to bother with this.

Along with the popularity of PWAs, browser support for WebAssembly technology is growing and improving every year. WebAssembly allows you to use the browser engine to perform computationally heavy tasks, including image analysis. We have been developing our products in this direction for a long time, thanks to WASM we have successfully recognizable barcodes, bank cards, documents, invoices, phone numbers inside the browser of the client device. Working with WASM allows you to take PWA to a new level.

PWA is a set of technical practices, among which we are most interested in the ability to cache page resources: if the size of the modules for recognizing barcodes, phone numbers and bank cards allows (with a good Internet connection) to quickly load them from the server, then the modules that allow recognizing identity documents are best stored on the device. For example, here is a comparison of modules with different functionality:

  • bank cards and barcodes: 3.5mb gzip

  • RF passport, maps and barcodes: 8.3 gzip

As you can see, caching the WASM module along with the rest of the resources eliminates the need to download ~8Mb from the server each time. The PWA mechanism that allows resource caching is called Service Worker. When your site requests resources from the server even when there is no Internet, the Service Worker intercepts the request and decides what to do with it: return the resource from the cache, request an update via the API, display a message, and so on. This is enough for your application to run faster than a familiar site (if resources are returned from the local cache) and be completely or partially autonomous.

Let’s look at a demo example for recognizing a Russian passport, in which we will place the entire site together with WASM files in the local cache of the client browser, so that they are now always loaded from the local cache. This will allow the application to work completely offline. Our demo site consists of:

  • index.html – page markup.

  • app.js – web page input script. Working with the camera, transferring the stream of images from the camera, displaying the result.

  • worker.js – web worker. A script that receives a stream of images from a camera and works with a WASM object.

  • sw.js is a service worker. The script of the service worker itself.

  • moduleName.js – a small script that determines the name of the WASM assembly for the current browser.

In the main script of the web page, we register the service worker:

if ("serviceWorker" in navigator) {
    (registration) => {
      console.log("Service worker registration succeeded:", registration);
    (error) => {
      console.error(Service worker registration failed: ${error});
} else {
  console.error("Service workers are not supported.");

In the service worker itself, we pass an array of addresses intended for caching. For ease of reading, we divide the arrays of addresses into groups. First, we will add the path to the main web page file itself, the main script and the web worker (this is the web worker that serves WASM ).

// Files to cache
const cacheName="smartenginesWasm";
const appShellHtml = [

Then we describe the array of graphical resources of the web page. Let it be icons.

const appShellIcons = [

And for caching WASM files, you need to make a small digression. In principle, WASM is now supported in almost any browser, however, there is a set of optimizations that are supported in different ways by modern (primarily mobile) browsers (we wrote about it here). Therefore, our WASM modules are divided into three groups, each of which is loaded depending on the technological capabilities of the browser. To define them via importScripts() , we include a tiny file that returns us the name of an assembly suitable for caching for the current runtime:


const module =  await getModuleName();

const WasmUrls = {
  'nosimd.nothreads': [
  'simd.nothreads': [
  'simd.threads': [

Next, we collect all the addresses into a single pile, and at the event, when the service worker is ready, we slip it to him:

const all = appShellHtml.concat(appShellIcons).concat(WasmUrls[module])

const cacheName="smartenginesWasm";

// Installing Service Worker

self.addEventListener('install', (e) => {
  console.log('[Service Worker] Install');
  e.waitUntil((async () => {
    const cache = await;
    console.log('[Service Worker] Caching all: app shell and content');
    await cache.addAll(all);

The last step is to add an event to listen for network requests. If the browser starts requesting something from the network, the service worker will be able to handle it:

// Fetching content using Service Worker

self.addEventListener('fetch', (e) => {
  e.respondWith((async () => {
    const r = await caches.match(e.request);
    console.log([Service Worker] Fetching resource: ${e.request.url});
    if (r) return r;
    const response = await fetch(e.request);
    const cache = await;
    console.log([Service Worker] Caching new resource: ${e.request.url});
    cache.put(e.request, response.clone());
    return response;

Now, after the first loading of a web page, a network connection is no longer required for its subsequent operation. We will demonstrate the work of such a PWA application in a video.


Recognition of documents directly on the device, without the need to send a picture somewhere, has a number of undeniable advantages – it is always available, there is no need to send images with the user’s personal data to third-party services, the recognition result is always “complete” and working with it is more flexible, it is possible to improve the quality recognition by combining the recognition results of several frames. In addition, with the development of various frameworks, the implementation of the recognition library is becoming easier – this article illustrating the implementation in PWA is a good example of this.

In general, modern PWA applications can largely replace classic mobile phone applications in cases where the application needs an Internet connection (let’s say this is a banking application – Here a recent Forbes study on the subject). With the development of WebAssembly support, PWAs will receive more and more functionality, getting closer and closer in convenience to native applications, allowing customers with different mobile operating systems to provide the same user experience and functionality that is not inferior to conventional applications.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *