diff --git a/bun.lockb b/bun.lockb index ff8211a49..946566f15 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 2b605a6c7..19a31fb98 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@geist-ui/icons": "^1.0.2", - "@gitbook/api": "^0.24.0", + "@gitbook/api": "^0.25.0", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-popover": "^1.0.7", "@readme/openapi-parser": "^2.5.0", diff --git a/src/components/PageBody/PageBody.tsx b/src/components/PageBody/PageBody.tsx index 88e4f5759..19c0e55ac 100644 --- a/src/components/PageBody/PageBody.tsx +++ b/src/components/PageBody/PageBody.tsx @@ -1,6 +1,7 @@ import { CustomizationSettings, JSONDocument, RevisionPageDocument, Space } from '@gitbook/api'; import React from 'react'; +import { api } from '@/lib/api'; import { hasFullWidthBlock } from '@/lib/document'; import { ContentRefContext, resolveContentRef } from '@/lib/references'; import { tcls } from '@/lib/tailwind'; @@ -9,6 +10,7 @@ import { PageCover } from './PageCover'; import { PageFooterNavigation } from './PageFooterNavigation'; import { PageHeader } from './PageHeader'; import { TogglePageFullWidth } from './TogglePageFullWidth'; +import { TrackPageView } from './TrackPageView'; import { DocumentView } from '../DocumentView'; import { PageFeedbackForm } from '../PageFeedback'; @@ -88,6 +90,9 @@ export function PageBody(props: { ) : null} + + + ); } diff --git a/src/components/PageBody/TrackPageView.tsx b/src/components/PageBody/TrackPageView.tsx new file mode 100644 index 000000000..f9302b743 --- /dev/null +++ b/src/components/PageBody/TrackPageView.tsx @@ -0,0 +1,64 @@ +'use client'; + +import type { RequestSpaceTrackPageView } from '@gitbook/api'; +import cookies from 'js-cookie'; +import * as React from 'react'; + +import { getVisitorId } from '@/lib/analytics'; + +/** + * Track the page view for the current page to integrations. + */ +export function TrackPageView(props: { + apiHost: string; + spaceId: string; + pageId: string | undefined; +}) { + const { apiHost, spaceId, pageId } = props; + + React.useEffect(() => { + trackPageView(apiHost, spaceId, pageId); + }, [apiHost, spaceId, pageId]); + + return null; +} + +let latestPageId: string | undefined | null = null; + +/** + * Track the page view for the current page to GitBook. + * We don't use the API client to avoid shipping 80kb of JS to the client. + * And instead use a simple fetch. + */ +async function trackPageView(apiHost: string, spaceId: string, pageId: string | undefined) { + if (pageId === latestPageId) { + // The hook can be called multiple times, we only want to track once. + return; + } + + latestPageId = pageId; + + const visitorId = await getVisitorId(); + const body: RequestSpaceTrackPageView = { + url: window.location.href, + pageId, + visitor: { + anonymousId: visitorId, + userAgent: window.navigator.userAgent, + language: window.navigator.language, + cookies: cookies.get(), + }, + referrer: document.referrer, + }; + + const url = new URL(apiHost); + url.pathname = `/v1/spaces/${spaceId}/insights/track_view`; + + await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(body), + }); +}