Set up Device Intelligence
Choose how to deploy cside Device Intelligence on your website using the npm package, an AI coding assistant, direct script injection, Cloudflare Workers, Framer, or Webflow.
Set up cside Device Intelligence by starting signal collection early, collecting telemetry with sendClientTelemetry, and sending the returned session token to your backend.
Device Intelligence is switched on per team, under Install Device Intelligence in the dashboard. Enabling it requires at least one managed, non-suspended domain and an acknowledgment that the feature collects personal data (PII) from visitors. See Device Intelligence.
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?). The same applies to the npm package: initDeviceIntelligence only starts collection.
Choose an implementation option
The Install Device Intelligence page in the dashboard has five tabs: npm, AI, HTML, Cloudflare, and Framer. npm is the default.
| Method | Best for | Production guidance |
|---|---|---|
| npm package | Apps built with a bundler | Default in the dashboard. Recommended when your app calls sendClientTelemetry itself |
| AI coding assistant | Teams that let Claude Code, Cursor, or a similar assistant do the install | The AI tab gives you a prompt with your team-specific script URL to paste into the assistant |
| Direct script injection (HTML tab) | Sites where you control the HTML or app shell | Uses the fail-open browser bootstrap |
| Cloudflare Workers | Sites already routed through Cloudflare | Good for edge injection and limited-path rollout |
| Framer | No-code Framer sites | Use Custom Code and publish before testing |
| Webflow | No-code Webflow sites | Use Custom code and publish before testing |
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 and open the HTML tab.
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 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. Telemetry is posted to https://edge.csidefd.com/client regardless of where the script is served from, so connect-src needs https://edge.csidefd.com. See Content Security Policy.
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({
userId: "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.
Content Security Policy
Whichever install method you use, the browser posts telemetry to https://edge.csidefd.com/client. Allow that host in connect-src. When you load client.js from a team subdomain or your own first-party domain, also allow that script origin in script-src:
script-src https://[your-team-id].csidefd.com;
connect-src https://edge.csidefd.com;
The npm package loads no remote script, so it only needs the connect-src entry. See Adjusting your CSP for how cside helps you manage the policy.
Troubleshooting
- No Device Intelligence data anywhere - Confirm that Device Intelligence is enabled for the team under Install Device Intelligence. The switch needs at least one managed, non-suspended domain: enabling a team without one succeeds but collects nothing.
- 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 asuserId,orderId, oremail.
NPM package
If your app is built with a bundler, install @cside.dev/device-intelligence instead of pasting the bootstrap above. This is the default method in the cside dashboard’s Device Intelligence setup. The collection code is bundled into the package, so there is no remote script to load, and it hands back a typed sendClientTelemetry, so you never reach for window.sendClientTelemetry and never have to guess whether a 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({ userId: "1234567890" });
initDeviceIntelligence starts passive signal collection and behavior tracking as soon as it is called, so a later sendClientTelemetry call only has the per-call probes left to run. Call it as early as your app allows, for the same reason the bootstrap belongs at the top of <head>: collection has to be running before you need a token.
What it handles for you:
- Repeated calls. Collection only starts once per page, and every call resolves with the same
sendClientTelemetry, so a React effect that runs twice (including under StrictMode) is harmless. - Failure.
sendClientTelemetrynever rejects: when telemetry could not be collected it resolves with{ token: null, errors }. Readerrors, continue without a token, and keep your page working.initDeviceIntelligenceitself only rejects, with aTypeError, whenteamIDis missing or empty. - Server-side rendering. The package can be imported wherever a server renderer or edge runtime evaluates client code: its
exportsmap points thereact-server,edge-light,workerd,workerandnodeconditions at a small server entry with the same API. There,initDeviceIntelligenceresolves with asendClientTelemetrythat returns{ token: null, errors }, so shared code can call it unguarded.
For a Content-Security-Policy, the package posts telemetry to the cside edge and loads no script from a team subdomain, so the only entry it needs is:
connect-src https://edge.csidefd.com;
AI coding assistant
The AI tab on the Install Device Intelligence page generates a prompt that points your assistant (Claude Code, Cursor, and similar tools) at this guide and includes your team-specific script URL. Paste it into the assistant and review the result: the assistant should use the npm package or the fail-open bootstrap above, never a bare <script src=".../client.js"> tag.
Cloudflare Workers
Use Cloudflare Workers when traffic already passes through Cloudflare and you want edge-controlled script injection. See the Cloudflare Workers guide.
Framer
Use the Framer tab, or the Framer guide, when your site is built with Framer. It uses the same fail-open bootstrap in Framer Custom Code.
Thanks for your feedback!