Is LibKey Nomad safe?
LibKey Nomad is low risk. LibKey Nomad generates a permanent device ID on first run. Landing on a page with a DOI, PubMed ID, or ISBN sends that ID plus your device fingerprint to a.thirdiron.com/events, linking every scholarly page you visit to one device.
Who publishes itThird Iron LLC - no other listings under this identity, 15 shared hostnames
Third Iron LLC - no other listings under this identity, 15 shared hostnames
What this publisher told the store about itself, and the other listings that told it the same thing.
Shared hosts - 15 hostnames
Hostnames hardcoded in this extension that few other listings call. That can mean one operator behind both, and it can equally mean a small shared vendor, so it is context rather than a conclusion. Hosts that many listings call are left out: they are services, not connections.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Persistent Device ID Fingerprints You on Every Research Page
LibKey Nomad generates a permanent device ID on first run.
Landing on a page with a DOI, PubMed ID, or ISBN sends that ID plus your device fingerprint to a.thirdiron.com/events, linking every scholarly page you visit to one device.
What actually happens
You visit a page containing a scholarly-article identifier, a DOI, PubMed ID, or ISBN, on any website, not just academic ones.
The extension's content script runs on every http(s) and file:// page, so this can fire anywhere a citation identifier appears.
The extension reads a permanent per-device ID from local storage, creating one on first use, and sends it with your full browser/OS fingerprint to Third Iron's analytics server.
The same device ID is reused on every future event, letting the server link your scholarly browsing across sessions and sites.
Fields included in every analytics event sent to a.thirdiron.com/events
- Permanent device ID7f492ad3-074c-4668-b4b6-3ef745e13040
A UUID generated once and stored forever, letting Third Iron link every event from this browser together indefinitely.
- Full browser user-agent stringMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36
Identifies your exact browser build and OS in one string, narrowing you down within the broader population of visitors.
- Operating systemmacOS 10.15.7
Your OS name and version, sent as separate fields alongside the user-agent string.
- Browser and versionChrome 146.0.0.0
Your browser name and exact version number.
- Device make and modelApple Macintosh
The hardware vendor and model reported by your browser.
- Your institution158 (Arizona State University Library)
The library you selected during onboarding, adding organizational context on top of the persistent device ID.
Captured request
{ "events": [ { "eventCategory": "NomadArticleLinkPresented", "eventType": "PubMed", "os": "macOS", "osVersion": "10.15.7", "deviceMake": "Apple", "deviceModel": "Macintosh", "browser": "Chrome", "browserVersion": "146.0.0.0", "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36", "uniqueDeviceId": "7f492ad3-074c-4668-b4b6-3ef745e13040", "libraryId": 158, "url": "not captured" } ], "token": "QnVvJNPw2LNnqx8b3AF5ecm0ULInX2"}The code that does this
Reading/creating the permanent device ID and attaching it to every analytics event
Deobfuscated: getBackgroundDimensions() / getAnalyticsDimensions()
static/background.jsasync getBackgroundDimensions() { let e = new U(navigator.userAgent).getResult(), t = await this.getStoredUniqueDeviceId(); return t || (t = i(), await this.setStoredUniqueDeviceId(t)), { appName: `Nomad`, appVersion: browser.runtime.getManifest().version, property: bt.PRODUCTION_FOREGROUND, os: e.os.name, osVersion: e.os.version, uniqueDeviceId: t, deviceMake: e.device.vendor, deviceModel: e.device.model, browser: e.browser.name, browserVersion: e.browser.version, userAgent: e.ua, url: `not captured` }}async getAnalyticsDimensions(e, t, n = null) { return { messageType: `analytics`, eventCategory: e, eventType: t, extras: { installType: await this.getStorageData(`installType`), ...await this.getBackgroundDimensions(), ...n } }}Deobfuscated: the analytics client that POSTs the batch with a shared token
static/background.jsyt = function() { function e(e) { this.mDelegate = e, this.mFailedEventQueue = new vt(e) } return e.prototype.getFailedEventCount = function() { return this.mFailedEventQueue.getFailedEventCount() }, e.prototype.sendEvent = function(e) { var t = _t.newEventOutput(this.mDelegate, e); return this.sendEventOutput(t, t.property) }, e.prototype.sendEventOutput = function(e, t) { var n = this.mFailedEventQueue.checkOutFailedEventsQueue(); n.push(e); var r = this.createFinalPayload(n); return this.sendFinalPayload(r, t) }, e.prototype.sendFinalPayload = function(e, t) { var n = this; return new Promise(function(t, r) { var i = JSON.stringify(e); n.mDelegate.postEvent(i, { onSuccess: function() { return t() }, onFailure: function(t) { return n.onEventSendFailed(t, e), r(t) } }) }) }, e.prototype.onEventSendFailed = function(e, t) { this.mDelegate.logError(e.actualError), this.mFailedEventQueue.onEventSendFailed(t.events, e) }, e.prototype.createFinalPayload = function(e) { return { events: e, token: this.mDelegate.getClientToken() } }, e}(),bt;(function(e) { e.PRODUCTION_FOREGROUND = `production_foreground`, e.NON_PRODUCTION_FOREGROUND = `non_production_foreground`})(bt ||= {});var xt = function() { function e() {} return e.getServerUrl = function(t) { switch (t) { case bt.PRODUCTION_FOREGROUND: return e.PRODUCTION_SERVER_URL; case bt.NON_PRODUCTION_FOREGROUND: return e.STAGING_SERVER_URL; default: return e.STAGING_SERVER_URL } }, e.PRODUCTION_SERVER_URL = `https://analytics.thirdiron.com/events`, e.STAGING_SERVER_URL = `https://staging-analytics.thirdiron.com/events`, e.CLIENT_TOKEN = `QnVvJNPw2LNnqx8b3AF5ecm0ULInX2`, e.MAX_OFFLINE_QUEUED_EVENTS = 256, e.DEFAULT_REQUEST_TIMEOUT_MS = 3e4, e }(),Where the fingerprinted analytics events go
- a.thirdiron.com
Production analytics endpoint for Third Iron LLC, LibKey Nomad's developer. Receives the persistent device ID and full browser/OS/device fingerprint on every qualifying page.
- staging-a.thirdiron.com
Staging counterpart of the same analytics endpoint, used when the extension's internal 'useStaging' flag is set.
What it can do
Permissions this extension asks for, as declared in version 1.60.0. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.
Read and change your data on every site you visit
<all_urls>
Store data in your browser
storage
Schedule its own background tasks
alarms
See every page you navigate to, as you navigate to it
webNavigation