CreepJS Math Signals: Read the Source Fields
Trace CreepJS Math results, browser reference flags, repeated-call checks and lie state without treating source labels as live browser evidence.
BotBrowser Team
Want the structured docs for Fingerprint?
This article lives in the editorial library. For step-by-step setup, reference material, and ongoing updates, jump into the docs section.
A CreepJS Math report contains several values that answer different questions. The returned numeric result comes from an expression. Browser-family booleans compare that result with constants embedded in the pinned source. A repeated-call check asks whether the same invocation is stable, while lieProps contributes an inherited concern. Reading those fields as one score turns source metadata into a claim the collector never makes. BotBrowser can document and review fingerprint surfaces in a controlled profile; it cannot decide how a third-party CreepJS revision labels a result.
TL;DR
- The pinned
src/math/index.tsruns a fixed list of functions and stores each output under its expression label. chrome,firefox,torBrowserandsafariare comparisons with source-declared reference values, not measurements of the current browser family.- The first pass repeats selected calls and marks a mismatch; this is separate from the inherited
lieProps.Math.*state. - A missing or blocked value identifies an output path, not a person, device or bot verdict.
- Source review is reproducible only when the commit, file and line range are recorded.
Contents
- The pinned source and its inputs
- Four kinds of Math output
- Missing, blocked and inherited states
- A provenance matrix for review
- FAQ: CreepJS Math fields
- Practical conclusion
The pinned source and its inputs
The relevant public revision is 10aa6724cd33a1015db1574211890518cd04f0cc. In src/math/index.ts, the check list names 23 Math methods, including acos, cos, hypot, sin, sqrt and pow. The first loop reads lieProps[Math.<method>], invokes the function with a fixed argument list, and compares the two calls. Two NaN values count as matching; other values use equality. A mismatch sets the module's local lied variable and calls the lie recorder.
The second table is different. It contains source expressions such as cos(Math.PI) and pow(Math.SQRT2, -100). Each row stores one expected value and optional values associated with the labels chrome, firefox, torBrowser and safari. The source therefore declares a mapping from an expression to reference slots. It does not say that a live request has been run in each of those browsers, and it does not expose the revision or operating system that produced each constant.
The table is not a uniform sample of every function. Some methods have one row and others have many. cos includes large magnitudes and constants such as Math.E and Math.LN2; hypot includes two- and six-argument calls; pow uses several bases with exponent -100. A report consumer who groups every row under one generic “Math score” loses the input shape that determines what is being compared. The expression is part of the evidence, not just a label for a metric.
The top-level repeatability list and the reference table also use different argument sets. The first list uses a small chosen input for each function, while the second list may use other constants and magnitudes. For example, the first cos repeatability call uses 1e308, while the reference rows include 0.123, Math.PI and other expressions. Passing the repeated-call check says nothing about whether the later reference expression equals a stored constant. Keep both tests in separate rows in any downstream explanation.
The ECMAScript Math object remains the authority for the operation's language semantics. It does not turn CreepJS's reference slots into a current compatibility guarantee. A value can be valid under the specification and still fail to equal one historical constant because the input, implementation, or rounding path differs. Keep the expression, argument and source revision beside any interpretation.
Four kinds of Math output
The returned data object uses the expression text as a key. Its value is produced by attempt(). For a normal row, result is the computed value and the four browser labels are booleans. They answer “does this result equal this source slot?” They do not answer “which browser is this?” A result that matches two slots, no slots, or a slot whose provenance is unknown cannot be converted into a browser identity.
The local equality pass is a separate signal. It executes the same selected function twice with the same arguments before the reference table is processed. A mismatch can indicate that the invocation was not stable for that source's check, but the code does not explain why. It could reflect a modified function, a transient failure or an input problem. The right record is the method, arguments, two observed values if available, and the pinned source path; a single lied boolean loses that detail.
The inherited Math lie state is read from lieProps, which is maintained by the separate lies module. The source also has a generic Math scan in src/lies/index.ts. That scan and the expression table are related because both can affect interpretation, but they are not the same producer. A report reviewer should keep “the method was already marked” separate from “the two calls disagreed” and from “the result matched a reference slot.”
The JavaScript Math consistency guide explains specification latitude and application-level tolerances; this page answers the separate question of where CreepJS obtains its Math fields. For a broader detector context, CreepJS signal groups and lies describes how grouped outputs and generic function checks should be bounded. These links support different reading tasks rather than treating a source field as a verdict.
| Field or branch | Producer in the pinned source | Safe reading | Not established |
|---|---|---|---|
result | Math[fn] or the polyfill expression | The value returned for the listed input | Device or person identity |
chrome / firefox / torBrowser / safari | Equality with a row's reference slot | A source-label comparison | Current browser family or version |
local lied | lieProps plus repeated-call mismatch | An inherited or local concern was recorded | Why a value changed or who changed it |
undefined from attempt | A callback threw or was unavailable | This callback has no returned value | The exact failure cause |
| absent module result | Outer collector error path | The module did not return its normal object | That every Math API is missing |
Why individual rows matter
The method list is a source inventory, not a recommendation to reproduce all values in a production collector. It contains 23 names: acos, acosh, asin, asinh, atan, atanh, atan2, cbrt, cos, cosh, expm1, exp, hypot, log, log1p, log10, sin, sinh, sqrt, tan, tanh and pow. Recording the method name lets a maintainer connect an observed difference with the operation's specification and its exact arguments.
The arguments expose which numerical edge a row exercises. cos(1e308) stresses argument reduction for a very large input; atanh(0.5) uses an interior value; atan2(1e-310, 2) uses a very small component; and hypot(1, 2, 3, 4, 5, 6) supplies more than two operands. These examples do not reveal why one implementation has a particular result. They only identify the cases chosen by that source revision. A diagnosis still needs a controlled reproduction with the same browser build and application context.
Several source constants are intentionally close rather than identical. For example, the listed atan(2) value is 1.1071487177940904, while another optional reference is 1.1071487177940906. That difference occupies the last represented digits. It is not a universal tolerance specification, and it must not be turned into one. The ECMAScript operation and the application requirement determine whether exact comparison, a tolerance or a domain-level assertion is appropriate.
The table also distinguishes expected values from missing optional slots. A NaN placeholder in a source array means that this revision does not provide a numeric reference for that slot in that row; it is not an observed NaN result from a live Firefox, Tor Browser or Safari run. A comparison helper treats a false or absent reference as nonmatching. Readers should therefore report “no source reference in this row” rather than “this browser returned NaN.”
The collector's rendered HTML can expose a shortened hash and a lied state, but the hash is a presentation choice. It is not a cryptographic proof that two browser sessions belong to the same user. A display hash can also hide which expression differs unless the underlying report is examined. For support, retain the source revision and the smallest relevant row instead of a whole fingerprint string.
The helper that builds the expression map also matters when reading exceptional cases. Each key is created from the human-readable expression stored beside the function and argument tuple. The function is invoked inside attempt(), and its output is compared against the row's reference columns. If a source edit changes the expression label but leaves the calculation unchanged, a downstream diff may look like a removed and added test rather than one renamed row. Include both the expression key and the source commit in a review record so that a label change is not confused with a changed mathematical result.
The fixed inputs are also not a random sample of real page workloads. The list includes constants, large values, small values and composed expressions chosen by the collector author. It does not report an application's workload distribution, expected precision, frequency of a call, or user-facing effect. A compatibility issue should be reduced to a minimal input that reproduces a visible product defect, then checked against the relevant ECMAScript clause. A detector's sample list is useful for understanding that detector's source, not for replacing an application's own acceptance tests.
There is another limit on cross-version reading: the reference values are part of a commit, while the browser and host runtime used to generate them are not encoded beside every row. A later revision could update constants, add expressions or change the comparison operation. Before comparing screenshots or exported JSON from two dates, diff the collector source and its helper implementation. Otherwise a detector update can be mistaken for a browser change. The source revision is therefore a required comparison field, not optional citation decoration.
Finally, the names of the reference columns are categories selected by the source. They do not identify the compiler, math library, operating system, architecture or exact release behind a number. If an analysis needs those dimensions, it requires independently documented build metadata. Do not infer unrecorded provenance from familiar browser names, and do not combine them with user account data to make an identity claim. The correct outcome when the provenance is absent is “not specified by this source.”
Missing, blocked and inherited states
attempt() converts a callback exception into an unavailable value. That means an undefined cell can result from a thrown operation, an unavailable method, or another callback boundary. The visible cell does not retain the exception category. Do not fill it with a guessed browser label. Preserve the method name and source line, then classify the cause only if a separate record supports it.
The outer getMaths() function has another try/catch. If an error escapes the row callback, the module logs an unsuccessful test and returns without the normal data object. This is not equivalent to one row being unavailable. A renderer that displays a blocked card can therefore represent module-level absence, a missing field, or an inherited display decision. The page must keep those states distinct.
The pinned source's browser labels are also historical source data. They are useful for explaining what the collector compares, but they are not a benchmark. A current Chromium build, a profile setting, or a different CreepJS commit may produce a different result while remaining within the language specification. The JavaScript Math consistency guide covers application tolerances and operation-specific rules; it should be read before turning a numeric difference into a compatibility bug.
A provenance matrix for review
Use the following matrix when reviewing a report. It is intentionally source-oriented and can be copied into a ticket without storing a complete fingerprint.
| Review row | Record | Choice rule |
|---|---|---|
| Source identity | commit 10aa6724…, file and line range | Reject an interpretation that cannot name the producer |
| Expression input | expression label and arguments | Compare only identical inputs and options |
| Computed output | result, undefined, or absent module | Preserve unknown instead of inferring a cause |
| Reference comparison | which family booleans are true | Describe a source-slot match, never a family identity |
| Equality check | method and whether repeated calls matched | Keep this separate from reference matching |
| Lie provenance | inherited lieProps or local mismatch | Name the path; do not collapse it into a score |
| Retention | ticket identifier and deletion date | Store the smallest evidence needed for the support decision |
Keep separate records for separate source paths. The reference row for cos(Math.PI) is result=-1 with the corresponding family-slot booleans at source line 86; it does not include a repeat result. The repeated-call check uses cos(1e308) at source lines 42-49, so record its two call results independently before deriving repeatMatch. lieProps.Math is a collection of present lie keys, not a source-shaped Math.cos=false value; absence is not a recorded false. None of these rows identifies a visitor's browser or predicts an external service decision.
When two reports differ, compare them in this order: first pin the same CreepJS commit; next match the expression key and arguments; then compare the raw result; then inspect which reference booleans were generated; finally check whether the separate lied property was inherited or set by a repeat mismatch. If the commit or input differs, the reports are not a controlled comparison. If the source and input match but the result differs, the difference is still only a numeric observation until an application requirement or specification clause explains its significance.
This order avoids two common category errors. A reference boolean is not an independent detector vote: it is derived from the same result value. A lied flag is not a second numerical reference: its code path reads other state or compares repeat calls. Counting these fields as three independent confirmations exaggerates the evidence. The artifact should preserve dependency relationships as well as values.
For reproducibility, a review record needs only the public revision, source line, expression, argument list, available result, comparison flags and missing-state marker. Do not attach account identifiers, cookies, full browsing history or unrelated API values. If a support ticket needs a browser build, record that build separately from the source's family labels. Retain the record only for the support purpose and remove it according to the team's documented retention period.
The matrix also prevents a common review error: copying a displayed browser name into a database field called browserFamily. The source label is a comparison column, not an identity assertion. If an application needs a compatibility decision, use the documented API and a task-specific acceptance rule. Do not make a CreepJS report the authority for authentication, risk scoring or access control.
BotBrowser's fingerprint privacy documentation is useful for separating a browser capability review from a detector verdict. Profile controls can help make an authorized comparison repeatable, but they cannot control an external collector's source revision or guarantee its classification. Keep profile configuration, source inspection and application outcome as three distinct records.
FAQ: CreepJS Math fields
Do the chrome and firefox fields identify the browser?
No. They report equality with constants stored in the pinned source. Multiple fields, no fields or a changed source revision can produce different combinations without proving a current browser family.
Is lied: true the same as a failed Math test?
No. The module combines inherited lieProps concerns with selected repeated-call mismatches. A row can be stable while an inherited property is already marked, and a missing row can avoid both checks.
Can undefined explain which API failed?
No. The callback wrapper intentionally returns an unavailable value after an exception. The row name and a separate diagnostic are needed to distinguish a throw, an absent method and another boundary.
Is the reference table a cross-browser benchmark?
No. It is source-declared comparison data. It has no claim that every constant was captured on a current release or identical operating system.
Practical conclusion
Pin the CreepJS commit, record the expression and arguments, and keep result, reference booleans, repeat equality and lie provenance in separate fields. Treat blocked and missing paths as unknown. That workflow makes a public detector report auditable without turning a source label into an identity or security verdict. When per-signal results appear together, the CreepJS prediction aggregation analysis traces candidate reduction and renderer states without treating them as identity.
Public sources
This article is part of the guide: What Is a Browser Fingerprint?
Related Articles
CreepJS Intl Report: Fields and Missing Values
FingerprintCreepJS Audio Reports: Rendering and Missing Values
FingerprintCreepJS WebGL Report: Contexts and Capability Signals
FingerprintCreepJS Android WebView Detection: Signal Limits
FingerprintCreepJS Prediction Report: Aggregation and Unknown States
FingerprintBrowserLeaks WebGL Report: Collection and Missing States
Take BotBrowser from research to production
The guides cover the model first, then move into cross-platform validation, isolated contexts, and scale-ready browser deployment.