What tinymon collects (and how to control it)
We try to be the boring, predictable choice on data. Defaults are privacy-preserving, controls are obvious, and the server applies the same scrubs your SDK does — so a misconfigured SDK never bypasses the protection.
What's collected
Every event the SDK sends contains:
| Field | What it is |
|---|---|
| exception.type / value | The error class name and message text. |
| stacktrace.frames | Filename, function, line, column for each frame. |
| breadcrumbs | Up to 30 recent breadcrumb messages. |
| tags | Key/value strings you attach via setTag. |
| user.id | Whatever identifier you pass to setUser({id}). No email/name unless you put it there. |
| request.url | Page URL the error happened on (browser SDK only). Query string is stripped by default. |
| release, environment | Free-form strings you pass to init(). |
We do not collect: request body, headers, cookies, OS version, device fingerprint, or any analytics-style data. The client IP is not collected unless you explicitly opt in (see below).
Default scrubs (on for every SDK, every version)
Before an event is sent — and again at the server before it's stored — tinymon redacts:
- URL query strings and fragments.
request.urlkeeps the path;?…and#…are dropped. - Email addresses in
exception.valueand breadcrumb messages →[redacted]. - Card-like numbers (13–16 digit runs, with or without spaces/dashes) →
[redacted]. - Bearer and Authorization tokens →
[redacted]. - Sensitive tags. Any tag whose key matches
password / token / secret / auth / card / cvv / ssnhas both key and value redacted.
Stack frame file paths and code are not scrubbed — doing so would break traces.
You can extend the pattern set with scrub_patterns, or turn off URL-query stripping with scrub_url_query: false. The server-side scrubs always run regardless of SDK config.
send_default_pii (default false)
Out of the box, tinymon does not attach the client IP to any event. To allow IP capture, pass send_default_pii: true in your init() call. This flag travels with the event; the server only stores IP when it sees the flag.
beforeSend — the escape hatch
For anything the defaults don't cover, supply a beforeSend callback. It receives the fully-built (and already-scrubbed) event, can mutate any field, and can return null to drop the event entirely.
import { init } from 'tinymonjs'; init({ dsn: process.env.TINYMON_DSN, // Drop events from health-check requests entirely. beforeSend(event) { if (event.request?.url?.endsWith('/health')) return null; // Redact a custom internal field name. if (event.tags?.customer_email) event.tags.customer_email = '[redacted]'; return event; }, });
import tinymonpy def before_send(event): # Drop events from health-check requests entirely. if (event.get("request") or {}).get("url", "").endswith("/health"): return None # Redact a custom internal field name. if (event.get("tags") or {}).get("customer_email"): event["tags"]["customer_email"] = "[redacted]" return event tinymonpy.init(dsn=os.environ["TINYMON_DSN"], before_send=before_send)
require "tinymonrb" before_send = ->(event) { # Drop events from health-check requests entirely. url = (event["request"] || {})["url"] || "" next nil if url.end_with?("/health") # Redact a custom internal field name. (event["tags"] ||= {})["customer_email"] = "[redacted]" if event.dig("tags", "customer_email") event } Tinymon.init(dsn: ENV["TINYMON_DSN"], before_send: before_send)
Server-side defense-in-depth
Every event that reaches our ingest endpoint is scrubbed again on the server using the same default patterns. This means even if a customer is on an older SDK version, has misconfigured beforeSend, or sends data with curl, emails / card-like numbers / bearer tokens never end up stored.