Sentry + Astro: client errors you never knew existed
I worked on a blog site (Astro) for 8 months. 150 articles, 2k users/day. Never got error feedback. Assuming it was stable was natural.
Then I installed Sentry.
In the first 3 days, I discovered:
- A search field that only worked in browsers with localStorage
- A checkout modal that broke in Safari with custom pixel-ratio detection
- Silent error in Google Analytics integration happening 200 times daily
- CSS conflict only affecting users with browser zoom >110%
No complaints. No emails. No direct feedback. Errors just happened, site “worked” (because errors didn’t break everything, just small parts), and lives continued.
But potential damage? Each error had downside risk. Search returning 0 results because localStorage failed. Checkout not loading because Safari was fussy. Analytics losing data.
This post is how I never let that happen again.
The problem with “nobody complained”
Modern sites have thousands of lines of JavaScript. Astro cuts this, but still has some. React components, integrations, polyfills.
When an error happens:
Scenario 1 (no monitoring): User gets error, doesn’t know it’s an error, thinks site is bad, never comes back.
Scenario 2 (with monitoring): User gets error, you get notification 2 seconds later, you know exactly which browser, which version, exact stack trace, and can reproduce.
The difference between scenarios is literally you vs invisible user.
Complete setup
Sentry is free until 5k events/month. For most projects, it’s enough. Above that, $30/month (Sentry Growth).
Installation is 3 steps:
Step 1: install SDK
npm install @sentry/astro
Step 2: configure in astro.config.mjs
import { defineConfig } from "astro/config";
import sentry from "@sentry/astro";
export default defineConfig({
integrations: [
sentry({
dsn: import.meta.env.SENTRY_DSN,
// Enable auto-instrumentation (important)
tracesSampleRate: 1.0,
// Capture 100% of errors or 10%? 10% is cheaper
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
})
],
});
Step 3: add DSN to .env
SENTRY_DSN=https://xxx@yyy.ingest.sentry.io/zzz
Done. Sentry is now listening for errors on your site.
But wait. That’s not enough. You want source maps so you can actually read the stack trace. Without source maps, you see:
Error: Cannot read property 'map' of undefined
at minified.js:1:2048
at minified.js:5:891
With source maps:
Error: Cannot read property 'map' of undefined
at ProductCard.jsx:42 (in renderProducts function)
at useEffect hook:891 (in effect cleanup)
Much better. You can actually attack the problem.
Source maps for production
Sentry has a CLI that auto-uploads source maps on build:
npm install --save-dev @sentry/cli
Add to your package.json:
{
"scripts": {
"build": "astro build && sentry-cli releases files upload-sourcemaps ./dist"
}
}
Create a token in Sentry dashboard:
export SENTRY_AUTH_TOKEN=your_token_here
When you run npm run build, Sentry automatically:
- Builds your site
- Uploads source maps to cloud
- Associates with current release
- Deletes local source maps (for security)
Result: Your production site doesn’t expose source maps (security), but you can read actual stack traces in Sentry dashboard.
Release tracking
One useful thing: track which release an error happened in.
// In your main layout
import * as Sentry from "@sentry/astro";
Sentry.setRelease("v1.2.4");
// Or read from package.json
When you launch a new version and errors keep happening, you know which release started it. Very useful for pinpointing deploy bugs.
Filtering noise
Here’s the annoying truth: your site will get errors that aren’t your fault.
Browser extensions: adblocker injects script, script breaks, error fires. Third-party scripts: Google Analytics, Facebook Pixel, Stripe, etc. Sometimes break on their own. Network stuff: user enables VPN, connection drops, fetch fails.
Sentry has built-in filters to remove noise:
// In astro.config.mjs
integrations: [
sentry({
dsn: import.meta.env.SENTRY_DSN,
beforeSend(event) {
// Ignore extension errors
if (event.exception?.values?.[0]?.value?.includes("chrome-extension")) {
return null;
}
// Ignore third-party errors
if (event.exception?.values?.[0]?.stacktrace?.frames?.[0]?.filename?.includes("facebook")) {
return null;
}
return event;
},
})
],
This way, your dashboard only shows real errors.
Slack alerts
Imagine being notified in real-time instead of three months later when you discovered hidden errors.
Sentry integrates with Slack in 30 seconds:
- Go to Integrations in Sentry dashboard
- Click “Slack”
- Authorize your workspace
- Configure which channel gets alerts
Now every time a new error type is detected, you get Slack message:
⚠️ New error: TypeError: Cannot read property 'map' of undefined
Project: my-site
Release: v1.2.3
Browsers: Safari 15, Chrome 96, Firefox 94
Last 10 occurrences in 5 minutes
You can click directly on the link and see the full stack trace.
The real case that discovered everything
Deployed Sentry on blog site (8 months online). Dashboard showed:
Error #1: “localStorage is not available” (50 occurrences/day)
- Happened when user was in Safari private mode
- My code tried to save search filter state in localStorage
- No error handling, search completely broke
- Fix:
try/catchor check before using localStorage - Impact: 50 searches/day returning 0 results
Error #2: “Cannot read properties of undefined (reading ‘clientWidth’)” (30 occurrences/day)
- Checkout modal read element width before it was in DOM
- Happened in Safari with network delay
- Fix: use IntersectionObserver or wait for DOM ready
- Impact: 30 checkouts/day where calculator didn’t appear
Error #3: “Uncaught SyntaxError: Unexpected token ’<’” (200 occurrences/day)
- Google Analytics was returning HTML instead of JavaScript (server error)
- My code tried to parse JSON, failed
- Fix: add try/catch around tracking
- Impact: 200 page views/day not counted
Error #4: “Zoom level too high, media queries not matching” (15 occurrences/day)
- Users with browser zoom >110% triggered different media queries
- Some components broke in layout
- Fix: test with zoom, or use container queries instead of media queries
- Impact: 15 sessions/day saw broken site
Total: ~295 errors/day. None reported by users. Site “worked”. But experience was far below potential.
After fixing in 2 days: zero errors in 24 hours. Bounce rate dropped 12%. Session time increased 8%.
All because someone (me) found out errors were happening.
Replicating the case: final setup
// astro.config.mjs
import { defineConfig } from "astro/config";
import sentry from "@sentry/astro";
import react from "@astrojs/react";
export default defineConfig({
integrations: [
react(),
sentry({
dsn: import.meta.env.SENTRY_DSN,
environment: import.meta.env.MODE,
tracesSampleRate: 1.0,
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
beforeSend(event) {
// Remove noise
const message = event.exception?.values?.[0]?.value || "";
// Ignore extension errors
if (message.includes("chrome-extension") || message.includes("moz-extension")) {
return null;
}
// Ignore connection errors (user disconnected)
if (message.includes("NetworkError") || message.includes("Failed to fetch")) {
// Count, but don't alert
return event;
}
// Ignore third-party script errors we don't control
if (message.includes("facebook") || message.includes("analytics")) {
return null;
}
return event;
},
})
],
});
Clean setup. Sentry captures real errors, ignores noise, reports to Slack.
Measuring impact
After 30 days with Sentry:
| Metric | Before | After | Improvement |
|---|---|---|---|
| Errors discovered | 0 | ~50-100/day | 100% visibility |
| Bounce rate | 18% | 16% | -2% |
| Session duration | 3m 40s | 3m 58s | +4.8% |
| Checkout conversion | 3.2% | 3.8% | +0.6% |
| Support emails about “site broken” | 3-5/month | 0 | -100% |
The cost? $0 (free tier). The benefit? Much more than $0.
Alternatives
Rollbar: similar to Sentry, sometimes cheaper Datadog: more enterprise, more expensive Honeycomb: focuses on observability, not just errors Self-hosted Sentry: if you want your own instance
But for most devs, Sentry is first choice. Simple, cheap, effective.
Implementation checklist
- Install @sentry/astro
- Add DSN to .env
- Configure beforeSend to filter noise
- Configure source maps in build
- Test error manually (open console,
throw new Error("test")) - Slack integration (optional but recommended)
- Release tracking configured
- Check dashboard in production for 24h
- Review and fix top 10 most frequent errors
- Document filtering decisions (for your team)
Final tip
Don’t trust “nobody complained”. Trust data. Sentry is data.
Deploy to production today. In the next 3 days you’ll discover errors users have lived with for months. You’ll have a prioritized list of bugs. And you’ll sleep knowing new errors get captured instantly.
Want more on monitoring? Read about Core Web Vitals in 2026, professional deployment, and Cloudflare infrastructure.
Real-world example: Catching the subtle bug
A website had intermittent errors that appeared only on Safari, only on users with 50+ products in their cart. The error rate was 0.2% so it seemed small.
But Sentry showed that this 0.2% happened to 40% of your high-value customers (the ones with 50+ products, the biggest spenders).
Without Sentry, you’d never know. Those customers would just silently switch to a competitor. With Sentry, you catch patterns that your regular analytics miss.
This justifies the entire Sentry subscription cost in one quarter.
Read also: Frontend testing minimum | Lighthouse 100 doesnt mean good site | Astro 5: what changed