diff --git a/packages/e2e-tests/test-applications/nextjs-app-dir/pages/pages-router/ssr-error-class.tsx b/packages/e2e-tests/test-applications/nextjs-app-dir/pages/pages-router/ssr-error-class.tsx
new file mode 100644
index 000000000000..86ce68c1c034
--- /dev/null
+++ b/packages/e2e-tests/test-applications/nextjs-app-dir/pages/pages-router/ssr-error-class.tsx
@@ -0,0 +1,16 @@
+import React from 'react';
+
+export default class Page extends React.Component {
+ render() {
+ throw new Error('Pages SSR Error Class');
+ return
Hello world!
;
+ }
+}
+
+export function getServerSideProps() {
+ return {
+ props: {
+ foo: 'bar',
+ },
+ };
+}
diff --git a/packages/e2e-tests/test-applications/nextjs-app-dir/pages/pages-router/ssr-error-fc.tsx b/packages/e2e-tests/test-applications/nextjs-app-dir/pages/pages-router/ssr-error-fc.tsx
new file mode 100644
index 000000000000..6342caec47ca
--- /dev/null
+++ b/packages/e2e-tests/test-applications/nextjs-app-dir/pages/pages-router/ssr-error-fc.tsx
@@ -0,0 +1,12 @@
+export default function Page() {
+ throw new Error('Pages SSR Error FC');
+ return Hello world!
;
+}
+
+export function getServerSideProps() {
+ return {
+ props: {
+ foo: 'bar',
+ },
+ };
+}
diff --git a/packages/e2e-tests/test-applications/nextjs-app-dir/tests/pages-ssr-errors.test.ts b/packages/e2e-tests/test-applications/nextjs-app-dir/tests/pages-ssr-errors.test.ts
new file mode 100644
index 000000000000..2c1eb9729fdd
--- /dev/null
+++ b/packages/e2e-tests/test-applications/nextjs-app-dir/tests/pages-ssr-errors.test.ts
@@ -0,0 +1,24 @@
+import { test, expect } from '@playwright/test';
+import { waitForError } from '../event-proxy-server';
+
+test('Will capture error for SSR rendering error (Class Component)', async ({ page }) => {
+ const errorEventPromise = waitForError('nextjs-13-app-dir', errorEvent => {
+ return errorEvent?.exception?.values?.[0]?.value === 'Pages SSR Error Class';
+ });
+
+ await page.goto('/pages-router/ssr-error-class');
+
+ const errorEvent = await errorEventPromise;
+ expect(errorEvent).toBeDefined();
+});
+
+test('Will capture error for SSR rendering error (Functional Component)', async ({ page }) => {
+ const errorEventPromise = waitForError('nextjs-13-app-dir', errorEvent => {
+ return errorEvent?.exception?.values?.[0]?.value === 'Pages SSR Error FC';
+ });
+
+ await page.goto('/pages-router/ssr-error-fc');
+
+ const errorEvent = await errorEventPromise;
+ expect(errorEvent).toBeDefined();
+});
diff --git a/packages/nextjs/src/common/index.ts b/packages/nextjs/src/common/index.ts
index 3aeef33af760..2f166b3e4b59 100644
--- a/packages/nextjs/src/common/index.ts
+++ b/packages/nextjs/src/common/index.ts
@@ -41,3 +41,5 @@ export { wrapRouteHandlerWithSentry } from './wrapRouteHandlerWithSentry';
export { wrapApiHandlerWithSentryVercelCrons } from './wrapApiHandlerWithSentryVercelCrons';
export { wrapMiddlewareWithSentry } from './wrapMiddlewareWithSentry';
+
+export { wrapPageComponentWithSentry } from './wrapPageComponentWithSentry';
diff --git a/packages/nextjs/src/common/wrapPageComponentWithSentry.ts b/packages/nextjs/src/common/wrapPageComponentWithSentry.ts
new file mode 100644
index 000000000000..d67dd2a544c0
--- /dev/null
+++ b/packages/nextjs/src/common/wrapPageComponentWithSentry.ts
@@ -0,0 +1,66 @@
+import { captureException } from '@sentry/core';
+import { addExceptionMechanism } from '@sentry/utils';
+
+interface FunctionComponent {
+ (...args: unknown[]): unknown;
+}
+
+interface ClassComponent {
+ new (...args: unknown[]): {
+ render(...args: unknown[]): unknown;
+ };
+}
+
+function isReactClassComponent(target: unknown): target is ClassComponent {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
+ return typeof target === 'function' && target?.prototype?.isReactComponent;
+}
+
+/**
+ * Wraps a page component with Sentry error instrumentation.
+ */
+export function wrapPageComponentWithSentry(pageComponent: FunctionComponent | ClassComponent): unknown {
+ if (isReactClassComponent(pageComponent)) {
+ return class SentryWrappedPageComponent extends pageComponent {
+ public render(...args: unknown[]): unknown {
+ try {
+ return super.render(...args);
+ } catch (e) {
+ captureException(e, scope => {
+ scope.addEventProcessor(event => {
+ addExceptionMechanism(event, {
+ handled: false,
+ });
+ return event;
+ });
+
+ return scope;
+ });
+ throw e;
+ }
+ }
+ };
+ } else if (typeof pageComponent === 'function') {
+ return new Proxy(pageComponent, {
+ apply(target, thisArg, argArray) {
+ try {
+ return target.apply(thisArg, argArray);
+ } catch (e) {
+ captureException(e, scope => {
+ scope.addEventProcessor(event => {
+ addExceptionMechanism(event, {
+ handled: false,
+ });
+ return event;
+ });
+
+ return scope;
+ });
+ throw e;
+ }
+ },
+ });
+ } else {
+ return pageComponent;
+ }
+}
diff --git a/packages/nextjs/src/config/templates/pageWrapperTemplate.ts b/packages/nextjs/src/config/templates/pageWrapperTemplate.ts
index 16cce1a6cc39..c383503f42cf 100644
--- a/packages/nextjs/src/config/templates/pageWrapperTemplate.ts
+++ b/packages/nextjs/src/config/templates/pageWrapperTemplate.ts
@@ -49,7 +49,7 @@ export const getServerSideProps =
? Sentry.wrapGetServerSidePropsWithSentry(origGetServerSideProps, '__ROUTE__')
: undefined;
-export default pageComponent;
+export default pageComponent ? Sentry.wrapPageComponentWithSentry(pageComponent as unknown) : pageComponent;
// Re-export anything exported by the page module we're wrapping. When processing this code, Rollup is smart enough to
// not include anything whose name matchs something we've explicitly exported above.
diff --git a/packages/nextjs/src/index.types.ts b/packages/nextjs/src/index.types.ts
index 479760633b54..804c8f2b3e35 100644
--- a/packages/nextjs/src/index.types.ts
+++ b/packages/nextjs/src/index.types.ts
@@ -186,3 +186,8 @@ export declare function wrapApiHandlerWithSentryVercelCrons(WrappingTarget: C): C;