Set up Device Intelligence
Choose how to deploy cside Device Intelligence on your website using Cloudflare Workers, Webflow, Google Tag Manager, direct script injection, or an NPM package.
Set up cside Device Intelligence by loading the browser script early, collecting telemetry with sendClientTelemetry, and sending the returned session token to your backend.
Loading https://[your-team-id].csidefd.com/client.js exposes sendClientTelemetry in the browser. A session fingerprint is created only after your site calls sendClientTelemetry(externalIds?).
Choose an implementation option
| Method | Best for | Production guidance |
|---|---|---|
| Cloudflare Workers | Sites already routed through Cloudflare | Good for edge injection and limited-path rollout |
| Direct script injection | Most production websites | Recommended when you control the HTML or app shell |
| Webflow | No-code Webflow sites | Use Custom code and publish before testing |
| NPM package | Apps built with a bundler | Recommended when your app calls sendClientTelemetry itself |
| Google Tag Manager | Quick validation without code changes | Use for testing only when script order matters |
Customer domain recommendation
Use the DNS setup to use your own domain where possible. cside offers this to avoid privacy concerns around third-party domains, make the script look first-party to the browser, and prevent browser ad blockers or client-side blocking from interfering with the script or impacting detection accuracy.
If cside provides a dedicated script URL, use that exact URL in every setup method. The examples below use placeholders. To see your full script URL, go to the cside dashboard.
Fail-open browser bootstrap
Use this bootstrap whenever you inject Device Intelligence directly into a page. Add it at the top of the document <head>, before other application scripts. It loads client.js asynchronously, queues calls made while the script loads, and rejects queued calls if the script fails, does not initialize telemetry, or takes longer than ten seconds. The page remains usable when cside is unavailable.
The HTML, GTM, and Framer install tabs in the cside dashboard generate this same bootstrap for your team-specific script URL. The Cloudflare Worker example below uses the same loader inside the edge-injected HTML.
<script>
(function () {
const calls = [];
let error;
let timeoutID;
function fallback(externalIds) {
return error
? Promise.reject(error)
: new Promise((resolve, reject) => {
calls.push({ externalIds, resolve, reject });
});
}
function rejectAll(nextError) {
if (error) {
return;
}
error = nextError;
while (calls.length > 0) {
calls.shift().reject(nextError);
}
}
function flush(sendClientTelemetry) {
while (calls.length > 0) {
const call = calls.shift();
Promise.resolve()
.then(() => sendClientTelemetry(call.externalIds))
.then(call.resolve, call.reject);
}
}
window.sendClientTelemetry = window.sendClientTelemetry || fallback;
const script = document.createElement("script");
script.async = true;
script.src = "https://[your-team-id].csidefd.com/client.js";
script.referrerPolicy = "origin";
script.setAttribute("data-src", "6");
const fail = (nextError) => {
clearTimeout(timeoutID);
rejectAll(nextError);
};
script.onerror = () =>
fail(new Error("cside client.js failed to load"));
script.onload = () => {
clearTimeout(timeoutID);
const sendClientTelemetry = window.sendClientTelemetry;
if (
typeof sendClientTelemetry !== "function" ||
sendClientTelemetry === fallback
) {
rejectAll(new Error("cside telemetry unavailable"));
return;
}
flush(sendClientTelemetry);
};
timeoutID = setTimeout(
() => fail(new Error("cside client.js timed out while loading")),
10000,
);
(document.head || document.documentElement).appendChild(script);
})();
</script>
Replace only the script URL. Your application should handle rejected sendClientTelemetry calls and continue its normal flow - this is the fail-open behavior.
Serve the script from your own domain
This option lets you serve the Device Intelligence script from a subdomain you control, such as fingerprint.example.com. It is intended for production accounts that want first-party script delivery and tighter CSP control.
Custom fingerprint domains require cside to provision a target hostname for your account. Contact cside before adding DNS records.
DNS setup
- Choose a subdomain, for example
fingerprint.example.com - Ask cside for your fingerprinting target hostname
- Add a
CNAMErecord from your subdomain to the cside target - Wait for DNS to propagate and for cside to validate the hostname
- Use your subdomain as the script source
Example DNS record:
| Type | Name | Value |
|---|---|---|
CNAME | fingerprint.example.com | [your-team-id].csidefd.com |
After validation, use the customer-domain script URL:
Use the fail-open browser bootstrap above and replace its script.src value with https://fingerprint.example.com/client.js.
Update your CSP to allow the customer subdomain for script-src and connect-src.
Direct script injection
Directly injecting the tag into your HTML is supported. Add the script in the page <head> before you call fingerprinting functions.
Use the fail-open browser bootstrap above and replace its script.src value with your team-specific csidefd.com URL.
Then call sendClientTelemetry after the script loads. You can call it with no arguments or pass an optional externalIds object.
const result = await sendClientTelemetry({
accountId: "customer-123",
orderId: "order-456",
});
if (result.errors) {
console.error(result.errors);
throw new Error("Telemetry request failed.");
}
const { token: sessionToken } = result;
Send the session token to your backend and exchange it with the cside API. Production backend exchanges use a server-side Device Intelligence API key generated in the cside dashboard. See the Events API for the full flow.
Troubleshooting
- Device Intelligence icon missing in the UI - Confirm that Device Intelligence is enabled for the managed domain in cside. If you removed and re-added the domain, the feature may need to be enabled again.
- Script loads, but no fingerprints appear - Confirm that your site calls
sendClientTelemetry(externalIds?)after the script loads. Loadingclient.jsonly makes the function available. - Custom IDs are missing - Pass optional
externalIdswhen callingsendClientTelemetry, such asaccountId,orderId, oremail.
NPM package
If your app is built with a bundler, install @cside.dev/device-intelligence instead of pasting the bootstrap above. It loads the same client.js for your team and hands back a typed sendClientTelemetry, so you never reach for window.sendClientTelemetry and never have to guess whether the script has loaded yet.
npm i @cside.dev/device-intelligence
import { initDeviceIntelligence } from "@cside.dev/device-intelligence";
const { sendClientTelemetry } = await initDeviceIntelligence({
teamID: "[your-team-id]",
});
const { token, errors } = await sendClientTelemetry({ accountId: "1234567890" });
initDeviceIntelligence appends <script async referrerpolicy="origin" src="https://[your-team-id].csidefd.com/client.js"> to <head> and resolves once the script has loaded and exposed its telemetry function. Call it as early as your app allows, for the same reason the bootstrap belongs at the top of <head>: the script has to be loading before you need a token.
What it handles for you:
- Repeated calls. Calling it again for the same team joins the load already running instead of adding a second tag, so a React effect that runs twice is harmless. It also picks up a tag that is already on the page, such as one injected by
@cside.dev/viteor@cside.dev/next. - Failure. The promise rejects if the script fails to load, does not load within ten seconds, or loads without exposing its telemetry function. Your page keeps working: wrap the call in
try/catchand continue without a token. - Server-side rendering. Without a
documentit resolves with asendClientTelemetrythat returns{ token: null, errors }rather than throwing, so shared code can call it unguarded.
One page reports for one team. A second call with a different team ID loads nothing and resolves with a sendClientTelemetry that reports the conflict, because the browser script exposes a single telemetry function.
For a Content-Security-Policy, the package exports the script URL so you do not have to hardcode the format:
import { buildDeviceIntelligenceScriptUrl } from "@cside.dev/device-intelligence";
buildDeviceIntelligenceScriptUrl("[your-team-id]"); // https://[your-team-id].csidefd.com/client.js
Allow that host in script-src and https://edge.csidefd.com in connect-src.
@cside.dev/vite and @cside.dev/next inject the script tag at build or render time but give no typed access to sendClientTelemetry. Use @cside.dev/device-intelligence when your app calls the telemetry function itself.
Google Tag Manager
GTM is useful for fast testing, but it does not guarantee that cside loads before other scripts. Use a Custom HTML tag with an All Pages trigger when validating the flow.
For production enforcement or high-confidence data collection, use direct script injection, an NPM package, or Cloudflare Workers.
Cloudflare Workers
Use Cloudflare Workers when traffic already passes through Cloudflare and you want edge-controlled script injection. See the Cloudflare Workers guide.
Thanks for your feedback!