Is Mendeley Web Importer safe?

Medium risk

Mendeley Web Importer sends analytics with your IP address and device fingerprint to New Relic, Adobe Analytics, and Mendeley.

When you use the extension to import academic articles, it collects telemetry that includes your public IP address (fetched from api.ipify.org), screen resolution, browser language, timezone, and the URL of the page you are viewing. These details are transmitted to three third-party analytics endpoints: Elsevier's Adobe Analytics (elsevier.sc.omtrdc.net), New Relic (insights-collector.newrelic.com), and Mendeley's own backend (brxt.mendeley.com). The IP is cached for 60 minutes and included in events fired on common actions such as opening the extension, scraping article metadata, and downloading PDFs.

Mendeleyv3.2.78Firefox Add-ons
45Risk

AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.

Publishers can request a review.

Findings

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI SANDBOX

Mendeley sends device analytics to New Relic and Adobe

Mendeley Web Importer builds analytics events when you open or use it, including browser, screen, language, time zone, tab URL, account, and IP when available.

It sends batched JSON to New Relic and maps fields into Adobe XML requests.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You open Mendeley Web Importer or use one of its import, login, PDF, or download features.

The extension did this

The extension builds an analytics event with device, browser, session, account, institution, IP, and tab context when those values are available.

02EvidenceFIELD TABLE
Fields assembled before analytics transmission
FieldValueWhy it matters
Action name
EXTENSION_LAUNCHEDThis tells the analytics service which extension action happened.
Browser and operating system
Firefox 128 on LinuxThis identifies your browser family, version, and operating-system family for the event.
Language and time zone
en-US, UTC offset -240This adds locale and time-zone context that can narrow where and how you use the browser.
Screen size
1920x1080This records your display dimensions as part of the event context.
Cookie support
trueThis records whether your browser reports cookies as enabled.
Extension version and ID
3.2.78, webapps@mendeley.comThis ties the event to the installed extension build and browser extension identifier.
Session ID
7d4a5c68-1c5e-4ac6-9f07-4f6b8fd3e318This lets events from the same browser session be grouped together.
Tab URL and hostname
https://pubmed.ncbi.nlm.nih.gov/37200000/This can reveal the page associated with the extension action.
Account and institution
userId 1234567, institution Example UniversityWhen you are signed in, this can associate the event with your Mendeley account and institution.
IP address
198.51.100.24 (illustrative)This can identify the network used when the analytics event is sent.
03EvidenceNETWORK CAPTURE
Captured request
POSThttps://insights-collector.newrelic.com/v1/accounts/67651/events
The verification evidence records the POST target and header; no request body or response body was recorded for this claim.
Headers
Content-Typeapplication/json
X-Insert-Key<redacted>
04EvidenceCODE COMPARE
The code that does this

The analytics builder and senders in background.js

What it actually does
New Relic queue and POST senderdeobfuscated/background.js
const newRelicUrl = N.newrelic_insights_url;
const newRelicInsertKey = N.newrelic_insights_apikey;
const normalizeFields = event => Object.fromEntries(
  Object.entries(event)
    .filter(([, value]) => value !== undefined)
    .map(([key, value]) => typeof value === "boolean" ? [key, String(value)] : [key, value])
);
const queuedEvents = new Set;
function Bs(actionName, fields = {}) {
  queuedEvents.add({
    appName: "brxt-extension",
    eventType: "PageAction",
    actionName,
    ...normalizeFields(fields)
  });
  if (Us === null) Us = setTimeout(js, 1000);
}
let Us = null;
async function js() {
  Us = null;
  fetch(newRelicUrl, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Insert-Key": newRelicInsertKey
    },
    body: JSON.stringify([...queuedEvents])
  });
  queuedEvents.clear();
}
Event context builderdeobfuscated/background.js
const analyticsClients = [e, n, t];
const Ys = (...args) => {
  try {
    (function(actionName, eventData = {}, context = {}) {
      const parsedUa = Is().parse(window.navigator.userAgent);
      const event = {
        ...eventData,
        ...context,
        extensionVersion: f.client_version,
        extensionBuildTarget: f.target_platform,
        userAgent: navigator.userAgent,
        userAgentName: parsedUa.browser.name,
        userAgentVersion: parsedUa.browser.version,
        userAgentOsName: parsedUa.os.name,
        userAgentOsVersion: parsedUa.os.version,
        userAgentOsVersionName: parsedUa.os.versionName,
        language: navigator.language,
        cookiesEnabled: navigator.cookieEnabled,
        timestamp: Date.now(),
        timezone: (new Date).getTimezoneOffset(),
        extensionId: o().runtime.id,
        height: window.screen.height,
        width: window.screen.width,
        sessionId: F()
      };
      analyticsClients.forEach(client => client.logEvent(actionName, event));
    })(...args);
  } catch (error) {
    console.error(error);
  }
};
Tab, account, institution, IP, and session contextdeobfuscated/background.js
const $c = tab => {
  if (tab && tab.url) {
    return {
      tabUrl: tab.url,
      tabHostname: new URL(tab.url).hostname,
      tabIncognito: tab.incognito
    };
  }
};
const Wc = state => {
  const timeSinceLaunched = Date.now() - state.launched;
  const timeSinceLoaded = state.loaded ? Date.now() - state.loaded : void 0;
  const oneHour = 36e5;
  const userInfo = rl.possiblyStale({ refreshIfOlderThan: oneHour });
  const userProfileUuid = userInfo == null ? void 0 : userInfo.mendeleyId;
  const analyticsInfo = userInfo == null ? void 0 : userInfo.analyticsInfo;
  const userId = analyticsInfo == null ? void 0 : analyticsInfo.userId;
  const institutionId = analyticsInfo == null ? void 0 : analyticsInfo.accountId;
  const institutionName = analyticsInfo == null ? void 0 : analyticsInfo.accountName;
  const accessType = analyticsInfo == null ? void 0 : analyticsInfo.accessType;
  const ipAddress = Rs.possiblyStale({ refreshIfOlderThan: oneHour });
  const sessionId = F();
  return {
    ...$c(state.tab),
    accessType,
    institutionId,
    institutionName,
    ipAddress,
    timeSinceLaunched,
    timeSinceLoaded,
    userId,
    userProfileUuid,
    sessionId
  };
};
Popup launch triggerdeobfuscated/background.js
const tl = async tab => {
  const state = Yc(tab);
  state.launched || (state.launched = Date.now());
  Xs(tab);
  Ys("EXTENSION_LAUNCHED", void 0, Wc(state));
};
o().browserAction.onClicked.addListener(tl);
Adobe Analytics XML senderdeobfuscated/background.js
function As(actionName, fields) {
  const adobePageFields = vs[actionName];
  if (!adobePageFields) return;
  if (actionName === "ADD_REF_TO_LIBRARY") {
    adobePageFields.events = fields.addReferenceSuccess ? "event79" : "event26";
  }
  const body = function(event) {
    const {
      accessType, cookiesEnabled, errorMessage, events, height, institutionId,
      institutionName, ipAddress, language, linkName, linkType, page, pageName,
      pageType, products, timestamp, timezone, userAgent, userId, width
    } = event;
    const xmlFields = {
      connectionType: "LAN",
      cookiesEnabled,
      evar7: institutionName,
      evar16: institutionId,
      evar29: userId,
      evar33: accessType,
      evar43: errorMessage,
      events,
      ipAddress,
      language,
      linkName,
      linkType,
      page,
      pageName,
      products,
      resolution: width && height ? `${width}x${height}` : "",
      timestamp,
      timezone,
      userAgent
    };
    return `<?xml version="1.0" encoding="UTF-8"?>\n<request>${
      "\n" + Object.entries(xmlFields)
        .map(([key, value]) => value ? `  <${key}>${value}</${key}>\n` : "")
        .join("")
    }</request>\n`;
  }({ ...fields, ...adobePageFields });
  fetch("https://elsevier.sc.omtrdc.net/b/ss//6", {
    method: "POST",
    headers: { "Content-Type": "text/xml" },
    body
  }).catch();
}
05EvidenceTHIRD PARTY LIST
Network destinations used by this analytics path
  • insights-collector.newrelic.com

    Receives batched JSON PageAction analytics events through the New Relic Insights endpoint.

  • elsevier.sc.omtrdc.net

    Receives Adobe Analytics XML requests built from the same event fields.

  • api.ipify.org

    Supplies the public IP address that Wc can add to later analytics event context.

Data recipients

elsevier.sc.omtrdc.netinsights-collector.newrelic.combrxt.mendeley.comapi.ipify.org
Updated 17 September 2026amo-2614372