Crashes and errors from your web, Node.js, Flutter, Android and iOS apps, grouped into issues, with the stack, breadcrumbs and the API call that failed right before the crash.
| Limit | Free | Pro | Scale | Enterprise |
|---|---|---|---|---|
| Crash reports per project | 5,000 per month | 100,000 per month | 1,000,000 per month | 10,000,000 per month |
| Crash events kept | 7 days | 30 days | 90 days | 90 days |
| crash_sourcemaps_mb | 50 MB | 1.0 GB | 5.0 GB | 10 GB |
Crash reporting collects the uncaught exceptions of your apps, and the errors you report yourself, in your project. Reports of the same bug are grouped into one issue, so you see how many events and users each bug has, in which releases it happens and whether a fix worked. Because the SDK already makes your app’s API calls, every report shows which request to your project failed right before the crash, and Studio lists the failed requests from the project’s logs around it.
#Set it up
- Open Studio › Crashes and click Turn on crash reporting.
- Call
crashes.start()once when your app starts, with the version of the app as the release. Nothing is captured or sent beforestart(), so if you ask your users for consent, call it after they agreed.
import { createClient } from 'stitchdb-js'
const stitchdb = createClient(STITCHDB_URL, STITCHDB_ANON_KEY)
stitchdb.crashes.start({
release: '1.4.0', // your app's version
environment: 'production',
beforeSend: (report) => report, // change a report, or return null to drop it
})final crashes = Stitch.instance.client.crashes;
await crashes.start(release: '1.4.0', environment: 'production');
// FlutterError.onError and PlatformDispatcher.instance.onError are reported for you
// (the handlers you set before keep working)stitchdb.crashes.start(context, release = BuildConfig.VERSION_NAME, environment = "production")
// uncaught exceptions on any thread are written to disk and sent on the next startstitchdb.crashes.start(release: "1.4.0", environment: "production")
// uncaught NSExceptions are written to disk and sent on the next start#Report errors yourself
Errors you catch are reported as handled. Add context (it is shown with the event) and, if the automatic grouping does not fit, your own fingerprint: reports with the same fingerprint are one issue.
try {
await checkout(cart)
} catch (e) {
stitchdb.crashes.captureException(e, { context: { cart: cart.id }, fingerprint: ['checkout'] })
showError()
}
stitchdb.crashes.captureMessage('Payment sheet closed without a result')
stitchdb.crashes.addBreadcrumb({ type: 'ui', message: 'tap Checkout' })
await stitchdb.crashes.flush() // send now, such as before a serverless function returns#What a report has
| Part | What it is |
|---|---|
| Exception | The error type, the message and the stack. Stacks from JavaScript engines, Dart, Java and Kotlin and Apple symbol lines are read into frames; your own code is told apart from libraries. |
| Breadcrumbs | The last 50 things that happened before: every API call the SDK made (method, path, the names of the query parameters but not their values, status, error code, duration), page changes on the web and anything you add. |
| The API call before the crash | The last failed API call in the two minutes before the crash, else the last call. A crash a few seconds after a 403 with 42501 usually means a policy refused a row the app expected. |
| Release, environment, device | What you passed to start(), and the OS, version, model and locale the SDK knows. |
| User | The signed-in user, from their token. An app cannot report as another user; only the service key may name one. |
#Issues
Without your own fingerprint, a report is grouped by the error type and the three topmost frames of your own code (function and file, without line numbers and without build hashes in file names), so the same bug in the next build is the same issue. Without a stack it is grouped by the type and the message, with numbers, ids and e-mail addresses taken out.
- Resolve an issue once you shipped the fix. If it happens again in a release that is new since then, it opens again as a regression and alerts; events from the old release do not.
- Ignore an issue to stop its alerts. It is still counted.
- Crash-free users per release: the share of installs that opened the app that day and did not crash. The SDK sends one small session a day per install and release for this.
#Alerts
A new issue and a regression alert by e-mail to the project owner, to the project’s webhooks (events crash.issue.new and crash.issue.regressed) and, if you add a bot, to a Telegram chat. Only crashes alert by default; turn on alerts for handled errors in the settings. At most 20 alerts per project an hour; Send a test alert checks the setup.
#Privacy
Before a report is kept, values of fields named like passwords, tokens, secrets, keys, cookies and authorization are replaced with [scrubbed], e-mail addresses and JWTs in messages and URLs are removed, and so are the values of query parameters such as token or api_key. Add your own field names under More fields to scrub. Reports are stored in your project’s database (schema _stitch_crashes), not in a third-party service.
#Read issues from your server
With the service key, for a dashboard of your own or a CI check after a release:
curl 'https://<ref>.p.stitchdb.com/crashes/v1/issues?status=open&release=1.4.0' \
-H "apikey: $SERVICE_KEY" -H "Authorization: Bearer $SERVICE_KEY"
# also: GET /crashes/v1/issues/<id>, PATCH /crashes/v1/issues/<id> {"status":"resolved"}, GET /crashes/v1/releases#Source maps
Minified JavaScript stacks point to app.3f9c2a1b.js:1:48213. Upload the source maps of each release and reports of that release show the original file, line, column and function, with a few lines of your source around each frame of your own code (when the map has sourcesContent). Stacks are read when a report arrives, before it is grouped, so issues group by your original code. The maps stay in your project; the box your project runs on reads them, and they are never sent anywhere else.
# the CLI 2.2 or newer
npm install -g https://stitchdb.com/cli/stitchdb.tgz
# after your build, in CI or by hand (the release is the one you pass to crashes.start)
stitchdb sourcemaps upload dist --release 1.4.0
stitchdb sourcemaps list --release 1.4.0
stitchdb sourcemaps delete --release 1.3.0Each map is stored under the path of its minified file: dist/assets/app.3f9c2a1b.js.map becomes /assets/app.3f9c2a1b.js. Use --url-prefix when the folder is served from a sub-path. A frame on another host or under a deeper path still finds its map; if two maps have the same file name in different folders, give the exact path. Turn on source maps in your bundler (build.sourcemap: true, devtool: 'source-map' or similar); you do not need to publish the .map files on your site.
Without the CLI, send the map with the service key:
curl -X POST 'https://<ref>.p.stitchdb.com/crashes/v1/sourcemaps?release=1.4.0&name=/assets/app.3f9c2a1b.js' \
-H "apikey: $SERVICE_KEY" -H "Authorization: Bearer $SERVICE_KEY" \
--data-binary @dist/assets/app.3f9c2a1b.js.map
# gzip is fine too: -H "Content-Encoding: gzip" --data-binary @app.js.map.gz
# also: GET /crashes/v1/sourcemaps?release=1.4.0, DELETE /crashes/v1/sourcemaps?release=1.4.0[&name=/assets/app.3f9c2a1b.js]- Upload the maps before the release goes out. Reports that arrived earlier are shown with original frames once the map is uploaded, but they stay in the issue they were grouped into.
- One map can be up to 64 MB. All maps of a project together count toward the plan’s source map storage (the unpacked size). They are stored compressed in your project’s database and stay until you delete them: delete the maps of releases nobody uses any more.
- Index maps (with
sections) work; Android R8 mapping files, iOS dSYMs and native crashes are not supported yet.
#Limits
Each report counts toward the plan’s reports per month. After that, new reports still count on their issue but are not kept until the next month. Up to 20 events per issue a day are kept with all their details, for the plan’s days; issues and their counts stay. Environments you list in the settings are the only ones kept.