---
Source: https://docs.microblink.com/blinkid/proxy
Title: Route network traffic through a proxy
Description: How to route BlinkID telemetry and online license checks through an HTTPS proxy that you host
---

# Route network traffic through a proxy

BlinkID processes documents on the device, but it still makes two kinds of network requests:

- **Ping**: SDK telemetry, sent to `https://ping.microblink.com`
- **Baltazar**: the online license check, sent to `https://baltazar.microblink.com/api/v2/status/check`, used only by online licenses

If your app or website may only talk to your own domains, for example because of an egress allowlist, a corporate firewall, or a strict Content Security Policy, you can send both through an HTTPS proxy that you host.
The SDK then sends requests to your proxy, and your proxy forwards them to Microblink.

```mermaid
flowchart LR
    SDK["BlinkID SDK"] -- HTTPS --> P["Your proxy"]
    P -- "/api/v2/status/check" --> B["baltazar.microblink.com"]
    P -- "/api/v3/ping" --> PG["ping.microblink.com"]
```

The proxy setting doesn't cover resource downloads or over-the-air (OTA) resource updates.
To avoid all communication with Microblink services, also [configure resources and OTA updates](#avoid-resource-requests).

:::note

Using a proxy requires a special license.
To get one, contact us at [help.microblink.com](https://help.microblink.com).

:::

## Set the proxy URL

Set the proxy URL in the SDK settings when you initialize the SDK.
The URL must use HTTPS.

<Tabs queryString="platform">

  <TabItem value="web" label="Web (TS)" default>

  Pass `microblinkProxyUrl` to `createBlinkId`.

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

  const blinkId = await createBlinkId({
    licenseKey: "your-license-key",
    microblinkProxyUrl: "https://your-proxy.example.com",
  });
  ```

  If the URL can't be parsed or doesn't use HTTPS, `createBlinkId` throws a `ProxyUrlValidationError` with the code `INVALID_PROXY_URL` or `HTTPS_REQUIRED`.

  </TabItem>
  <TabItem value="android" label="Android (Kotlin)">

  Set `microblinkProxyUrl` on `BlinkIdSdkSettings`.

  ```kotlin
  val sdk = BlinkIdSdk.initializeSdk(
      context,
      BlinkIdSdkSettings(
          licenseKey = "your-license-key",
          microblinkProxyUrl = "https://your-proxy.example.com"
      )
  ).getOrThrow()
  ```

  If the URL can't be parsed or doesn't use HTTPS, initialization fails with an `IllegalArgumentException`.

  Don't end the URL with a slash.
  The Android SDK doesn't remove it, so with `https://your-proxy.example.com/`, Ping requests go to `https://your-proxy.example.com//api/v3/ping`, which most proxies don't route.

  If the proxy uses a private certificate authority, trust it through your app's [network security configuration](https://developer.android.com/privacy-and-security/security-config).

  </TabItem>
  <TabItem value="ios" label="iOS (Swift)">

  Set `microblinkProxyURL` on `BlinkIDSdkSettings`.
  Note the uppercase `URL` in the property name.

  ```swift
  let sdk = try await BlinkIDSdk.createBlinkIDSdk(
      withSettings: BlinkIDSdkSettings(
          licenseKey: "your-license-key",
          microblinkProxyURL: "https://your-proxy.example.com"
      )
  )
  ```

  If the URL can't be parsed or doesn't use HTTPS, `createBlinkIDSdk` throws an `InvalidLicenseKeyError`.

  </TabItem>
  <TabItem value="rn" label="React Native (TS)">

  Set `microblinkProxyURL` on `BlinkIdSdkSettings`.

  ```typescript
  const sdkSettings = new BlinkIdSdkSettings("your-license-key");
  sdkSettings.microblinkProxyURL = "https://your-proxy.example.com";
  ```

  Don't end the URL with a slash.
  On Android, the SDK doesn't remove it, so Ping requests go to `//api/v3/ping`, which most proxies don't route.

  If the proxy uses a private certificate authority, trust it through the Android app's [network security configuration](https://developer.android.com/privacy-and-security/security-config).

  </TabItem>
  <TabItem value="flutter" label="Flutter (Dart)">

  Set `microblinkProxyURL` on `BlinkIdSdkSettings`.

  ```dart
  final sdkSettings = BlinkIdSdkSettings("your-license-key");
  sdkSettings.microblinkProxyURL = "https://your-proxy.example.com";
  ```

  Don't end the URL with a slash.
  On Android, the SDK doesn't remove it, so Ping requests go to `//api/v3/ping`, which most proxies don't route.

  If the proxy uses a private certificate authority, trust it through the Android app's [network security configuration](https://developer.android.com/privacy-and-security/security-config).

  </TabItem>
</Tabs>

The SDK appends the service paths to the URL you provide, and keeps any path prefix.
For example, with `https://example.com/mb-proxy` the license check goes to `https://example.com/mb-proxy/api/v2/status/check`.
This lets you run the proxy under an existing API gateway.

## Avoid resource requests

Besides the two services above, the SDK loads its resources and resource updates.
Depending on your configuration, these requests can go to Microblink services:

- **Initial resources** are downloaded from `https://models.cdn.microblink.com/resources` by default on iOS and Android.
  On Web, they're loaded from your own host by default.
- **Over-the-air (OTA) resource updates** are on by default, and go to `https://blinkid-ota.microblink.com` on all platforms.

To avoid all requests to Microblink services, load resources from a location you control, and either turn off resource update checks, or point the update service URL to a host you control, such as a mirror or a proxy.

With update checks turned off, the SDK uses the resources it ships with, and resources change only when you update them yourself.
This means you don't get support for newly added documents as soon as Microblink releases it.
On iOS and Android, download newer resources and ship them in a new release of your app.
On Web, replace the resource files on your server.

<Tabs queryString="platform">

  <TabItem value="web" label="Web (TS)" default>

  Host the resources yourself, and don't point `resourcesLocation` to Microblink's CDN (`https://models.cdn.microblink.com/web/...`).
  See [Hosting resources](sdk/web/resources.md).

  Turn off update checks with `otaResources.checkForUpdates`.
  The SDK then loads the OTA resources from `resources/ota-resources/` under the resources location, or from `otaResources.resourcesLocation` if you set it.

  ```typescript
  const blinkId = await createBlinkId({
    licenseKey: "your-license-key",
    microblinkProxyUrl: "https://your-proxy.example.com",
    otaResources: {
      checkForUpdates: false,
    },
  });
  ```

  To keep update checks on, set `otaResources.otaResourceProviderUrl` to an OTA provider that you host or proxy.
  It must serve the OTA versions API:

  ```text
  GET {otaResourceProviderUrl}/api/v1/versions?generic_version={recognizerVersion}
  ```

  The response contains links to the resource files, and the SDK downloads the files from those links.
  The links must also point to hosts you control.

  </TabItem>
  <TabItem value="android" label="Android (Kotlin)">

  [Pre-bundle the resources](https://github.com/microblink/blinkid-android/blob/master/README.md#pre-bundling-resources) as app assets and set `download = false`, or set `ResourcesConfig.serviceUrl` to a host you control.

  Turn off update checks with `OtaResourcesConfig(checkForUpdates = false)`.
  To keep them on, set `OtaResourcesConfig.serviceUrl` to an OTA service that you host or proxy.

  ```kotlin
  BlinkIdSdkSettings(
      licenseKey = "your-license-key",
      resourcesConfig = ResourcesConfig(download = false),
      otaResourcesConfig = OtaResourcesConfig(checkForUpdates = false),
      microblinkProxyUrl = "https://your-proxy.example.com"
  )
  ```

  </TabItem>
  <TabItem value="ios" label="iOS (Swift)">

  Bundle the resources in your app with `download: false` and `bundleUrl`, or set `ResourcesConfig.serviceUrl` to a host you control.
  See [Resource management](https://github.com/microblink/blinkid-ios/blob/master/README.md#resource-management) in the iOS README.

  Turn off update checks with `OTAResourcesConfig(checkForUpdates: false)`.
  To keep them on, set `OTAResourcesConfig.serviceUrl` to a host you control that serves the same OTA API as `https://blinkid-ota.microblink.com`.

  ```swift
  let settings = BlinkIDSdkSettings(
      licenseKey: "your-license-key",
      resourcesConfiguration: ResourcesConfig(
          download: false,
          bundleUrl: Bundle.main.bundleURL
      ),
      otaResourcesConfiguration: OTAResourcesConfig(checkForUpdates: false),
      microblinkProxyURL: "https://your-proxy.example.com"
  )
  ```

  </TabItem>
</Tabs>

## Set up the proxy server

Your proxy is a reverse proxy that routes requests by path:

- `/api/v2/status/check` goes to `https://baltazar.microblink.com/api/v2/status/check`.
- `/api/v3/ping` and `/api/v3/ping;multi` go to `https://ping.microblink.com`, with the path unchanged.

Route Ping by the `/api/v3/ping` path prefix, or forward every path other than `/api/v2/status/check` to `https://ping.microblink.com`.
A route that only matches `/ping` doesn't work.

If the proxy runs under a path prefix, strip the prefix and forward the rest of the path.

The proxy must:

- serve a TLS certificate that your users' devices and browsers trust
- forward request bodies and the `Content-Type` header unchanged, without re-encoding, compressing, or batching requests
- forward `;multi` as part of the path, without stripping it, encoding the `;`, or treating it as a parameter
- set the upstream `Host` header and TLS SNI to the Microblink host, not the proxy host
- return upstream status codes and response bodies unchanged, so that the SDK can handle license errors

### Additional requirements for web

The web SDK sends requests from a web worker, so they are cross-origin requests to your proxy.
The proxy must:

- answer `OPTIONS` preflight requests
- return `Access-Control-Allow-Origin` with your page's origin, and `Access-Control-Allow-Headers: Content-Type`

Also add the proxy origin to the `connect-src` directive of your Content Security Policy.

### Example nginx configuration

```nginx
server {
    listen 443 ssl;
    server_name your-proxy.example.com;

    ssl_certificate     /etc/ssl/your-proxy.crt;
    ssl_certificate_key /etc/ssl/your-proxy.key;

    # CORS, required for web only
    add_header Access-Control-Allow-Origin  "https://your-app.example.com" always;
    add_header Access-Control-Allow-Methods "POST, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Content-Type" always;
    proxy_hide_header Access-Control-Allow-Origin;
    proxy_hide_header Access-Control-Allow-Methods;
    proxy_hide_header Access-Control-Allow-Headers;
    if ($request_method = OPTIONS) { return 204; }

    location = /api/v2/status/check {
        proxy_pass https://baltazar.microblink.com;
        proxy_set_header Host baltazar.microblink.com;
        proxy_ssl_server_name on;
    }

    location /api/v3/ping {
        proxy_pass https://ping.microblink.com;
        proxy_set_header Host ping.microblink.com;
        proxy_ssl_server_name on;
    }
}
```

## Verify the setup

1. Initialize the SDK and confirm that it doesn't return an error.
2. Check the proxy access log for `POST /api/v3/ping` requests made during initialization.
   With an online license, also check for a `POST /api/v2/status/check` request that returned `200`.
3. In a network inspector, confirm that there are no direct requests to `ping.microblink.com` or `baltazar.microblink.com`.
   If you must avoid all Microblink services, also confirm that there are no requests to `models.cdn.microblink.com` or `blinkid-ota.microblink.com`.

## Troubleshooting

- **Initialization fails with "your license doesn't permit proxy usage."**
  Your license doesn't support using a proxy.
  Contact us at [help.microblink.com](https://help.microblink.com) to get one that does.
- **Initialization fails with a server permission error.**
  The proxy doesn't forward `/api/v2/status/check` to Baltazar, or it sends the wrong `Host` header or SNI.
- **Ping requests fail on Android, or the proxy log shows `//api/v3/ping`.**
  The proxy URL ends with a slash.
  Remove it.
- **The browser console shows a CORS error.**
  The proxy doesn't answer preflight requests or doesn't return the CORS headers.
  See [Additional requirements for web](#additional-requirements-for-web).
- **A TLS handshake error occurs on mobile.**
  The device doesn't trust the proxy certificate.
  Use a publicly trusted certificate, or trust your certificate authority in the app configuration.
- **Requests still go to `models.cdn.microblink.com` or `blinkid-ota.microblink.com`.**
  The proxy setting doesn't cover resources and OTA updates.
  See [Avoid resource requests](#avoid-resource-requests).
- **All requests still go directly to Microblink.**
  The proxy URL isn't set when the SDK is initialized, or your SDK version doesn't support it.


Last updated on Oct 30, 2026
