diff --git a/app/layout.tsx b/app/layout.tsx
index 9eb58a9c..e724ee9a 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,19 +1,21 @@
import Analytics from '../components/head/Analytics';
import GoogleTagManagerScript from '../components/head/GoogleTagManagerScript';
+import RollbarScript from '../components/head/RollbarScript';
import ErrorBoundary from '../components/layout/ErrorBoundary';
+import { newRelicInit } from '../config/newRelic';
import rootMetadata from './rootMetadata';
-import RollbarScript from '../components/head/RollbarScript';
import ThemeRegistry from './ThemeRegistry';
export const metadata = rootMetadata;
-export default function RootLayout({
+export default async function RootLayout({
// Layouts must accept a children prop.
// This will be populated with nested layouts or pages
children,
}: {
children: React.ReactNode;
}) {
+ const NewRelicScript = await newRelicInit();
return (
@@ -26,6 +28,7 @@ export default function RootLayout({
{children}
+ {NewRelicScript}
diff --git a/config/newRelic.tsx b/config/newRelic.tsx
new file mode 100644
index 00000000..281586bb
--- /dev/null
+++ b/config/newRelic.tsx
@@ -0,0 +1,46 @@
+import newrelic from 'newrelic';
+import Script from 'next/script';
+
+// Configuration according to Newrelic app router example
+// See https://github.com/newrelic/newrelic-node-nextjs?tab=readme-ov-file#example-projects
+export const newRelicInit = async () => {
+ // @ts-ignore
+ if (newrelic.agent.collector.isConnected() === false) {
+ await new Promise((resolve) => {
+ // @ts-ignore
+ newrelic.agent.on('connected', resolve);
+ });
+ }
+
+ const browserTimingHeader = newrelic.getBrowserTimingHeader({
+ hasToRemoveScriptWrapper: true,
+ // @ts-ignore
+ allowTransactionlessInjection: true,
+ });
+
+ return ;
+};
+
+export type NewRelicScriptProps = {
+ browserTimingHeader: string;
+};
+
+const NewRelicScript = ({ browserTimingHeader }: NewRelicScriptProps) => {
+ return (
+ // eslint-disable-next-line @next/next/no-before-interactive-script-outside-document
+
+ );
+};
diff --git a/next.config.js b/next.config.js
index c0146d37..490617fe 100644
--- a/next.config.js
+++ b/next.config.js
@@ -14,8 +14,26 @@ const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});
+// Configuration according to Newrelic app router example
+// See https://github.com/newrelic/newrelic-node-nextjs?tab=readme-ov-file#example-projects
+const nrExternals = require('@newrelic/next/load-externals');
+
module.exports = withBundleAnalyzer(
withPWA({
+ experimental: {
+ // Without this setting, the Next.js compilation step will routinely
+ // try to import files such as `LICENSE` from the `newrelic` module.
+ // See https://nextjs.org/docs/app/api-reference/next-config-js/serverComponentsExternalPackages.
+ serverComponentsExternalPackages: ['newrelic'],
+ },
+
+ // In order for newrelic to effectively instrument a Next.js application,
+ // the modules that newrelic supports should not be mangled by webpack. Thus,
+ // we need to "externalize" all of the modules that newrelic supports.
+ webpack: (config) => {
+ nrExternals(config);
+ return config;
+ },
reactStrictMode: true,
publicRuntimeConfig: {
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,