Skip to main content

Hosting resources

WebAssembly (WASM) allows you to run high-performance code, like the image processing engine in BlinkID, directly in the browser. However, to make this work, you need to host the WASM-related files correctly. This guide explains why this is necessary and how to do it.

The core challenge comes from the browser's security model, designed to protect users by isolating websites from each other.

Why can't the browser just load the files?

Modern web applications, to get the most out of devices, often rely on multi-threading. This means that they use features like Web Workers and SharedArrayBuffer to avoid freezing the user interface during heavy computations. To use these securely, browsers enforce a secure context and cross-origin isolation.

Cross-origin isolation is a prerequisite for powerful features and is enabled by specific HTTP headers.

The main reasons for specific hosting requirements are:

  1. Same-Origin Policy (SOP): A fundamental security mechanism that restricts how a document or script from one origin can interact with a resource from another origin. Workers must obey the same-origin policy. The URL is resolved relative to the current HTML page's location.

  2. Cross-Origin Embedder Policy (COEP): This policy, enabled with the Cross-Origin-Embedder-Policy: require-corp header, prevents a document from loading any cross-origin resources that don't explicitly grant the document permission to be loaded (using CORS). This is required for features like SharedArrayBuffer which BlinkID uses for its multi-threaded WASM modules.

  3. Correct MIME Type: The browser needs to know that a .wasm file is a WebAssembly module, not a plain text file or an image. The server must identify it with the Content-Type: application/wasm header.

The best practice: same-origin hosting

The simplest and most robust solution is to host the WASM resources on the same domain as your web application. This avoids nearly all cross-origin security complexities.

How to do it:

Copy Resources: Locate the WASM assets from the library you're using (e.g., node_modules/@microblink/blinkid/dist/resources). Copy this entire directory into a publicly accessible folder on your web server. A common practice is to place it in a static, public, or a dedicated resources folder. The path on the web server should be /resources.

Advanced case: hosting on a different domain (CDN)

If you must host resources on a different domain (e.g., a Content Delivery Network), you need to configure both the application server and the resource server to handle cross-origin requests securely.

This is necessary to enable the "cross-origin isolated" state required by BlinkID's multi-threaded WASM module.

Step 1: Configure headers on your main application server

Your primary web application needs to serve its HTML pages with the following two headers. This allows using multi-threading (i.e. SharedArrayBuffer):

  • Cross-Origin-Opener-Policy: same-origin: Isolates your page context from other top-level windows.
  • Cross-Origin-Embedder-Policy: require-corp: Requires all embedded cross-origin resources to explicitly opt-in via CORS.

Example for Netlify (netlify.toml)

[[headers]]
# Apply these headers to all pages
for = "/*"
[headers.values]
Cross-Origin-Opener-Policy = "same-origin"
Cross-Origin-Embedder-Policy = "require-corp"

Step 2: Configure headers on your resource server (CDN)

The server hosting your WASM files must add an Access-Control-Allow-Origin header to its responses. This explicitly permits your web application's domain to fetch the resources.

Example for a resource server (Netlify)

[[headers]]
for = "/*"
[headers.values]
"Access-Control-Allow-Origin" = "https://my-app-url.com"
"Cross-Origin-Resource-Policy" = "cross-origin"

Step 3: Use resourcesLocation to specify the location of your WASM binary

import { createBlinkId } from "@microblink/blinkid";

const blinkid = await createBlinkId({
licenseKey: "your license key here",
resourcesLocation: "your CDN URL here",
});

The key thing to note here is that you should pass the base URL, and the SDK will append the rest of the path.

If you supply cdn.example.com/somepackage, the SDK will append resources/blinkid-worker.js and will fetch that full URL.

Edge case: What if I can't set COOP/COEP headers?

If you are in a situation where you cannot set the Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers, you will not be able to use features that depend on SharedArrayBuffer.

For BlinkID, this means you must disable multi-threading. By default, the SDK will attempt the most performant method (threaded) and fall back on simpler (slower) methods, depending on the browser and amount of memory.

You can also set single-threading yourself by modifying the wasmVariant parameter. The threaded version (advanced-threads) uses SharedArrayBuffer, while advanced doesn't.


import { createBlinkId } from "@microblink/blinkid";

const blinkid = await createBlinkId({
licenseKey: "your license key here",
resourcesLocation: "your CDN URL here",
wasmVariant: "advanced"
},
});

While this will work, performance may be degraded since all processing will happen on the main browser thread, which can impact UI responsiveness.

note

If you manually specify the wasmVariant, the automatic failover logic will no longer apply.