Akamai Bot Manager internals Measured notes on the sensor, the payload and the edge

What the sensor collects

Two sources answer this. An environment recorder installed before page scripts says what the sensor actually touched on one clean load, and the recovered string table names everything the build knows how to look for.

Touched in a clean run

Recorded on a desktop Chrome load of a generation 2 property, counting only accesses whose call site is the sensor script:

first seenusesproperty
1110 ms1342navigator.userAgent
1169 ms339window.innerWidth
1169 ms337window.innerHeight
1170 ms329navigator.language
1170 ms975Math.random
1172 ms83navigator.plugins
1175 ms12navigator.webdriver
1176 ms997document.documentElement
1164 ms307Date.now
1680 ms4screen.colorDepth, screen.pixelDepth
2188 ms1canvas.getContext("webgl")
2190 ms2getParameter(37445) after getExtension("WEBGL_debug_renderer_info")
2191 ms2navigator.connection.rtt

Read a handful of times each: maxTouchPoints, hardwareConcurrency (8), deviceMemory (16), productSub, product, onLine, cookieEnabled, doNotTrack, javaEnabled(), devicePixelRatio, the four screen dimensions, document.hidden, and the existence of credentials, bluetooth, storage, mediaDevices, permissions, serviceWorker, webkitTemporaryStorage, speechSynthesis, indexedDB.

storage.setItem("dummy", "test") runs 23 times, which is a write-availability probe rather than persistence.

How it is detected: volume matters as much as value. A patched getter that returns a plausible string is fine; one that is slow, throws after a few hundred calls, or is installed on the instance rather than the prototype, is not. navigator.userAgent is read over a thousand times in a single load.

Listeners

On document: mousemove and touchmove twice each, then touchstart, touchend, touchcancel, click, mousedown, mouseup, pointerdown, pointerup, keydown, keyup, keypress, visibilitychange. On window: deviceorientation, devicemotion, blur, focus.

Each of those handlers feeds counters that end up in the payload as named fields, so an event log and its counters have to move together. Where fields come from names which event drives which field.

Named internals

The build's own vocabulary, recovered from the string table:

buildPostData, calculateFP, getDeviceData, get_telemetry, collectHeadlessSignals, collectSeleniumData, checkIprSignals, calcSynthesisSpeechHash, synthesisSpeechHash, getHeartbeatTimestamp, extractAbckHeartbeatTimestamp, storeWebWideTrackingException, stripProxyFromErrors, setBraveSignal, getStorageUpdates, processAutopostRes, listFunctions, applyFunc, mouseMoveData, deltaTimestamp, totVel, stackLen, webGLVendor, webGLRenderer, webGLInfo, pluginsTest, pluginsLength, navigatorPermissions, navPerm, fpValStr, fpValCalculated, rCFP, powDone, _setPowState, _setIpr, _sdTrace, aprApTimer, aprApInFlight, failedAprApCnt, failedAprApBackoff, lastAprAutopostTS.

powDone and _setPowState next to _abck and bm_sz are why the proof-of-work client is inside the sensor rather than being a separate script.

Plugins are checked by name, not by length

The build carries around thirty legacy plugin names (Shockwave Flash, Chrome PDF Viewer, Silverlight Plug-In, QuickTime Plug-in, Java Applet Plug-in, Widevine Content Decryption Module and more) and looks each one up on the plugin array, emitting the index of each hit. A desktop Chrome emits ,7 for the PDF viewer.

Separately it reports navigator.plugins.length in its own field, and carries browser tells like brave, brave_brws, opera, InstallTrigger and Trident/5.0 through Trident/7.0.

How it is detected: the two plugin fields have to agree. An emptied plugin array drops the length field to 0 and empties the hit list, which no real Chrome does; faking the length without faking named lookup fails the other half.

Proxy-trap awareness

stripProxyFromErrors, and the string at newHandler.<computed> [as apply], are aimed at Proxy-based patching: the script reads error stacks looking for the frame a trap leaves behind.

How it is detected: any instrumentation built on Proxy is visible to this check, including the recorders used to study the script. A run made with a proxy-based recorder is not a clean baseline, and treating it as one poisons every comparison made against it.

Payload vocabulary in the table

Field markers appear verbatim in the string table: ,cpen:, ,loc:, ,s1:, ,uaend,, bat:, cwen:, dm:, fc:, i1:, isc:, non:, opc:, sc:, vib:, wrc:, x11:, x12:, alongside <bpd>, </bpd>, <init/> and the POST body template {"sensor_data":". A run of negative integers from -70 to -134 is the section-code table for the generation 2 plaintext.