Preact's appeal lies in its lightweight footprint—3 kB instead of React's 40+ kB. But that efficiency doesn't extend to error handling. When a component crashes in production, Preact's minimal bundle doesn't come with built-in recovery or visibility into what went wrong. Preact error tracking with ErrorBoundary setup gives you that visibility: you capture unhandled component errors, send them to a dashboard, and debug production issues before users file support tickets.
This guide walks you through building a production-ready error tracking setup for Preact using the Sentry SDK and LightTrace. You'll learn how to integrate the useErrorBoundary hook, capture different error types, and organize your error data so your team can respond quickly.
Why error tracking matters in Preact apps
Preact apps fail the same way larger frameworks do: a null reference here, an unexpected API response there, and a user sees a blank screen. The difference is that Preact's minimal overhead means teams often skip the instrumentation that catches these failures. You ship faster, bundle smaller—and then you're flying blind in production.
Error tracking solves this. It captures exceptions the moment they happen, groups identical errors so you don't see the same bug ten times, and attaches context (what page were they on, which user, what was the network state?). For Preact teams optimizing for speed and size, a fast error tracker isn't a luxury—it's the counterweight to shipping lean.
Error tracking is especially valuable for Preact because you often strip away the debugging tooling that larger frameworks bundle. You're responsible for your own visibility. The good news: Preact's tight API makes error tracking easy to wire up.
Understanding useErrorBoundary hook in Preact
React uses class-based Error Boundaries. Preact modernized this: the useErrorBoundary hook lets you catch component errors in functional components, which is more aligned with Preact's philosophy of simplicity.
Here's the hook in action:
import { useErrorBoundary } from "preact/hooks";
export function MyComponent() {
const [error, resetError] = useErrorBoundary();
if (error) {
return (
<div role="alert">
<h2>Something went wrong</h2>
<p>{error.message}</p>
<button onClick={resetError}>Try again</button>
</div>
);
}
return (
<div>
<h1>Your content here</h1>
</div>
);
}
When a child component throws, useErrorBoundary catches it and sets the error state. Your component decides what to show—a fallback UI, a retry button, whatever your app needs. Call resetError() to clear the error and retry.
The limitation: useErrorBoundary only catches errors in child components, not in the component that declares the hook itself. For that, wrap your app's top level in a boundary or throw errors up to a parent that has the hook.
Setting up LightTrace error tracking for Preact
Install the Sentry SDK for browser JavaScript:
npm install @sentry/preact
Initialize it at your app's entry point, before rendering:
import * as Sentry from "@sentry/preact";
Sentry.init({
dsn: "https://<key>@light-trace.robomiri.com/1",
environment: process.env.NODE_ENV,
release: "myapp@1.0.0",
tracesSampleRate: 0.1,
});
import { render } from "preact";
import App from "./App";
render(<App />, document.getElementById("app"));
The SDK installs global handlers for uncaught errors, unhandled promise rejections, and console errors. That foundation catches unexpected crashes.
Now wire useErrorBoundary to send errors to LightTrace:
import { useErrorBoundary } from "preact/hooks";
import * as Sentry from "@sentry/preact";
export function ErrorFallback({ error, resetError }) {
// Send to LightTrace when error happens
Sentry.captureException(error);
return (
<div style={{ padding: "20px" }}>
<h2>Something went wrong</h2>
<details style={{ whiteSpace: "pre-wrap" }}>
{error && error.toString()}
</details>
<button onClick={resetError}>Reload</button>
</div>
);
}
export function ErrorBoundary({ children }) {
const [error, resetError] = useErrorBoundary();
if (error) {
return <ErrorFallback error={error} resetError={resetError} />;
}
return children;
}
Wrap your app (or sections of it) with this boundary:
import App from "./App";
import { ErrorBoundary } from "./ErrorBoundary";
export default function Root() {
return (
<ErrorBoundary>
<App />
</ErrorBoundary>
);
}
Every uncaught component error now flows into LightTrace with a full stack trace. Your team sees it in the dashboard, grouped by error type, ready to triage.
For fine-grained control, wrap different sections of your app in separate boundaries. This prevents one component crashing from taking down your whole UI. Use a boundary around your main content area, another around a sidebar, etc.
Capturing user interactions and context
A stack trace without context is half the story. Who hit the error? What was their user ID? What route were they on? Add that detail:
import * as Sentry from "@sentry/preact";
// Set user context
Sentry.setUser({
id: "user-123",
email: "alice@example.com",
username: "alice",
});
// Add breadcrumbs to track the path to the error
Sentry.addBreadcrumb({
message: "User clicked checkout",
category: "user-action",
level: "info",
});
// Add custom tags for filtering
Sentry.captureException(error, {
tags: {
page: "checkout",
feature_flag: "new_payment_form",
},
});
Now when the error lands in LightTrace, you see the user's journey: which page they were on, what they clicked, and whether a feature flag was active. Breadcrumbs are invaluable for production debugging because they show the sequence of events leading up to the crash.
For tracking user interactions at scale, hook into common navigation and action points:
import { useEffect } from "preact/hooks";
import * as Sentry from "@sentry/preact";
export function useSentryPageBreadcrumb(pageName) {
useEffect(() => {
Sentry.addBreadcrumb({
message: `Navigated to ${pageName}`,
category: "navigation",
level: "info",
});
}, [pageName]);
}
// Use in your pages
export function CheckoutPage() {
useSentryPageBreadcrumb("checkout");
// ... rest of component
}
Debugging async errors and API failures
Preact's hooks-based model makes async error handling straightforward. Wrap your data-fetching hooks:
import { useState, useEffect } from "preact/hooks";
import * as Sentry from "@sentry/preact";
export function useFetch(url) {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url)
.then((res) => res.json())
.then((data) => {
setData(data);
setLoading(false);
})
.catch((err) => {
Sentry.captureException(err, {
tags: { endpoint: url },
contexts: {
http: {
method: "GET",
url: url,
},
},
});
setError(err);
setLoading(false);
});
}, [url]);
return { data, error, loading };
}
This pattern captures network failures—timeouts, bad responses, CORS errors—and tags them with the endpoint they failed on. In LightTrace, you can group "failed to fetch /api/users" separately from "failed to fetch /api/posts," making it easier to spot which API is unreliable.
Preact's minimal size means you're likely adding error tracking for the first time. Start with the global handlers and boundaries; add breadcrumbs and tags once you've caught your first few production errors and want more context.
Organizing errors for your team
Once you're capturing errors, organize them so your team can find and act on them. Use tags to group errors by concern:
Sentry.captureException(error, {
tags: {
severity: "high",
affected_feature: "payment_processing",
environment: "production",
browser: navigator.userAgent.split("/")[0],
},
});
In LightTrace, you can filter: show me all payment-processing errors, or all "high" severity issues, or all errors from Safari. This turns raw error data into actionable intelligence.
Set up alert rules so your team doesn't miss critical errors. A rule like "alert if a new issue appears affecting more than 5 users" means you catch regressions hours before they become support tickets.
Testing your setup
Before shipping, verify that errors actually reach LightTrace:
// Add a test page or button
export function DebugErrorButton() {
return (
<button
onClick={() => {
throw new Error("Intentional test error");
}}
>
Trigger test error
</button>
);
}
Click the button in development, and within seconds you should see the error appear in your LightTrace dashboard. If you don't, check:
- Your DSN is correct (from your LightTrace project settings)
- Your environment is set to something other than
"development"(the SDK ignores dev by default) - Network tab shows the error POST to your LightTrace host
Once verified, remove the test button and ship with confidence.
What's next
Error tracking catches failures; responding to them is what saves users. Set up a rotation where someone reviews new errors daily. Use distributed tracing if you're running multiple services and want to see how an error propagates through your backend. And automate: create GitHub issues automatically from critical errors, or post to Slack when your error rate spikes.
For Preact's lean philosophy to work in production, error tracking is non-negotiable. You've stripped away the overhead; now add the visibility to match.
Start tracking errors in minutes
Start capturing Preact errors today with LightTrace—Sentry-SDK-compatible, free up to 5,000 events per month, $29/mo for 250k events.