diff --git a/.env.example b/.env.example
index 2d8cdbae..6dc3140b 100644
--- a/.env.example
+++ b/.env.example
@@ -39,4 +39,7 @@ CDN_CGI_IMAGE_URL=https://example.com/cdn-cgi/image
MAILCHIMP_SIGNUP_URL=https://example.us1.list-manage.com/subscribe/post?u=secret123&id=secret123
# Sentry.io
-SENTRY_DSN=https://123456789123456789@123456789.ingest.de.sentry.io/123456789
\ No newline at end of file
+SENTRY_DSN=https://123456789123456789@123456789.ingest.de.sentry.io/123456789
+SENTRY_ORG=my-org
+SENTRY_PROJECT=my-project
+SENTRY_AUTH_TOKEN=secret123
\ No newline at end of file
diff --git a/app/components/ErrorPage/index.tsx b/app/components/ErrorPage/index.tsx
index 82088e37..db9bf1af 100644
--- a/app/components/ErrorPage/index.tsx
+++ b/app/components/ErrorPage/index.tsx
@@ -2,11 +2,26 @@ import React from "react";
import { useRouteError, isRouteErrorResponse } from "@remix-run/react";
import environment from "~/util/environment";
import Page from "../Page";
+import {
+ captureRemixErrorBoundaryError,
+ captureException,
+} from "@sentry/remix";
export const ErrorPage: React.FC = () => {
let error = useRouteError();
let children = null;
+ captureRemixErrorBoundaryError(error);
+
+ if (
+ !isRouteErrorResponse(error) ||
+ (isRouteErrorResponse(error) && error.status >= 500)
+ ) {
+ console.log("captured error with sentry");
+ captureException(error);
+ // console.error(error);
+ }
+
if (isRouteErrorResponse(error)) {
children = (
diff --git a/app/entry.client.tsx b/app/entry.client.tsx
index fdfc23b1..85731d52 100644
--- a/app/entry.client.tsx
+++ b/app/entry.client.tsx
@@ -1,5 +1,5 @@
-import { RemixBrowser } from "@remix-run/react";
-import { startTransition, StrictMode } from "react";
+import { RemixBrowser, useLocation, useMatches } from "@remix-run/react";
+import { startTransition, StrictMode, useEffect } from "react";
import { hydrateRoot } from "react-dom/client";
import i18n from "./i18n";
import i18next from "i18next";
@@ -7,6 +7,24 @@ import { I18nextProvider, initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import Backend from "i18next-http-backend";
import { getInitialNamespaces } from "remix-i18next";
+import * as Sentry from "@sentry/remix";
+import environment from "./util/environment";
+
+Sentry.init({
+ dsn: environment().SENTRY_DSN,
+ tracesSampleRate: 1,
+ replaysSessionSampleRate: 0.1,
+ replaysOnErrorSampleRate: 1,
+
+ integrations: [
+ Sentry.browserTracingIntegration({
+ useEffect,
+ useLocation,
+ useMatches,
+ }),
+ Sentry.replayIntegration(),
+ ],
+});
async function hydrate() {
await i18next
diff --git a/app/entry.server.tsx b/app/entry.server.tsx
index 27321e97..77b1719c 100644
--- a/app/entry.server.tsx
+++ b/app/entry.server.tsx
@@ -12,6 +12,17 @@ import { I18nextProvider, initReactI18next } from "react-i18next";
import Backend from "i18next-fs-backend";
import i18n, { returnLanguageIfSupported } from "./i18n"; // your i18n configuration file
import { resolve } from "node:path";
+import * as Sentry from "@sentry/remix";
+
+export function handleError(error: any, { request }: { request: Request }) {
+ Sentry.captureRemixServerException(error, "remix.server", request);
+ console.error(error);
+}
+
+Sentry.init({
+ dsn: process.env.SENTRY_DSN,
+ tracesSampleRate: 1,
+});
const ABORT_DELAY = 5000;
diff --git a/app/root.tsx b/app/root.tsx
index f06123a2..e415cc18 100644
--- a/app/root.tsx
+++ b/app/root.tsx
@@ -31,6 +31,7 @@ import { getHreflangLinks } from "./util/getHreflangLinks";
import { localizeTo } from "./components/localized-link/util/localizeTo";
import { i18nCookie } from "./cookie";
import { useChangeLanguage } from "remix-i18next";
+import { withSentry } from "@sentry/remix";
export const ErrorBoundary = ErrorPage;
@@ -81,6 +82,9 @@ export async function loader({
NODE_ENV: environment().NODE_ENV,
MAILCHIMP_SIGNUP_URL: environment().MAILCHIMP_SIGNUP_URL,
CDN_CGI_IMAGE_URL: environment().CDN_CGI_IMAGE_URL,
+ SENTRY_DSN: environment().SENTRY_DSN,
+ // SENTRY_ORG: environment().SENTRY_ORG,
+ // SENTRY_PROJECT: environment().SENTRY_PROJECT,
},
},
{
@@ -148,7 +152,7 @@ export const handle = {
i18n: "common", // i18n namespace
};
-export default function App() {
+function App() {
// Get the locale from the loader
const { locale, serializedI18nCookie, publicKeys, site } =
useLoaderData();
@@ -218,3 +222,5 @@ export default function App() {