Client-Side Integration
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
deferso 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
| Requirement | Details |
|---|---|
| Site Key | Starts with public_ — obtain from your Mubeen dashboard |
| Backend URL | Region-specific collection endpoint — https://fp.de.mubeen.ai (EU) or https://fp.sa.mubeen.ai (KSA). Required on every initialization. |
| Browser Support | Modern 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.
| Manual | Auto | |
|---|---|---|
| Script | mub_fp.js | mub_fp.js?site_key=...&backend_url=... |
| Initialization | Explicit mub_fp.init() call | Automatic on script load |
| Credentials | Passed in the init() config object | Passed as URL query parameters |
| Ready pattern | await after init() | mub_fp.ready() promise |
| Best for | Multi-page sites, dynamic config | Static pages, quick setup |
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.
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
<!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
<!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
| Parameter | Type | Required | Description |
|---|---|---|---|
site_key | String | Required | Your unique site key (starts with public_) |
backend_url | String | Required | Region-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. |
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 requiredInitialization 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:
- The
<script>tag for the SDK appears before your code in the HTML - Your code runs inside a
DOMContentLoadedevent listener - For the Auto method, the inline shim script is placed before the SDK script tag
getDeviceId() returns an error
- Verify that
init()(Manual) orready()(Auto) has resolved before callinggetDeviceId() - Confirm your
site_keyis correct and active - Check the browser console for network errors — the SDK needs to reach Mubeen's servers
Device ID not populated in form
- Confirm the hidden input
idmatches what your JavaScript uses (mub_device_id) - Ensure the SDK initializes before the user submits the form — add error handling to verify the field is populated
- Check the browser console for SDK errors
mub_fp.ready() never resolves
This typically means the SDK script failed to load. Verify:
- The
mub_fp.jsscript URL is correct and accessible - The inline shim script is present and runs before the SDK script
- 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:
- Confirm the
deferattribute is present on the script tag - Check that you are not calling SDK methods synchronously at the top level
- Use browser DevTools Network tab to verify the script loads after DOM content
Next Steps
- Client-Side Integration (React) — React hook-based integration for SPAs
- Server-Side Integration — Send the device ID to your backend for risk validation
- Android Integration — Native Android SDK for mobile applications