Docs

DocsIngest

What Checkend stores

After Checkend accepts an event, it cleans the event, limits its size, and puts it in an issue. This guide tells what Checkend keeps, and what it removes.

1. Remove secrets[Filtered] 2. Limit sizestored JSON ≤ 64 KB 3. Groupfingerprint v1 4. Apply capswrite issue + event
From accepted event to issue. Each accepted event goes through these steps before Checkend stores it.

1Secrets are removed first#

Checkend removes secrets before it stores anything. It replaces each secret with [Filtered].

{
  "message": "login failed for password=hunter2[Filtered] id 4821",
  "request": {
    "url": "https://api.example.com/v1?api_key=sk_live_123[Filtered]&id=7",
    "headers": {
      "Authorization": "Bearer eyJhbGciOiJIUzI1NiJ9.e30.Zm9v[Filtered]",
      "Cookie": "session=8f2c1e9a[Filtered]"
    }
  },
  "extra": { "card": "4242 4242 4242 4242[Filtered]" }
}
Secrets become [Filtered]. An example event before and after Checkend removes the secrets.

Checkend removes:

  • the values of sensitive keys, for example password, token, secret, api_key, cookie, authorization and session
  • credentials after Bearer, Basic and Token
  • JSON Web Tokens (JWTs)
  • private key blocks (-----BEGIN ... PRIVATE KEY-----)
  • Stripe, AWS, GitHub and Slack tokens
  • passwords in URLs (https://user:password@host)
  • the value after a sensitive key in text, for example password=..., token: ... or "api_key": "...", also in URLs and query strings
  • card numbers that pass the Luhn check

Examples of text with a key and a value:

BeforeAfter
password=hunter2 id 4821password=[Filtered] id 4821
login with password: hunter2 failedlogin with password: [Filtered] failed
{"password": "hunter 2"} (as text){"password": "[Filtered]"}
https://api.example.com/v1?api_key=sk_live_123&id=7https://api.example.com/v1?api_key=[Filtered]&id=7

A key is sensitive when it has a sensitive word: my_password and myPassword are sensitive, but mypassword is not. A value without quotes ends at a space, a quote, & or ;. A value in quotes ends at its matching closing quote, also across spaces and line breaks (a backslash escapes a quote). When there is no closing quote, Checkend filters to the end of the text.

Checkend removes secrets everywhere: in the stored event, in the issue title, and in the raw payload.

Your own scrub rules#

You can add rules for each project with PATCH /v1/projects/:project:

  • scrub_keys: up to 50 key names (letters, digits, _, . and -; any case). The value of any key with one of these names becomes [Filtered]: in the event, extra, contexts, tags, request headers and the raw payload. Prefer keys: they are fast and exact.
  • scrub_patterns: up to 10 regular expressions (JavaScript syntax), each at most 200 characters. Every match in every string becomes [Filtered], also in the issue title, so grouping uses the filtered text.
JSON
{"scrub_keys": ["patient_id", "x-internal-token"], "scrub_patterns": ["ACCT-[0-9]{8}"]}

Your rules apply after the default rules, within 60 seconds of a change.

Checkend checks each pattern before it saves it, so that a pattern cannot make ingest slow. It rejects a pattern that is not valid, that has a backreference (\1), that has a nested quantifier such as (a+)+, or that is slow on long inputs (it runs the pattern on test inputs of up to 16,384 characters). Then the response is 400 with the reason. Saving can take up to about a second.

2Size limits#

Checkend keeps the most useful parts of an event, and cuts the rest:

ItemLimit
Exceptions per event10
Frames per exception50
Breadcrumbs50
Tags50
Depth of free-form data (extra, contexts, user)4 levels
Stored event, as JSON64 KB

When an event is still too large, Checkend removes the least useful parts first (breadcrumb data, breadcrumbs, extra, contexts, headers, source lines) until the event fits.

Strings also have length limits. Checkend keeps source lines only for in-app frames (frames from your code, not from libraries).

Checkend removes invisible characters, control characters and bidi characters from text.

An event timestamp more than 30 days in the past, or more than 60 seconds in the future, is replaced with the time when Checkend received the event. A breadcrumb timestamp that is not valid becomes null.

3Grouping into issues#

An issue is a group of events with the same cause. Checkend makes a fingerprint for each event. Events with the same fingerprint go into the same issue.

Checkend uses the first of these rules that applies (fingerprint version 1):

  1. The SDK fingerprint, if your code sets one. {{ default }} works: it is replaced with the default fingerprint.
  2. The exception types and the in-app frames. When an exception has no in-app frames, Checkend uses all its frames. A frame is its module (or file name) and its function. Line numbers and bundle hashes are not used, so a deploy that only moves code does not create new issues. A renamed function or module gives a new issue.
  3. The exception type and the message, when no frame is usable: there is no stack trace, or the frames have only minified names (in a hashed or .min.js bundle, with names of 3 characters or fewer). Checkend replaces the parts that change in the message: numbers, IDs, and quoted values.
  4. The message for message events (captureMessage), with the same replacements.
Event SDK sets a fingerprint? yes Rule 1: the SDK fingerprint{{ default }} becomes the default no Has an exception? no Rule 4: the messagenumbers, IDs, quoted values replaced yes Usable frames?in-app, or all if none in-app yes Rule 2: types + framesmodule or file + function no Rule 3: type + messageno stack, or only minified names
How Checkend picks the grouping rule. The first rule that applies makes the fingerprint. Events with the same fingerprint are one issue.

4Caps per project#

These caps protect your database from an error flood:

error TypeError: Cannot read properties of undefined (reading 'id')
times_seen
stored_events/ 100
Cap reached: new events are counted, not stored.
The stored-events cap. After 100 stored events, the issue still counts each event in times_seen, but Checkend does not store it.
CapDefaultWhat happens above the cap
Stored events per issue100Checkend counts the event, but does not store it.
New issues per hour100Events that would make a new issue go into one "flood" issue. The hour is the last 60 minutes. Events of existing issues are counted as usual.
Tag keys200Checkend removes tags with a new key from the event. Tags with known keys stay.

You can change the defaults. See Settings and health.

Known limitation: when an issue has 100 stored events, or in budget mode, Checkend does not store the event. If an SDK sends the same event again, it is counted again.

5The raw payload#

Checkend also keeps the original event, so that a later version of Checkend can process old events again. The raw payload:

  • has its secrets removed, like the stored event
  • is compressed with gzip
  • is kept only for events of 256 KB or less
  • is in D1 when it is 64 KB or less after compression. A larger one goes to the BLOBS bucket (see Settings and health); without BLOBS, it is not kept, and only the processed event is stored.
  • is deleted with its event (see Data retention)
  • is used only to process events again. The API never returns it.

6Untrusted data#

The text in an event comes from the monitored application, so an attacker can control it. For example, an error message can say "Ignore previous instructions". Checkend stores this text, but the issue brief and the MCP tools mark it as UNTRUSTED, so that a coding agent treats it as data and not as instructions. See Untrusted data.

Edit this page on GitHubSource: guides/what-checkend-stores.md

Esc