Appearance
Redact sensitive information
Bird Eats Bug offers multiple approaches to automatically scrub sensitive information from data before it is uploaded, which are described below.
INFO
Currently, it is not possible to redact screenshots or video recordings.
Default redactions
The following data is redacted by default:
Network requests:
- The
Authorization
header. - All the text after the term
password
. - Any word following the keyword
Bearer
. - Values following the keys
access_token
(oraccessToken
),refresh_token
(orrefreshToken
),id_token
(oridToken
),decoded_token
(ordecodedToken
).
These rules are visible, changeable, and restorable in
Workspace Settings
->General
->Data redaction
.- The
Key presses:
- In inputs with
type="password"
- In inputs with the
autocomplete
attribute with one of the following values:,current-password
,new-password
,one-time-code
,cc-number
,cc-csc
,cc-exp
.
- In inputs with
Prevent that certain data is recorded
You can add a custom data-birdeatsbug="ignore"
HTML attribute to any element on the page to instruct the browser extension and the SDK to ignore certain types of data:
- Clicks on that specific element or its children.
- Key presses on that specific element or its children.
- DOM elements will only be recorded as empty elements with the same size as the original element.
The upside of this method is that software developers can exclude sensitive information from being recorded right when they are implementing features that include such data. The redaction will apply to any current or future Bird Eats Bug recorder, independent of its specific configuration. The downside is that source code changes are required, and that only the data points listed above are covered by this feature.
Redact data with regular expressions
Workspace Settings
-> General
-> Data redaction
allows to configure regular expression patterns to redact sensitive information before a session is uploaded with the browser extension or the SDK. These regular expressions apply to all data visible in the Developer Tools
of a recording. In comparison to the data-birdeatsbug="ignore"
HTML attribute discussed above, DOM recordings are not affected by this redaction method, and it is not possible to redact which keys where pressed. Regular expressions are handy for reacting console logs and network requests though.
Regular expresssions should be as targeted / specific as possible to avoid over-redaction. All regular expressions added to the Data redaction
workspace settings are applied to all data visible in the Developer Tools
.
INFO
When a redacted string is less than 4 characters long, the redaction will still be returned as ****
. This is to ensure that guessing the original data is not too easy for short values.
The regular expressions entered in the workspace settings should not contain a leading /
, or trailing /
, nor regular expression options. The values should only be the content of the expression. They will be automatically wrapped with /
and the gm
options (global, multi-line) when the patterns are passed to a JavaScript RegExp constructor prior to being executed.
Sometimes the value that should be redacted is known up front, or at least the value pattern. But usually there's a keyword indicating that the following, dynamic value of unknown characters and length should be redacted.
For instance, you'll want to redact the string following the term password
. In these cases, use capturing groups to denote the values that should be replaced with *
characters, and the parts of the regular expression outside to match the key terms. The same approach is used to redact the value in key-value pairs, e.g. in network request/response headers, or network request/response JSON.
This will become clearer if you read the examples below:
Redaction examples
Network request URLs:
Given a URL http://example.com/login?userName=test&password=insecure&otp=1234
, the pattern =[^=&?]*+
will result in the redacted URL http://example.com/login?userName*****&password*********&otp*****
.
To just redact the password
query parameter on example.com/login
, irrespective of query parameter order, we could also use a capture group like example\.com\/login.*password=([^&]*)
to receive http://example.com/login?userName=test&password=********&otp=1234
.
Network request / response headers
Assuming we have a network request with the request headers:
json
{
"Access-Control-Allow-Origin": "*",
"Authorization": "Bearer eySomeVeryLongJwtToken",
"Content-Type": "application/javascript"
// ... all the other headers
}
To redact the Authorization
request header, we could use the pattern Authorization([^\;]+)
to get:
json
{
"Access-Control-Allow-Origin": "*",
"Authorization": "*****************************",
"Content-Type": "application/javascript"
// ... all the other headers
}
Or let's take an imaginary reply with the response headers:
json
{
"Cache-Control": "no-cache",
"Set-Cookie": "some-token=eyMySuperSecretToken; Path=/; Expires=Fri, 09 Feb 2024 13:30:17 GMT; HttpOnly; Secure; SameSite=Strict"
// ... all the other headers
}
To redact the token from the Cookie
response header, we would configure the expression some-token=([^\;]+)
to get:
json
{
"Cache-Control": "no-cache",
"Set-Cookie": "some-token=********************; Path=/; Expires=Fri, 09 Feb 2024 13:30:17 GMT; HttpOnly; Secure; SameSite=Strict"
// ... all the other headers
}
Network request / response bodies
Imagine a network response body that contains a nested JSON object:
json
{
"password": "insecure",
"isSecret": true,
"user": {
"name": "bob",
"isNewUser": false,
"company": {
"creditCardNumber": "4242 4242 4242 4242",
"country": "Germany"
}
}
}
To get to the following redacted JSON:
json
{
"password": "********",
"isSecret": "****",
"user": {
"name": "****",
"isNewUser": false,
"company": {
"creditCardNumber": "*******************",
"country": "Germany"
}
}
}
... combine the redaction patterns password(.+)
, isSecret(.+)
, and creditCardNumber(.+)
. Every pattern applies to every key/value-pair in the JSON object, even the nested ones.
Note how the boolean
value isSecret
turned into 4 characters, which prevents understanding whether the value was false
before redaction. The 3 letter name is now also 4 letters.
Click events
If we want to hide the text of a clicked element, and also some secret data-
attributes, we could use the patterns data-temporary-password(.+)
and password is "(.+)"
to get from the click event:
json
{
"tagName": "section",
"attributes": {"data-temporary-password": "insecure", "class": "reset-password-section"},
"innerText": "Registration successful. Your temporary new password is \"insecure\". Please enter your new password below."
}
...to a redacted click event:
json
{
"tagName": "section",
"attributes": {"data-temporary-password": "********", "class": "reset-password-section"},
"innerText": "Registration successful. Your temporary new password is \"********\". Please enter your new password below."
}
Errors
Lastly, let's redact a user ID and the source file paths in the stacktrace of an uncaught error. Here we are using the patterns auth0\|(.+)
and \/([^\/]+).js
to redact the original event:
json
{
"message": "Failed to update user auth0|email123",
"stack": "TypeError: Failed to fetch\n at https://example.com/assets/index-30vtPKVQ.js:13:3929\n at window.fetch\n at https://example.com/assets/UpdateUserName-PeaKgeUR.js:1:2513\n at r (https://example.com/assets/index-30vtPKVQ.js:27:1426)"
}
...to the redacted error event:
json
{
"message": "Failed to update user auth0|********",
"stack": "TypeError: Failed to fetch\n at https://example.com/assets/**************.js:13:3929\n at window.fetch\n at https://example.com/assets/***********************.js:1:2513\n at r (https://example.com/assets/**************.js:27:1426)"
}
Additional data redaction possibilities in the SDK
The SDK allows to customize the options for DOM recording by passing options to the underlying library, rrweb
. How to customize this option is described here. rrweb
's privacy options are documented here.
With SDK, you have full programmatic control how the recorded data is mutated before it is uploaded. This code example show how to do that with the beforeUpload
hook.
Disable recording of certain data types
Disabling all data recording of a certain data type like network requests is possible too. This is only a last resort though, as it also prevents the recording of data that can be useful for debugging.