Skip to main content

Client-Side Integration

JavaScript SDK — HTML Integration · Version 1.5 · October 2026

Mubeen Device Intelligence gives every browser that visits your site a stable device ID, so you can catch fraud, deduplicate accounts, and spot suspicious sessions. This guide shows how to drop the JavaScript SDK into a plain HTML page and get a device ID you can send to your backend.

Overview​

The JavaScript SDK collects browser fingerprint data and generates a unique device identifier. The SDK provides:

  • Device Fingerprinting — Collects browser and device signals automatically
  • Unique Device ID — Persistent identifier for fraud detection and risk analysis
  • Async & Non-blocking — Loads with defer so it never impacts page rendering

The device ID returned by the SDK must be sent to your backend alongside user data, allowing Mubeen to link the fingerprint with the user's request.


Prerequisites​

RequirementDetails
Site KeyStarts with public_ — obtain from your Mubeen dashboard
Backend URLRegion-specific collection endpoint — https://fp.de.mubeen.ai (EU) or https://fp.sa.mubeen.ai (KSA). Required on every initialization.
Browser SupportModern browsers with JavaScript enabled (Chrome, Firefox, Safari, Edge)

Choose Your Integration Method​

The SDK supports two HTML integration methods. Pick one and use it consistently.

ManualAuto
Scriptmub_fp.jsmub_fp.js?site_key=...&backend_url=...
InitializationExplicit mub_fp.init() callAutomatic on script load
CredentialsPassed in the init() config objectPassed as URL query parameters
Ready patternawait after init()mub_fp.ready() promise
Best forMulti-page sites, dynamic configStatic pages, quick setup
Which should I choose?

Use Auto if you want the simplest setup — just add two script tags and go. Use Manual if you need to control when initialization happens or when the site key is loaded dynamically. Building a React SPA? See Client-Side Integration (React).


Quick Start​

1. Add the SDK​

Manual

<script src="https://cdn.mubeen.ai/fp/mub_fp.js" defer></script>

The defer attribute ensures the script loads after the page content is parsed, preventing any impact on page load performance. Your site_key and backend_url are passed to the SDK in Step 2 below.

Auto

<script>
(function(){
var r, p = new Promise(function(res){ r = res; });
window.mub_fp = { ready: function(){ return p; }, _readyResolve: r };
})();
</script>
<script defer src="https://cdn.mubeen.ai/fp/mub_fp.js?site_key=public_your_site_key_here&backend_url=https://fp.sa.mubeen.ai"></script>

The inline script is a small stub that lets your code call mub_fp.ready() immediately, even before the full SDK has finished downloading. When the SDK lands, it resolves the waiting promise and your code runs. The site_key and backend_url are passed as URL query parameters (both required), and defer ensures the SDK loads after the page is parsed.

2. Initialize the SDK​

Manual

document.addEventListener('DOMContentLoaded', async () => {
await mub_fp.init({
site_key: 'public_your_site_key_here',
backend_url: 'https://fp.sa.mubeen.ai'
});
});

Call mub_fp.init() once the DOM is ready. The SDK is available to use after the returned promise resolves.

Auto

No explicit initialization is required — the SDK initializes automatically when the script loads using the site_key and backend_url from the URL parameters.

Use mub_fp.ready() to wait for initialization to complete before calling other SDK methods:

mub_fp.ready().then(function() {
console.log('SDK is ready');
});

The ready() promise resolves once the SDK has fully loaded and initialized. The shim script from Step 1 ensures mub_fp.ready() is available immediately, so you can call it anywhere — no need to wait for DOMContentLoaded.

3. Retrieve the Device ID​

Call init() once per page (see Step 2). Once it has resolved, you can call getDeviceId() as many times as you need — no re-initialization required.

Manual

document.addEventListener('DOMContentLoaded', async () => {
try {
await mub_fp.init({
site_key: 'public_your_site_key_here',
backend_url: 'https://fp.sa.mubeen.ai'
});

const deviceId = await mub_fp.getDeviceId();
console.log('Device ID:', deviceId);
} catch (error) {
console.error('Failed to get Device ID:', error);
}
});

Auto

mub_fp.ready().then(function() {
return mub_fp.getDeviceId();
}).then(function(deviceId) {
console.log('Device ID:', deviceId);
}).catch(function(error) {
console.error('Failed to get Device ID:', error);
});

getDeviceId() returns a string containing the unique device identifier. Send this value to your backend with user requests for risk validation.


Form Integration​

The most common pattern is populating a hidden form field with the device ID so it is submitted alongside user data.

Manual

<form id="registrationForm">
<input type="text" name="name" placeholder="Name" required>
<input type="email" name="email" placeholder="Email" required>
<input type="password" name="password" placeholder="Password" required>

<!-- Hidden field automatically populated with device fingerprint -->
<input type="hidden" id="mub_device_id" name="mub_device_id">

<button type="submit">Register</button>
</form>

<script>
document.addEventListener('DOMContentLoaded', async () => {
try {
await mub_fp.init({ site_key: 'public_your_site_key_here', backend_url: 'https://fp.sa.mubeen.ai' });
const deviceId = await mub_fp.getDeviceId();
document.getElementById('mub_device_id').value = deviceId;
} catch (error) {
console.error('Failed to get Mubeen Device ID:', error);
}
});
</script>

Auto

<form id="registrationForm">
<input type="text" name="name" placeholder="Name" required>
<input type="email" name="email" placeholder="Email" required>
<input type="password" name="password" placeholder="Password" required>

<!-- Hidden field automatically populated with device fingerprint -->
<input type="hidden" id="mub_device_id" name="mub_device_id">

<button type="submit">Register</button>
</form>

<script>
mub_fp.ready().then(function() {
return mub_fp.getDeviceId();
}).then(function(deviceId) {
document.getElementById('mub_device_id').value = deviceId;
}).catch(function(error) {
console.error('Failed to get Mubeen Device ID:', error);
});
</script>

The hidden field mub_device_id is automatically filled with the device ID and submitted with your form data to your backend.

info

Not using forms? Pass the device ID in your API request body instead. See Server-Side Integration for the expected request format.


Complete Example​

Two end-to-end, copy-pasteable HTML pages — one for each integration method. Both produce the same result: the hidden mub_device_id field is populated with the device ID before the user submits the login form. Pick whichever matches your setup.

Manual

login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Log In</title>

<!--
Load the SDK without any query parameters. `defer` waits for the
HTML to finish parsing before executing the script, so it never
blocks rendering. Credentials are supplied to init() below.
-->
<script src="https://cdn.mubeen.ai/fp/mub_fp.js" defer></script>
</head>

<body>
<h2>Log In</h2>

<form action="/api/login" method="POST">
<label for="email">Email</label>
<input type="email" id="email" name="email" required>

<label for="password">Password</label>
<input type="password" id="password" name="password" required>

<!--
Hidden field submitted with the form. Your backend uses this
device ID to run risk checks against the login attempt.
-->
<input type="hidden" id="mub_device_id" name="mub_device_id">

<button type="submit">Log In</button>
</form>

<script>
// Wait for the DOM (and the deferred SDK script) before touching mub_fp.
document.addEventListener('DOMContentLoaded', async () => {
try {
// Explicit init — you choose when this runs, useful if the
// site_key is fetched dynamically or gated behind user consent.
await mub_fp.init({
site_key: 'public_your_site_key_here',
backend_url: 'https://fp.sa.mubeen.ai' // 'https://fp.de.mubeen.ai' for EU data residency
});

// Safe to call any SDK method once init() has resolved.
const deviceId = await mub_fp.getDeviceId();
document.getElementById('mub_device_id').value = deviceId;
} catch (error) {
// Fail open — the form still submits without a device ID so a
// transient SDK error doesn't block real users from logging in.
console.error('Failed to get device ID:', error);
}
});
</script>
</body>
</html>

Auto

login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Log In</title>

<!--
Tiny inline shim. It gives the page a `mub_fp.ready()` promise
immediately, so application code never has to check whether the
SDK has finished downloading — it just awaits ready().
-->
<script>
(function () {
var r, p = new Promise(function (res) { r = res; });
window.mub_fp = { ready: function () { return p; }, _readyResolve: r };
})();
</script>

<!--
Auto-init: credentials live in the query string. The SDK reads them
on load, initializes itself, then resolves the shim's promise.
`defer` keeps rendering fast.
-->
<script defer
src="https://cdn.mubeen.ai/fp/mub_fp.js?site_key=public_your_site_key_here&backend_url=https://fp.sa.mubeen.ai"></script>
</head>

<body>
<h2>Log In</h2>

<form action="/api/login" method="POST">
<label for="email">Email</label>
<input type="email" id="email" name="email" required>

<label for="password">Password</label>
<input type="password" id="password" name="password" required>

<!--
Hidden field submitted with the form. Your backend uses this
device ID to run risk checks against the login attempt.
-->
<input type="hidden" id="mub_device_id" name="mub_device_id">

<button type="submit">Log In</button>
</form>

<script>
// ready() resolves once the SDK has loaded and auto-initialized.
// No DOMContentLoaded needed — the shim makes ready() safe to call
// anywhere on the page, before or after the SDK script arrives.
mub_fp.ready()
.then(function () { return mub_fp.getDeviceId(); })
.then(function (deviceId) {
document.getElementById('mub_device_id').value = deviceId;
})
.catch(function (error) {
// Fail open — see the Manual example above for rationale.
console.error('Failed to get device ID:', error);
});
</script>
</body>
</html>

Configuration Reference​

mub_fp.init() Parameters​

ParameterTypeRequiredDescription
site_keyStringRequiredYour unique site key (starts with public_)
backend_urlStringRequiredRegion-specific collection endpoint. Use https://fp.de.mubeen.ai (EU / default) or https://fp.sa.mubeen.ai (KSA). Accepts a bare domain or full URL.
info

The Auto method passes site_key and backend_url via the script URL query parameters instead of the init() config object. The values are the same for both methods.

backend_url is required

Initialization will fail if backend_url is missing. Choose the region that matches your data-residency obligations — see Regional Endpoints in the advanced reference for details.


Troubleshooting​

mub_fp is not defined

The SDK script has not loaded yet when your code runs. Ensure:

  1. The <script> tag for the SDK appears before your code in the HTML
  2. Your code runs inside a DOMContentLoaded event listener
  3. For the Auto method, the inline shim script is placed before the SDK script tag
getDeviceId() returns an error
  1. Verify that init() (Manual) or ready() (Auto) has resolved before calling getDeviceId()
  2. Confirm your site_key is correct and active
  3. Check the browser console for network errors — the SDK needs to reach Mubeen's servers
Device ID not populated in form
  1. Confirm the hidden input id matches what your JavaScript uses (mub_device_id)
  2. Ensure the SDK initializes before the user submits the form — add error handling to verify the field is populated
  3. Check the browser console for SDK errors
mub_fp.ready() never resolves

This typically means the SDK script failed to load. Verify:

  1. The mub_fp.js script URL is correct and accessible
  2. The inline shim script is present and runs before the SDK script
  3. No Content Security Policy (CSP) rules are blocking the script
SDK impacts page load performance

The SDK uses defer by default and should not block rendering. If you observe performance issues:

  1. Confirm the defer attribute is present on the script tag
  2. Check that you are not calling SDK methods synchronously at the top level
  3. Use browser DevTools Network tab to verify the script loads after DOM content

Next Steps​