Is LeadContact safe?
LeadContact sends the URL of every page you visit to its own servers once you enable its 'browse everywhere' feature.
When a user opts into LeadContact's site-wide floating button, the extension registers a content script that runs on every website and sends the full URL of each page visited to api.leadcontact.ai, along with the user's session cookie, framed as a lookup for whether the button should be shown. Separately, on install and when that feature is enabled, the extension computes a persistent browser fingerprint (from canvas, WebGL, audio, fonts, and hardware signals, with a fallback fingerprint designed to survive anti-fingerprinting defenses) and sends it to LeadContact's tracking endpoint together with the session cookie.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Opt-in 'browse everywhere' mode reports every page URL to LeadContact
Code analysis shows that once you enable LeadContact's all-sites feature, a content script it installs on every website sends the page's full URL to LeadContact's own server on each page load, framed as a preference lookup.
You turn on LeadContact's all-sites feature and accept Chrome's all-sites permission prompt.
A script the extension runs on every site you visit reads the page's full address and sends it to LeadContact's server.
The script skips google.com, linkedin.com, leadcontact.ai and roughly ninety government, financial and policy-institute domains; every other site's address is sent.
Sitewide permission grant and content-script registration
async function enableAllSites() {
try {
if (!await chrome.permissions.request({ origins: ["*://*/*"] })) return false;
await chrome.storage.local.set({ AllSitesEnabled: true });
logEvent({ name: "ServiceEnableAllSites" });
const already = (await chrome.scripting.getRegisteredContentScripts())
.find(s => s.id === "sidebar");
if (!already) {
await chrome.scripting.registerContentScripts([{
id: "sidebar",
js: ["src/content-script/sidebar.js"],
matches: ["*://*/*"],
runAt: "document_idle",
}]);
}
} catch (e) { console.error("enableAllSites error:", e); return false; }
}async function onPageLoad() {
if (isSkipListHost(["google", "leadcontact.ai", "linkedin.com"])
|| await isForbiddenDomain(window.location.hostname)) return;
const currentUrl = window.top?.location.href || document.URL;
// Always: report the URL to check the account's login state
await checkLoginState(currentUrl); // POST /api/auth/check_login { targetUrl }
let preference = { floatBallVisible: true };
if (cache.get("logged")) {
// Logged in: also look up the per-page preference
const { code, data } = await getUserPreference({ targetUrl: currentUrl });
// POST https://api.leadcontact.ai/api/user/preference { targetUrl, ... }
if (code === SUCCESS) preference = data;
}
if (preference.floatBallVisible === false) return;
showFloatingButton();
}| Field | Value | Why it matters | |
|---|---|---|---|
Page address | https://www.example.com/account/billing?invoice=48213 | The full address of the page you're viewing, including its path and query string. | |
Account session | connect.sid=s%3AaB12cD34eF56... | Your LeadContact login session cookie, attached automatically to the request. | |
Extension ID and version | cgfkgghhfpkdodlnkcbpabbghkkacdco / 1.2.9 | Identifies which build of the extension made the request. | |
Browser language | en-US | Your browser's interface language setting. | |
Browser and OS string | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 | Your browser and operating system version. |
- api.leadcontact.ai
Receives the address of every site you visit, except a built-in skip list, to decide whether to show the extension's floating button.
Rebuilds the JSON body LeadContact's own code sends to api.leadcontact.ai from a page address, so you can compare it against what your browser's Network tab captures.
// Reproduces the request body built by content-script/sidebar.js's
// ur()/f1()/kI() helpers for a given page URL.
function buildRequestBody(pageUrl, opts = {}) {
return {
userAgent: opts.userAgent || (typeof navigator !== "undefined" ? navigator.userAgent : "<your UA>"),
locale: opts.locale || "en-US",
extId: opts.extId || "cgfkgghhfpkdodlnkcbpabbghkkacdco",
version: opts.version || "1.2.9",
targetUrl: pageUrl,
};
}
const body = buildRequestBody("https://www.example.com/account/billing?invoice=48213");
console.log("POST https://api.leadcontact.ai/api/user/preference");
console.log(JSON.stringify(body, null, 2));
- 1Save and run `node leadcontact-request-reproducer.js`.
- 2Enable LeadContact's all-sites feature, open DevTools Network tab, filter leadcontact.ai, visit any site.
- 3Compare bodies.
Static analysis finding. This behaviour was identified by reading the shipped extension code and has not yet been reproduced in a live run. The trigger conditions and the exact data sent are read from the code, not from an observed capture.