Stop tracking events for sites served through /url/ on GitBook's own host

This commit is contained in:
Nolann Biron
2026-09-10 13:12:58 +02:00
parent 415e70f954
commit 031a2e9a56
6 changed files with 30 additions and 10 deletions
@@ -3,3 +3,5 @@
---
Fix analytics and adaptive content silently breaking on sites served from a different host than the one configured (apex vs www, domain alias, CDN). The insights and visitor-claims endpoints are now requested relative to the page's own origin instead of the configured host, which a prerendered page cannot know.
Stop tracking events when a site is served through `/url/:url` on GitBook's own host, the access mode used by local development and preview deployments. That traffic is not the site's and no longer reaches its analytics.
@@ -18,9 +18,13 @@ export default async function SiteDynamicLayout({
params,
children,
}: React.PropsWithChildren<SiteDynamicLayoutProps>) {
const { context, visitorAuthClaims } = await getDynamicSiteContext(await params);
const resolvedParams = await params;
const { context, visitorAuthClaims } = await getDynamicSiteContext(resolvedParams);
const forcedTheme = await getThemeFromMiddleware();
const withTracking = shouldTrackEvents(await headers());
const withTracking = shouldTrackEvents({
mode: resolvedParams.mode,
headers: await headers(),
});
return (
<CustomizationRootLayout
@@ -19,7 +19,10 @@ export default async function RootLayout({
}: React.PropsWithChildren<SiteStaticLayoutProps>) {
const resolvedParams = await params;
const { context, visitorAuthClaims } = await getEmbeddableStaticContext(resolvedParams);
const withTracking = shouldTrackEvents(await headers());
const withTracking = shouldTrackEvents({
mode: resolvedParams.mode,
headers: await headers(),
});
// The forced theme (`?theme=`) comes through the route context (set by the middleware), not a
// request header, so the embed can honor it while staying statically rendered. RND-11571
const forcedTheme = getSiteURLDataFromParams(resolvedParams).embedTheme ?? null;
@@ -15,8 +15,9 @@ export default async function SiteStaticLayout({
params,
children,
}: React.PropsWithChildren<SiteStaticLayoutProps>) {
const { context, visitorAuthClaims } = await getStaticSiteContext(await params);
const withTracking = shouldTrackEvents();
const resolvedParams = await params;
const { context, visitorAuthClaims } = await getStaticSiteContext(resolvedParams);
const withTracking = shouldTrackEvents({ mode: resolvedParams.mode });
return (
<CustomizationRootLayout
@@ -17,7 +17,7 @@ export default async function RootLayout({
}: React.PropsWithChildren<SiteStaticLayoutProps>) {
const resolvedParams = await params;
const { context, visitorAuthClaims } = await getEmbeddableStaticContext(resolvedParams);
const withTracking = shouldTrackEvents();
const withTracking = shouldTrackEvents({ mode: resolvedParams.mode });
// The forced theme (`?theme=`) is threaded through the route context by the middleware so the
// embed stays statically rendered — read it from the params rather than a request header. RND-11571
const forcedTheme = getSiteURLDataFromParams(resolvedParams).embedTheme ?? null;
+14 -4
View File
@@ -9,16 +9,26 @@ import { getLogger } from './logger';
/**
* Return true if events should be tracked on the site.
* Can be called from the static context or the dynamic context.
* In the static context, only an env variable is checked.
* In the dynamic context, the request headers are checked - this allows the middleware
* In the static context, only the env variable and the serving mode are checked.
* In the dynamic context, the request headers are checked too - this allows the middleware
* to disable tracking for preview requests.
*/
export function shouldTrackEvents(headers?: Awaited<ReturnType<typeof nextHeaders>>): boolean {
export function shouldTrackEvents(args: {
/** Serving mode, from the route params. */
mode: string;
headers?: Awaited<ReturnType<typeof nextHeaders>>;
}): boolean {
if (GITBOOK_DISABLE_TRACKING) {
return false;
}
const disableTrackingHeader = headers?.get('x-gitbook-disable-tracking');
// `url` mode only serves `/url/:url` on GitBook's own host — local dev and preview
// deployments. That traffic is not the site's, so it must stay out of its analytics.
if (args.mode === 'url') {
return false;
}
const disableTrackingHeader = args.headers?.get('x-gitbook-disable-tracking');
if (disableTrackingHeader === 'true') {
return false;