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.
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]" }
}Checkend removes:
- the values of sensitive keys, for example
password,token,secret,api_key,cookie,authorizationandsession - credentials after
Bearer,BasicandToken - 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:
| Before | After |
|---|---|
password=hunter2 id 4821 | password=[Filtered] id 4821 |
login with password: hunter2 failed | login with password: [Filtered] failed |
{"password": "hunter 2"} (as text) | {"password": "[Filtered]"} |
https://api.example.com/v1?api_key=sk_live_123&id=7 | https://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.
{"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:
| Item | Limit |
|---|---|
| Exceptions per event | 10 |
| Frames per exception | 50 |
| Breadcrumbs | 50 |
| Tags | 50 |
Depth of free-form data (extra, contexts, user) | 4 levels |
| Stored event, as JSON | 64 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):
- The SDK fingerprint, if your code sets one.
{{ default }}works: it is replaced with the default fingerprint. - 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.
- 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.jsbundle, with names of 3 characters or fewer). Checkend replaces the parts that change in the message: numbers, IDs, and quoted values. - The message for message events (
captureMessage), with the same replacements.
4Caps per project#
These caps protect your database from an error flood:
| Cap | Default | What happens above the cap |
|---|---|---|
| Stored events per issue | 100 | Checkend counts the event, but does not store it. |
| New issues per hour | 100 | Events 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 keys | 200 | Checkend 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
BLOBSbucket (see Settings and health); withoutBLOBS, 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.