Back to Knowledge Hub
Fingerprint

CreepJS Emoji Metrics: What Sets and Sums Reveal

Read CreepJS emojiSet and textMetricsSystemSum from pinned source. Separate representative metrics, lossy aggregation and field inclusion from OS identity.

BotBrowser Team

Documentation

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.

CreepJS emoji metrics describe text geometry and how the library groups it. The names emojiSet and textMetricsSystemSum do not turn those measurements into an operating-system certificate. BotBrowser documents profile-backed fonts and emoji fallback, but it does not promise identical values for every text metric or establish an OS from a CreepJS summary.

The relevant evidence is public source at revision 10aa6724cd33a1015db1574211890518cd04f0cc, inspected on 2026-11-02. The cited canvas block selects representatives and calculates a sum; the cited assembly block decides which fields to retain. Neither block assigns an OS label. This is source interpretation, not an executed browser comparison or a claim about every inference elsewhere in CreepJS.

TL;DR

  • emojiSet retains the first emoji encountered for each distinct tuple of seven text metrics. It is not a complete emoji-support list.
  • textMetricsSystemSum aggregates unique metric tuples, rather than weighting each input emoji separately. The summary loses information.
  • The result assembler checks lied for pixel fields and liedTextMetrics separately for metric fields. Absence needs branch context.
  • Equal geometry does not establish equal pixels, the same font file or the same OS. An OS classifier would need additional evidence outside these blocks.
  • Compare source revision, metric membership and inclusion stage before comparing summaries. Keep raw fingerprint material out of routine support records.

Contents

Five source stages: measureText produces seven metrics, pattern keeps distinct tuples, emojiSet selects representatives, textMetricsSystemSum summarizes unique tuples, and liedTextMetrics controls inclusion. No stage in these blocks assigns an OS label.

Seven metrics describe geometry

The measured object is not an image

The pinned CreepJS canvas source calls context.measureText(emoji) and reads seven properties: actualBoundingBoxAscent, actualBoundingBoxDescent, actualBoundingBoxLeft, actualBoundingBoxRight, fontBoundingBoxAscent, fontBoundingBoxDescent and width. It joins those values into a tuple representation. That tuple, not the emoji's painted image, becomes the deduplication key.

MDN's measureText reference describes a returned TextMetrics object. The TextMetrics reference distinguishes advance width from bounding-box measurements and describes their CSS-pixel units. Consequently, matching width alone is weaker than matching all seven selected properties. Neither comparison includes the individual colors or edge pixels of a rendered glyph.

The distinction matters when two reports say that an emoji “matches.” One may mean equal width; another may mean the selected tuple is equal; a third may compare a rendered image. Those are different comparisons with different inputs. The text-measurement fingerprinting explanation separates geometry from raster output and font-loading state. An equality claim should name the layer instead of allowing an image conclusion to inherit a metric result.

Font matching is a separate dependency

The CSS Fonts matching specification describes font selection and fallback. A requested family name is not, by itself, proof that every character came from one font file. The geometry obtained through measureText() is therefore not a file inventory. Comparing metric tuples cannot recover an unrecorded font-selection path merely because a family name appeared in a canvas setting.

Unicode's emoji specification distinguishes text and emoji presentation requests. Presentation and fallback are relevant context, but the selected TextMetrics properties are still measurements of the resulting text layout. A support note should not replace the actual input sequence with a screenshot that happens to look similar: visual resemblance does not preserve the original presentation request.

Representatives are not a support inventory

Selection follows the tuple, not a support verdict

In src/canvas/index.ts:369-394, CreepJS maintains a pattern set. An emoji enters emojiSet only when its dimensions tuple has not appeared in that set. If a later input yields an already-seen tuple, it adds no new representative. Its omission from emojiSet is compatible with successful measurement; no unsupported-glyph verdict is required by that branch.

A hypothetical grouping makes the consequence explicit. Suppose two different input strings produce the same selected geometry, and another produces a different tuple. The representatives retain one member from the first group and one from the second. That does not establish that the discarded member was unavailable, nor that the retained members identify two font files. The grouping rule concerns equality of selected properties only.

Order also has a limited but important role. Because emojiSet receives the first encountered member of each new pattern, changing input order can change the representative chosen for a group even if the collection of unique tuples stays unchanged. A representative-list difference is therefore not sufficient evidence of an environment change. First establish that the source revision and input sequence are comparable.

A source-to-claim matrix

The following matrix is an interpretation aid, not browser output. Each row names the maximum conclusion supplied by that stage; a later classifier cannot be attributed to an earlier stage simply because it consumes the stage's data.

StageSource operationProduced objectSupported interpretationUnsupported shortcut
MeasurementRead seven TextMetrics propertiesA geometry tupleSelected text geometryOS identity
DeduplicationAdd unseen tuples to patternDistinct patternsDifferent selected measurementsDifferent font files
Representative selectionKeep the first member of each patternemojiSetRepresentatives of metric groupsComplete emoji support
AggregationSummarize the unique tuplestextMetricsSystemSumA lossy metric summaryReversible device identity
Result assemblyCheck liedTextMetrics separatelyIncluded metric fieldsA source-specific inclusion decisionAn external service's verdict

This choice rule resolves a common reporting mistake: count neither emojiSet members as installed fonts nor absent members as failed glyphs. If the question concerns a user's unreadable message, a metric-group count does not answer whether the intended sequence is displayed correctly. Inspect the user-visible rendering problem in an authorized application instead of treating a fingerprint field as a glyph-support test.

A sum discards the structure it summarizes

Unique groups, not frequency weights

The aggregation at src/canvas/index.ts:396-399 iterates over pattern, the set of unique tuple representations. Repeated inputs that yield an existing tuple do not contribute another copy to this stage. Consequently, the total is not a measurement of how frequently the input collection used a particular geometry. An interpretation that assumes every original input contributes equally describes a different algorithm.

The conversion and reduction also compress several distinctions. The published implementation converts tuple components to numbers and uses a zero fallback for falsey numeric conversions before adding them. A result that reaches the summary does not prove that every selected property was present with a nonzero finite value. Raw property availability and the numeric summary are separate facts; the latter cannot reconstruct the former.

Summation loses the arrangement of component values. Different tuples can have the same total, and different collections of tuples can share an aggregate. This is an information-loss argument about addition, not an observed collision rate or a measured browser population. No uniqueness percentage, identification confidence or operating-system accuracy follows from the sum's existence.

Pixel generation follows another path

The canvas module also produces rendered data, but textMetricsSystemSum is not a digest of every pixel in an emoji image. A metric comparison and a pixel comparison should therefore keep separate result names. A report that labels both “canvas matched” cannot tell a layout equality from a raster equality, even when the underlying collector originally retained the distinction.

The CreepJS canvas seed analysis addresses deterministic drawing requests and their relationship to rendered output. It does not replace the metric-grouping question: a known drawing sequence does not determine which text tuples collapse together. Conversely, equal representative geometry does not establish that the drawing requests, image output or later aggregation pipeline were identical.

For an authorized compatibility comparison, preserve the actual question. If the incident is unexpected line wrapping, width and layout context are relevant. If it is an unreadable emoji, visible glyph rendering matters. An aggregate can flag a report difference without explaining either user-facing failure. Replacing the incident with a fingerprint score would discard the evidence needed to fix the application.

Pixel and metric fields have separate gates

Inclusion is not one canvas-wide switch

The pinned result assembly first returns without a result when the incoming canvas2d module result is absent. For an available module result, it handles two conditions independently. The !lied branch includes dataURI, paintURI, textURI and emojiURI. The !liedTextMetrics branch includes textMetricsSystemSum and emojiSet.

JavaScript negation matters here: both !lied and !liedTextMetrics admit any falsey value, not only the literal boolean false. The source describes inclusion conditions; it does not justify translating an absent flag into a completed validation run. Likewise, the labels lied and liedTextMetrics are library identifiers, not findings about a person's honesty or intent.

The second branch preserves any data assembled by the first branch or starts a new object when that earlier data is absent. Metric fields can therefore be included even when the pixel branch did not populate its fields. An exporter that combines those cases into a single “canvas rejected” label erases a distinction present in the cited source.

Omitted fields need the surrounding record

Available evidenceBounded interpretationEvidence still missing
No incoming canvas2d resultThis assembly block returns without that module resultWhy the module result is absent
Pixel branch withheld, metric branch includedThese two groups are handled independentlyAny OS classification or pixel comparison
Module result exists, metric condition does not admit fieldsMetric inclusion was withheld at this stageWhether a later export also transformed data
A downloaded report lacks emojiSetThe inspected report has no visible fieldThe module result, inclusion branch and export history

These rows are source-based cases, not reproduced executions. In particular, the absence of emojiSet in a downloaded report cannot select the third row unless the module result and branch state are available. Export filtering, schema changes and an unavailable module result remain distinct possibilities. Assign the observation at the layer actually inspected rather than inferring an earlier event from a final blank field.

Report comparisons need provenance

A source revision is part of the comparison

Record the fixed CreepJS revision beside the field name. The pin 10aa6724cd33a1015db1574211890518cd04f0cc identifies the source read here; a moving branch URL does not establish that another report used the same tuple membership or result assembler. A date alone also cannot establish which source bytes a page served. That limitation applies even when two exports display identical labels.

The observation stage belongs beside the revision. A canvas module object, the assembled fingerprint object and a downloaded report need not expose the same fields. Before interpreting a missing textMetricsSystemSum, identify which object the support attachment contains and whether a transformation removed or renamed anything. If that provenance was not retained, leave the cause unresolved instead of manufacturing a run history.

For a permitted comparison of existing records, the table below defines a minimal provenance note. These are suggested support fields, not a CreepJS export format and not records automatically emitted by BotBrowser. Store only what the support purpose requires; a pointer to a user-controlled attachment can be preferable to copying raw metric vectors into routine analytics.

Support fieldQuestion answeredCollection boundary
Source revisionWhich implementation is being interpreted?Pin the actual revision, not an assumed current branch
Object stageModule, assembled object or exported record?Do not infer an unseen earlier state
Metric membershipWere the same seven properties selected?Record the schema before collecting raw values
Representative semanticsFirst member of each unique tuple?Do not relabel representatives as font support
User-visible symptomWrapping, missing glyph or report-only change?Keep the application problem separate from identity claims

An OS label needs its own evidence

Neither cited block contains the missing classification step. A report that adds an OS label needs a separately identified rule, inputs and validation evidence for that claim. Reading textMetricsSystemSum next to such a label does not prove that the sum uniquely determined it, and a label displayed by some later component is not a conclusion documented by measureText().

Population claims require another evidence category again. Source inspection cannot establish how often a value appears among real users or whether a browser version changes that distribution. No population study was performed here. Avoid converting the informal word “system” in a variable name into measured identification accuracy, cross-device stability or a guarantee that unrelated installations never share the value.

BotBrowser font controls have a narrower claim

The BotBrowser font documentation describes profile-backed font inventories, cross-platform font rendering and platform-appropriate emoji fallback. Those are product capabilities, not claims supplied by the CreepJS repository, MDN or Unicode. The same BotBrowser page explicitly allows some layout measurements to differ; a profile setting does not warrant an identical result for every glyph or text-measurement property.

An authorized application can use a declared profile when checking a specific layout or rendering requirement. Its acceptance question should name that requirement: whether the intended message remains readable or whether a known line wraps as designed. It should not substitute “CreepJS inferred the intended OS” for application correctness, nor infer successful profile loading from a matching emojiSet alone.

The documentation page and this source analysis answer different questions. The page explains configuration capabilities and their boundaries. The matrix above explains how one public implementation reduces metrics and admits fields. Keeping those scopes separate prevents a product-control description from becoming a promise about an external classifier, and prevents an external collector's field name from being presented as a documented BotBrowser output.

FAQ

Does a shorter emojiSet mean fewer supported emoji?

No. Selection in the cited block follows new metric tuples. Multiple measurable inputs may share one tuple, leaving only the first representative in emojiSet. A support-inventory conclusion would require a different test and evidence about the intended glyphs; the representative count does not provide that result.

Can equal sums establish the same operating system?

No. textMetricsSystemSum compresses unique tuples and discards their arrangement. The two cited blocks do not assign OS labels, and no browser-population validation is claimed. A later classifier needs its own evidence; equality of this aggregate does not authenticate an OS, physical device or person.

Why might metrics remain when pixel fields are absent?

The assembler checks lied and liedTextMetrics separately. Its metric branch can construct an object even when the pixel branch supplied none. That source path explains a possible field combination; it does not establish which path a particular downloaded report followed without its surrounding module and export evidence.

Sources

Practical conclusion

Interpret emojiSet as representatives of unique geometry and textMetricsSystemSum as a lossy summary, then identify the result-inclusion stage before explaining an absent field. Preserve the revision and object provenance for authorized comparisons. Use direct application evidence for rendering failures and separately justified evidence for any OS label; these source blocks supply neither a support inventory nor a device identity.

#CreepJS#Emoji Metrics#Font Fingerprinting#Canvas#Privacy

This article is part of the guide: What Is a Browser Fingerprint?

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.