Understand error fingerprinting
When your application generates thousands of errors, you need to know which are unique and which are repeated. Frontend Observability uses error fingerprinting to automatically group similar errors together, so you can focus on distinct issues rather than sifting through individual error instances.
Fingerprinting computes a stable identifier for each error based on its characteristics. Errors that share the same fingerprint are grouped together, enabling accurate error counts, trend analysis, and alerting.
How fingerprinting works
Frontend Observability uses a four-layer cascading strategy to compute fingerprints. Each layer targets a different level of information available in the error, falling back to the next layer when the previous one can’t produce a reliable fingerprint.
Layer 1: User-provided fingerprint
If you provide a custom fingerprint when reporting an error, Frontend Observability uses it directly. This gives you full control over how specific errors are grouped.
Use this approach when you want to:
- Group errors that have different stack traces but represent the same logical issue
- Split errors that would otherwise be grouped together
- Create stable groupings for known error patterns
faro.api.pushError(new Error('Payment processing failed'), {
fingerprint: 'checkout-payment-timeout',
});Layer 2: Normalized stack trace
When no user-provided fingerprint is available and the error has a stack trace with meaningful function names, Frontend Observability computes a fingerprint from the normalized stack trace.
Normalization removes dynamic elements that change between deployments but don’t represent different errors:
- Line numbers and column numbers
- Webpack module IDs
- Dynamic function suffixes
- Chunk hashes, for example,
main.a1b2c3.jsbecomesmain.HASH.js - Memory addresses
- Query parameters from file URLs
This means the same error produces the same fingerprint even after you deploy new code with different chunk hashes or source map changes.
This layer relies on the stack trace structure alone and doesn’t factor in the error message. Two different errors that pass through the same function and file produce the same fingerprint. For example, Cannot read property 'userId' of undefined and Cannot read property 'email' of undefined in the same function are grouped together. In practice this is a narrow edge case; if the errors occur in different functions or different files, they’re split correctly.
Layer 3: File sequence and canonical message
When the stack trace only contains anonymous or heavily minified function names but still has valid paths, Frontend Observability combines the sequence of files in the stack trace with a canonical version of the error message.
This layer is common for minified JavaScript where function names are stripped to single characters but paths remain intact.
Layer 4: Error type and canonical message
When no stack trace is available, for example, for network errors or assertion failures, Frontend Observability falls back to grouping by the error type and a normalized version of the error message.
Message normalization replaces dynamic values so that errors like these are grouped together:
Cannot read property 'userId' of undefinedandCannot read property 'email' of undefinedboth become a single null access pattern, because the property name is a dynamic value specific to each occurrence.- Browser-specific prefixes like
Uncaughtare stripped. - URLs, UUIDs, numeric IDs, timestamps, and paths are replaced with placeholders.
Provide custom fingerprints
You can set a custom fingerprint on any error to control how it’s grouped. Pass a fingerprint string in the pushError options or set it on the exception payload in the beforeSend hook.
Errors with the same fingerprint value are grouped together regardless of their stack trace or message. Errors with different fingerprints are never grouped together, even if they have identical stack traces.
When pushing errors manually
To set a custom fingerprint when manually reporting errors:
import { faro } from '@grafana/faro-web-sdk';
faro.api.pushError(new Error('Request timeout'), {
fingerprint: 'api-request-timeout',
});Use the beforeSend hook
You can set fingerprints dynamically using the beforeSend hook to assign fingerprints to automatically captured errors based on their properties:
initializeFaro({
url: 'https://my-domain.my-tld/collect/{app-key}',
app: {
name: 'my-app',
},
beforeSend(item) {
if (item.type === 'exception') {
const message = item.payload.value ?? '';
if (message.includes('ChunkLoadError')) {
item.payload.fingerprint = 'chunk-load-error';
}
}
return item;
},
});Improve fingerprint accuracy
The quality of fingerprints depends on the information available in each error. You can improve grouping accuracy by ensuring that Frontend Observability has access to the best possible error data.
Upload source maps
Source maps allow Frontend Observability to resolve minified stack traces back to original function names and paths. This significantly improves fingerprint accuracy by enabling Layer 2 (normalized stack trace) matching instead of falling back to less precise layers.
Refer to source map uploads for instructions on how to configure source map uploads.
Enable cross-origin error details
Errors from third-party scripts are restricted by browsers and reported as generic “Script error” messages with no stack trace. Adding crossorigin="anonymous" to script tags exposes the full error details.
Refer to error tracking for more details on handling third-party script errors.
Use custom fingerprints for known patterns
If you notice that automatic grouping doesn’t produce the right results for specific error patterns, use user-provided fingerprints to override the automatic behavior. This is particularly useful for:
- Errors with highly dynamic stack traces
- Errors that come from third-party libraries with inconsistent error messages
- Business logic errors that should be grouped by their domain meaning rather than their technical characteristics



