From 9c28f8322f8a0c13d52e9586681cb047a8468ef1 Mon Sep 17 00:00:00 2001 From: Vercel Date: Thu, 1 Oct 2026 14:26:45 +0000 Subject: [PATCH 1/3] Install and Configure Vercel Speed Insights # Vercel Speed Insights Installation Successfully installed and configured Vercel Speed Insights for this Next.js project. ## Changes Made ### 1. Installed Package - Added `@vercel/speed-insights@^2.0.0` to dependencies - Updated package-lock.json to reflect the new dependency ### 2. Modified Files - **suite/app/layout.tsx**: Added SpeedInsights component to root layout - Imported `SpeedInsights` from `@vercel/speed-insights/next` (Next.js-specific entry point) - Added `` component at the end of the body, after existing Vercel Analytics components - **suite/package.json**: Added the package to dependencies ### 3. Implementation Details - Followed the latest official Vercel documentation from https://vercel.com/docs/speed-insights/quickstart - Used the Next.js App Router-specific import path (`@vercel/speed-insights/next`) - Placed the component in the root layout file to enable tracking across all pages - No environment variables or additional configuration required - Speed Insights will automatically start collecting metrics when deployed to Vercel ## Framework Detection - Confirmed project uses Next.js 16.3.8 with App Router - Package manager: npm (package-lock.json present at root) - Project structure: Monorepo with suite as the Next.js application ## Testing - Verified package installation: `@vercel/speed-insights@2.0.0` successfully installed - Confirmed TypeScript compilation for the Next.js application (existing vitest.config.ts issues are unrelated to this change) - Lock files updated correctly ## Notes - The SpeedInsights component will only collect metrics when deployed to Vercel - No runtime overhead when running locally or on non-Vercel platforms - Metrics will appear in the Vercel dashboard after deployment and sufficient data collection - The implementation follows existing patterns in the codebase (similar to @vercel/analytics already present) Co-authored-by: Vercel --- package-lock.json | 82 +++++++++++++++++++++----------------------- suite/app/layout.tsx | 2 ++ suite/package.json | 1 + 3 files changed, 43 insertions(+), 42 deletions(-) diff --git a/package-lock.json b/package-lock.json index fcdac96a..c75e21d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1531,9 +1531,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1550,9 +1547,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1569,9 +1563,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1588,9 +1579,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1928,9 +1916,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1949,9 +1934,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1970,9 +1952,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1991,9 +1970,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2012,9 +1988,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2033,9 +2006,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4190,6 +4160,44 @@ "node": ">=16.20.0" } }, + "node_modules/@vercel/speed-insights": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@vercel/speed-insights/-/speed-insights-2.0.0.tgz", + "integrity": "sha512-jwkNcrTeafWxjmWq4AHBaptSqZiJkYU5adLC9QBSqeim0GcqDMgN5Ievh8OG1rJ6W3A4l1oiP7qr9CWxGuzu3w==", + "license": "Apache-2.0", + "peerDependencies": { + "@sveltejs/kit": "^1 || ^2", + "next": ">= 13", + "nuxt": ">= 3", + "react": "^18 || ^19 || ^19.0.0-rc", + "svelte": ">= 4", + "vue": "^3", + "vue-router": "^4" + }, + "peerDependenciesMeta": { + "@sveltejs/kit": { + "optional": true + }, + "next": { + "optional": true + }, + "nuxt": { + "optional": true + }, + "react": { + "optional": true + }, + "svelte": { + "optional": true + }, + "vue": { + "optional": true + }, + "vue-router": { + "optional": true + } + } + }, "node_modules/@vitest/coverage-v8": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-5.0.3.tgz", @@ -6400,6 +6408,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } @@ -7521,9 +7530,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -7546,9 +7552,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -7571,9 +7574,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -7596,9 +7596,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -8048,6 +8045,7 @@ "@supabase/ssr": "^0.12.7", "@supabase/supabase-js": "^2.45.0", "@vercel/analytics": "^2.0.1", + "@vercel/speed-insights": "^2.0.0", "clsx": "^2.1.1", "fontkit": "^2.0.4", "framer-motion": "^13.4.0", diff --git a/suite/app/layout.tsx b/suite/app/layout.tsx index 0ac64dca..80a68c4a 100644 --- a/suite/app/layout.tsx +++ b/suite/app/layout.tsx @@ -1,5 +1,6 @@ import type { Metadata } from "next"; import { Lato, Marcellus } from "next/font/google"; +import { SpeedInsights } from "@vercel/speed-insights/next"; import { PageCounts } from "@/components/shell/PageCounts"; import { ReportUnhandled } from "@/components/shell/ReportUnhandled"; import { onVercel, siteUrl } from "@/lib/env"; @@ -62,6 +63,7 @@ export default function RootLayout({ {/* Cookieless page counts on the hosted instance. Vercel serves the endpoint, so a copy hosted anywhere else sends nothing. */} {onVercel() ? : null} + ); diff --git a/suite/package.json b/suite/package.json index f9b53aca..29d3e266 100644 --- a/suite/package.json +++ b/suite/package.json @@ -22,6 +22,7 @@ "@supabase/ssr": "^0.12.7", "@supabase/supabase-js": "^2.45.0", "@vercel/analytics": "^2.0.1", + "@vercel/speed-insights": "^2.0.0", "clsx": "^2.1.1", "fontkit": "^2.0.4", "framer-motion": "^13.4.0", From 445d3de3938b6fd4d664e54aa34d8806277f770f Mon Sep 17 00:00:00 2001 From: Jacob Frusher <99102901+JFrusher@users.noreply.github.com> Date: Fri, 2 Oct 2026 10:13:25 +0100 Subject: [PATCH 2/3] Conditionally render SpeedInsights on Vercel Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Jacob Frusher <99102901+JFrusher@users.noreply.github.com> --- suite/app/layout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/suite/app/layout.tsx b/suite/app/layout.tsx index 80a68c4a..2c7577d9 100644 --- a/suite/app/layout.tsx +++ b/suite/app/layout.tsx @@ -63,7 +63,7 @@ export default function RootLayout({ {/* Cookieless page counts on the hosted instance. Vercel serves the endpoint, so a copy hosted anywhere else sends nothing. */} {onVercel() ? : null} - +{onVercel() ? : null} ); From 31b0d67289cc4e1576c4259ce4bcd6e242d64727 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 2 Oct 2026 09:14:56 +0000 Subject: [PATCH 3/3] Scrub Speed Insights URLs and disclose telemetry Co-authored-by: JFrusher <99102901+JFrusher@users.noreply.github.com> --- suite/app/layout.tsx | 4 ++-- suite/components/shell/Speed.tsx | 9 +++++++++ suite/lib/legal.test.ts | 2 ++ suite/lib/legal.ts | 5 +++-- 4 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 suite/components/shell/Speed.tsx diff --git a/suite/app/layout.tsx b/suite/app/layout.tsx index 2c7577d9..c6d0833b 100644 --- a/suite/app/layout.tsx +++ b/suite/app/layout.tsx @@ -1,8 +1,8 @@ import type { Metadata } from "next"; import { Lato, Marcellus } from "next/font/google"; -import { SpeedInsights } from "@vercel/speed-insights/next"; import { PageCounts } from "@/components/shell/PageCounts"; import { ReportUnhandled } from "@/components/shell/ReportUnhandled"; +import { Speed } from "@/components/shell/Speed"; import { onVercel, siteUrl } from "@/lib/env"; import "./globals.css"; // Before any tool's own stylesheet: each of those maps its vocabulary onto the @@ -63,7 +63,7 @@ export default function RootLayout({ {/* Cookieless page counts on the hosted instance. Vercel serves the endpoint, so a copy hosted anywhere else sends nothing. */} {onVercel() ? : null} -{onVercel() ? : null} + {onVercel() ? : null} ); diff --git a/suite/components/shell/Speed.tsx b/suite/components/shell/Speed.tsx new file mode 100644 index 00000000..aca9a165 --- /dev/null +++ b/suite/components/shell/Speed.tsx @@ -0,0 +1,9 @@ +"use client"; + +import { SpeedInsights } from "@vercel/speed-insights/next"; +import { countedUrl } from "@/lib/pageCounts"; + +/** Hosted performance telemetry, with each address cut to its route first. */ +export function Speed() { + return ({ ...event, url: countedUrl(event.url) })} />; +} diff --git a/suite/lib/legal.test.ts b/suite/lib/legal.test.ts index a02ec83a..f84d3472 100644 --- a/suite/lib/legal.test.ts +++ b/suite/lib/legal.test.ts @@ -55,7 +55,9 @@ test("the visit counting the policy describes is the one the site runs", () => { const layout = readFileSync(join(process.cwd(), "app", "layout.tsx"), "utf8"); const text = policyText(PRIVACY).toLowerCase(); const counts = layout.includes("