Error Monitoring

Capture, group, and analyze errors from connected telemetry sources.

How it works

Moneat turns error telemetry into issues your team can triage. When an error arrives, Moneat normalizes the payload, extracts exception and runtime context, generates a fingerprint, and stores the event history for analysis.

Error monitoring is source-neutral in the dashboard. Source-specific details only matter when you are configuring ingestion or troubleshooting a payload.

Ingestion sources

SourceError data Moneat can use
Sentry-compatible SDKsException events, breadcrumbs, tags, users, request data, releases, and replays
OpenTelemetrySpan status, exception events, exception attributes, and related logs
Datadog-compatible intakeAPM and log error context from compatible agents

Sentry-compatible SDKs are currently the richest source for full exception events and client replay correlation. OpenTelemetry and Datadog-compatible telemetry still contribute error context to traces, logs, service health, and related issue workflows as supported by the incoming signal.

Sentry-compatible envelope endpoint

When you use a Sentry-compatible SDK, the SDK sends events to the envelope endpoint automatically:

HTTP
POST /api/{projectId}/envelope/
Content-Type: application/x-sentry-envelope
X-Sentry-Auth: Sentry sentry_key=<public_key>,sentry_version=7

The endpoint supports gzip compression. Events are processed asynchronously and typically appear in the dashboard within seconds.

Event data

Error events can include:

  • Exception details - Type, message, and stack trace
  • Breadcrumbs - Trail of events leading up to the error
  • Tags - Key-value pairs for filtering, such as environment and release
  • User context - User ID, email, and IP address when provided
  • Device/OS info - Platform, browser, and OS version
  • Request data - URL, method, and request metadata for web applications
  • Custom context - Additional fields attached by the source SDK or exporter

Symbolicate Apple crashes

Release builds of iOS, macOS, tvOS, and watchOS apps strip their symbols, so the SDK on the device reports the app's frames as addresses, often with the function <redacted>. Upload each build's dSYMs to turn those frames back into functions, files, and lines:

Shell
export SENTRY_URL=https://api.moneat.io
export SENTRY_AUTH_TOKEN=<your_auth_token>
export SENTRY_ORG=<your_org_slug>

sentry-cli debug-files upload --project <project_slug> path/to/dSYMs

Upload the dSYMs of a build before it ships, since Moneat symbolicates events as they arrive. Xcode build phases and fastlane actions that run sentry-cli upload to Moneat the same way once SENTRY_URL points at it.

When an event arrives, Moneat finds the image that holds each native frame's address in the event's debug images, reads the uploaded dSYM whose UUID matches that image, and replaces the frame with the function, file, and line at that address. A frame with inlined calls becomes one frame per function. Exception and thread stack traces are both symbolicated. Thin and universal dSYMs work; a binary that has only a symbol table names its functions without files or lines.

Frames in system libraries and other images without an uploaded dSYM keep what the SDK sent. Each debug image whose frames were looked up records the outcome as debug_status in the event's debug metadata: found, missing when no file was uploaded for its UUID, or malformed when the uploaded file could not be read.

Kotlin/Native frames are named by their Kotlin function, such as kfun:com.example.app.Recorder#start(kotlin.Int){}kotlin.Int. Kotlin/Native links the Kotlin standard library and the app's code into one image, which the SDK marks as all the app's. When an exception has Kotlin/Native frames under the release's package, the application ID before @ in the release name, its Kotlin/Native frames count as the app's own only under that package, so grouping uses the app's code rather than the standard library.

Error grouping

Automatic fingerprinting

For Sentry-compatible events, Moneat uses the main thrown exception's type and the innermost application frame's module or class plus function. A frame without an in_app flag is eligible; frames explicitly marked outside the application are used only when no eligible frame exists. When a module is present, filenames and line numbers do not affect grouping. Without a module, the function and filename provide a fallback; generic SourceFile and Unknown Source filenames are ignored. An exception without frames groups by its type.

For obfuscated Android builds, upload each build's ProGuard/R8 mapping before sending events. Moneat retraces the exception and frames before grouping, so different obfuscated names can resolve to the same issue across releases. When the retraced stack has frames under the release's package, the application ID before @ in the release name, frames without an in_app flag are classified by it: frames under the package are application frames and the rest are library or platform frames. Grouping then uses the innermost frame of the app's own code. Events received without their mapping retain their raw symbols.

Apple events group by their symbolicated function names. When the app's innermost frame is still <redacted>, its name would put every unsymbolicated error of one exception type in the same issue, so an error with a message groups by its exception type and message instead. Values that change between occurrences are replaced in the message first: UUIDs, 0x hex values, runs of eight or more hex digits that mix letters and digits, and numbers. Take 1f0c3d1e-9a7b-4c2d-8e5f-0a1b2c3d4e5f was released and Take 8a2b7c4d-9a7b-4c2d-8e5f-0a1b2c3d4e5f was released share an issue.

An event without an exception, such as one sent with captureMessage or by a logging integration, groups by its message, with the same values replaced. When the SDK sends a message template with separate parameters, the template is used, so Could not load asset %s is one issue for every asset; the issue title shows the formatted message. An event with neither an exception nor a message groups into a single <unlabeled event> issue.

Custom fingerprinting

Sentry-compatible SDKs can override default grouping with a custom fingerprint:

JavaScript
Sentry.captureException(error, {
  fingerprint: ["custom-group-key"],
});

To refine automatic grouping, include the exact {{ default }} placeholder:

JavaScript
Sentry.captureException(error, {
  fingerprint: ["{{ default }}", "checkout"],
});

Moneat replaces each placeholder with the automatic fingerprint components. A fingerprint containing only {{ default }} groups exactly like automatic grouping. Other values, including their whitespace and order, are used as supplied; a fingerprint without the placeholder overrides automatic grouping.

Existing issue history

The stable class-and-function grouping update applies when new events are ingested. Previously stored events retain their issue IDs, history, statuses, and comments; Moneat does not backfill or automatically merge them. A recurring error whose fingerprint changes starts a new issue after the update, while its older history remains accessible in the previous issue. New-issue alerts and release new-issue counts can therefore show a one-time new issue at this cut-over. Type-only fingerprints and custom fingerprints without {{ default }} retain their grouping when their inputs are unchanged.

Uploading a missing mapping later likewise does not regroup stored events. Upload mappings before ingestion to keep subsequent releases together.

Retraced Android events change fingerprints once when their mapping first applies. They group by the original exception type and the class and method of the app's innermost frame. Earlier events of the same error stay in issues keyed by obfuscated names or a platform frame, so each recurring error starts one new issue.

Apple events change fingerprints once as well. Errors whose innermost app frame is <redacted> used to share one issue per exception type; they now group by type and message, so each recurring error starts one new issue. Once a build's dSYMs are uploaded, its errors group by the symbolicated function, which starts one more new issue per recurring error. Earlier events keep their issues, and uploading dSYMs later does not regroup stored events.

Events without an exception used to share one <unlabeled event> issue per project whatever their message. They now group by message, so each recurring message starts one new issue and raises one new-issue alert. The <unlabeled event> issue keeps its history and status, and afterwards collects only events that have no message either.

Usage & rate limiting

Moneat meters ingestion by plan and billable usage rather than by source-specific event quotas. If an organization reaches a configured budget cap or ingestion limit, Moneat can reject or drop new events to protect the account.

Usage tracking

Monitor usage, included capacity, overages, and budgets under Billing & Plans.

Supported platforms

Any platform that can emit OpenTelemetry errors, Sentry-compatible envelopes, or compatible agent telemetry can contribute error context to Moneat.

For full exception capture through Sentry-compatible SDKs, popular platforms include JavaScript, TypeScript, Python, Java, Kotlin, Swift, Go, Ruby, PHP, .NET, Rust, Elixir, React, Vue, Angular, Next.js, Django, Flask, Spring, Android, iOS, React Native, Flutter, and Node.js.