Skip to content

Commit

Permalink
feat(web-analytics): Add web analytics to onboarding (#25239)
Browse files Browse the repository at this point in the history
  • Loading branch information
robbie-c authored Oct 3, 2024
1 parent 02bf6bb commit a561868
Show file tree
Hide file tree
Showing 28 changed files with 402 additions and 3 deletions.
Binary file modified frontend/__snapshots__/scenes-other-products--products--dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
65 changes: 65 additions & 0 deletions frontend/src/scenes/onboarding/Onboarding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
import { useEffect, useState } from 'react'
import { billingLogic } from 'scenes/billing/billingLogic'
import { newDashboardLogic } from 'scenes/dashboard/newDashboardLogic'
import { WebAnalyticsSDKInstructions } from 'scenes/onboarding/sdks/web-analytics/WebAnalyticsSDKInstructions'
import { SceneExport } from 'scenes/sceneTypes'
import { teamLogic } from 'scenes/teamLogic'
import { userLogic } from 'scenes/userLogic'
Expand Down Expand Up @@ -185,6 +186,69 @@ const ProductAnalyticsOnboarding = (): JSX.Element => {
</OnboardingWrapper>
)
}

const WebAnalyticsOnboarding = (): JSX.Element => {
const { currentTeam } = useValues(teamLogic)

const options: ProductConfigOption[] = [
{
title: 'Autocapture frontend interactions',
description: `If you use our JavaScript or React Native libraries, we'll automagically
capture frontend interactions like clicks, submits, and more. Fine-tune what you
capture directly in your code snippet.`,
teamProperty: 'autocapture_opt_out',
value: !currentTeam?.autocapture_opt_out,
type: 'toggle',
inverseToggle: true,
visible: true,
},
{
title: 'Enable heatmaps',
description: `If you use our JavaScript libraries, we can capture general clicks, mouse movements,
and scrolling to create heatmaps.
No additional events are created, and you can disable this at any time.`,
teamProperty: 'heatmaps_opt_in',
value: currentTeam?.heatmaps_opt_in ?? true,
type: 'toggle',
visible: true,
},
{
title: 'Enable web vitals autocapture',
description: `Uses Google's web vitals library to automagically capture performance information.`,
teamProperty: 'autocapture_web_vitals_opt_in',
value: currentTeam?.autocapture_web_vitals_opt_in ?? true,
type: 'toggle',
visible: true,
},
{
title: 'Enable session recordings',
description: `Turn on session recordings and watch how users experience your app. We will also turn on console log and network performance recording. You can change these settings any time in the settings panel.`,
teamProperty: 'session_recording_opt_in',
value: currentTeam?.session_recording_opt_in ?? true,
type: 'toggle',
visible: true,
},
{
title: 'Capture network performance',
description: `Automatically enable network performance capture`,
teamProperty: 'capture_performance_opt_in',
value: true,
type: 'toggle',
visible: false,
},
]

return (
<OnboardingWrapper>
<SDKs
usersAction="collecting events"
sdkInstructionMap={WebAnalyticsSDKInstructions}
stepKey={OnboardingStepKey.INSTALL}
/>
<OnboardingProductConfiguration stepKey={OnboardingStepKey.PRODUCT_CONFIGURATION} options={options} />
</OnboardingWrapper>
)
}
const SessionReplayOnboarding = (): JSX.Element => {
const { hasAvailableFeature } = useValues(userLogic)
const { currentTeam } = useValues(teamLogic)
Expand Down Expand Up @@ -284,6 +348,7 @@ const DataWarehouseOnboarding = (): JSX.Element => {

export const onboardingViews = {
[ProductKey.PRODUCT_ANALYTICS]: ProductAnalyticsOnboarding,
[ProductKey.WEB_ANALYTICS]: WebAnalyticsOnboarding,
[ProductKey.SESSION_REPLAY]: SessionReplayOnboarding,
[ProductKey.FEATURE_FLAGS]: FeatureFlagsOnboarding,
[ProductKey.SURVEYS]: SurveysOnboarding,
Expand Down
9 changes: 8 additions & 1 deletion frontend/src/scenes/onboarding/onboardingLogic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ export const availableOnboardingProducts: AvailableOnboardingProducts = {
url: urls.insights(),
scene: Scene.SavedInsights,
},
[ProductKey.WEB_ANALYTICS]: {
name: 'Web Analytics',
icon: 'IconPieChart',
iconColor: 'var(--warning)',
url: urls.webAnalytics(),
scene: Scene.WebAnalytics,
},
[ProductKey.DATA_WAREHOUSE]: {
name: 'Data Warehouse',
icon: 'IconDatabase',
Expand All @@ -73,7 +80,7 @@ export const availableOnboardingProducts: AvailableOnboardingProducts = {
[ProductKey.SURVEYS]: {
name: 'Surveys',
icon: 'IconMessage',
iconColor: 'salmon',
iconColor: 'blue',
url: urls.surveys(),
scene: Scene.Surveys,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,26 @@ export function SDKInstallAndroidInstructions(props: AndroidSetupProps): JSX.Ele
</>
)
}

export function SDKInstallAndroidTrackScreenInstructions(): JSX.Element {
return (
<>
<p>
With <code>captureScreenViews = true</code>, PostHog will try to record all screen changes
automatically.
</p>
<p>
If you want to manually send a new screen capture event, use the <code>screen</code> function.
</p>
<CodeSnippet language={Language.Kotlin}>{`import com.posthog.PostHog
PostHog.screen(
screenTitle = "Dashboard",
properties = mapOf(
"background" to "blue",
"hero" to "superhog"
)
)`}</CodeSnippet>
</>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,20 @@ export function SDKInstallIOSInstructions(props: iOSSetupProps): JSX.Element {
</>
)
}

export function SDKInstallIOSTrackScreenInstructions(): JSX.Element {
return (
<>
<p>
With <code>configuration.captureScreenViews</code> set as <code>true</code>, PostHog will try to record
all screen changes automatically.
</p>
<p>
If you want to manually send a new screen capture event, use the <code>screen</code> function.
</p>
<CodeSnippet
language={Language.Swift}
>{`PostHogSDK.shared.screen("Dashboard", properties: ["fromIcon": "bottom"])`}</CodeSnippet>
</>
)
}
34 changes: 34 additions & 0 deletions frontend/src/scenes/onboarding/sdks/web-analytics/FinalSteps.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { CodeSnippet, Language } from 'lib/components/CodeSnippet'

function JSEventSnippet(): JSX.Element {
return (
<CodeSnippet language={Language.JavaScript}>{`posthog.capture('my event', { property: 'value' })`}</CodeSnippet>
)
}

export const WebAnalyticsAllJSFinalSteps = (): JSX.Element => {
return (
<>
<h4>Send events</h4>
<p>
Click around and view a couple pages to generate some events. Our package automatically captures them
for you.
</p>
<h4>Optional: Send a manual event</h4>
<p>If you'd like, you can manually define events, too.</p>
<JSEventSnippet />
</>
)
}

export const WebAnalyticsMobileFinalSteps = (): JSX.Element => {
return (
<>
<h3>Track screen views</h3>
<p>
Despite the name, the web analytics dashboard can be used to track screen views in mobile apps, too.
Open your app and view some screens to generate some events.
</p>
</>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { SDKInstructionsMap, SDKKey } from '~/types'

import {
AndroidInstructions,
AngularInstructions,
AstroInstructions,
BubbleInstructions,
FramerInstructions,
HTMLSnippetInstructions,
iOSInstructions,
JSWebInstructions,
NextJSInstructions,
NuxtJSInstructions,
ReactInstructions,
RemixInstructions,
SvelteInstructions,
VueInstructions,
WebAnalyticsRNInstructions,
WebflowInstructions,
} from '.'

export const WebAnalyticsSDKInstructions: SDKInstructionsMap = {
[SDKKey.JS_WEB]: JSWebInstructions,
[SDKKey.HTML_SNIPPET]: HTMLSnippetInstructions,
[SDKKey.ANGULAR]: AngularInstructions,
[SDKKey.ASTRO]: AstroInstructions,
[SDKKey.IOS]: iOSInstructions,
[SDKKey.BUBBLE]: BubbleInstructions,
[SDKKey.FRAMER]: FramerInstructions,
[SDKKey.NEXT_JS]: NextJSInstructions,
[SDKKey.NUXT_JS]: NuxtJSInstructions,
[SDKKey.REACT]: ReactInstructions,
[SDKKey.REMIX]: RemixInstructions,
[SDKKey.SVELTE]: SvelteInstructions,
[SDKKey.VUE_JS]: VueInstructions,
[SDKKey.WEBFLOW]: WebflowInstructions,
[SDKKey.ANDROID]: AndroidInstructions,
[SDKKey.REACT_NATIVE]: WebAnalyticsRNInstructions,
}
13 changes: 13 additions & 0 deletions frontend/src/scenes/onboarding/sdks/web-analytics/android.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { WebAnalyticsMobileFinalSteps } from 'scenes/onboarding/sdks/web-analytics/FinalSteps'

import { SDKInstallAndroidInstructions, SDKInstallAndroidTrackScreenInstructions } from '../sdk-install-instructions'

export function AndroidInstructions(): JSX.Element {
return (
<>
<SDKInstallAndroidInstructions includeReplay={false} />
<WebAnalyticsMobileFinalSteps />
<SDKInstallAndroidTrackScreenInstructions />
</>
)
}
11 changes: 11 additions & 0 deletions frontend/src/scenes/onboarding/sdks/web-analytics/angular.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { SDKInstallAngularInstructions } from '../sdk-install-instructions'
import { WebAnalyticsAllJSFinalSteps } from './FinalSteps'

export function AngularInstructions(): JSX.Element {
return (
<>
<SDKInstallAngularInstructions />
<WebAnalyticsAllJSFinalSteps />
</>
)
}
11 changes: 11 additions & 0 deletions frontend/src/scenes/onboarding/sdks/web-analytics/astro.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { SDKInstallAstroInstructions } from '../sdk-install-instructions'
import { WebAnalyticsAllJSFinalSteps } from './FinalSteps'

export function AstroInstructions(): JSX.Element {
return (
<>
<SDKInstallAstroInstructions />
<WebAnalyticsAllJSFinalSteps />
</>
)
}
11 changes: 11 additions & 0 deletions frontend/src/scenes/onboarding/sdks/web-analytics/bubble.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { SDKInstallBubbleInstructions } from '../sdk-install-instructions'
import { WebAnalyticsAllJSFinalSteps } from './FinalSteps'

export function BubbleInstructions(): JSX.Element {
return (
<>
<SDKInstallBubbleInstructions />
<WebAnalyticsAllJSFinalSteps />
</>
)
}
11 changes: 11 additions & 0 deletions frontend/src/scenes/onboarding/sdks/web-analytics/framer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { SDKInstallFramerInstructions } from '../sdk-install-instructions'
import { WebAnalyticsAllJSFinalSteps } from './FinalSteps'

export function FramerInstructions(): JSX.Element {
return (
<>
<SDKInstallFramerInstructions />
<WebAnalyticsAllJSFinalSteps />
</>
)
}
11 changes: 11 additions & 0 deletions frontend/src/scenes/onboarding/sdks/web-analytics/html-snippet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { SDKHtmlSnippetInstructions } from '../sdk-install-instructions/html-snippet'
import { WebAnalyticsAllJSFinalSteps } from './FinalSteps'

export function HTMLSnippetInstructions(): JSX.Element {
return (
<>
<SDKHtmlSnippetInstructions />
<WebAnalyticsAllJSFinalSteps />
</>
)
}
16 changes: 16 additions & 0 deletions frontend/src/scenes/onboarding/sdks/web-analytics/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export * from './android'
export * from './angular'
export * from './astro'
export * from './bubble'
export * from './framer'
export * from './html-snippet'
export * from './ios'
export * from './js-web'
export * from './next-js'
export * from './nuxt'
export * from './react'
export * from './react-native'
export * from './remix'
export * from './svelte'
export * from './vue'
export * from './webflow'
13 changes: 13 additions & 0 deletions frontend/src/scenes/onboarding/sdks/web-analytics/ios.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { WebAnalyticsMobileFinalSteps } from 'scenes/onboarding/sdks/web-analytics/FinalSteps'

import { SDKInstallIOSInstructions, SDKInstallIOSTrackScreenInstructions } from '../sdk-install-instructions'

export function iOSInstructions(): JSX.Element {
return (
<>
<SDKInstallIOSInstructions includeReplay={false} />
<WebAnalyticsMobileFinalSteps />
<SDKInstallIOSTrackScreenInstructions />
</>
)
}
11 changes: 11 additions & 0 deletions frontend/src/scenes/onboarding/sdks/web-analytics/js-web.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { SDKInstallJSWebInstructions } from '../sdk-install-instructions'
import { WebAnalyticsAllJSFinalSteps } from './FinalSteps'

export function JSWebInstructions(): JSX.Element {
return (
<>
<SDKInstallJSWebInstructions />
<WebAnalyticsAllJSFinalSteps />
</>
)
}
11 changes: 11 additions & 0 deletions frontend/src/scenes/onboarding/sdks/web-analytics/next-js.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { SDKInstallNextJSInstructions } from '../sdk-install-instructions/next-js'
import { WebAnalyticsAllJSFinalSteps } from './FinalSteps'

export function NextJSInstructions(): JSX.Element {
return (
<>
<SDKInstallNextJSInstructions />
<WebAnalyticsAllJSFinalSteps />
</>
)
}
11 changes: 11 additions & 0 deletions frontend/src/scenes/onboarding/sdks/web-analytics/nuxt.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { SDKInstallNuxtJSInstructions } from '../sdk-install-instructions/nuxt'
import { WebAnalyticsAllJSFinalSteps } from './FinalSteps'

export function NuxtJSInstructions(): JSX.Element {
return (
<>
<SDKInstallNuxtJSInstructions />
<WebAnalyticsAllJSFinalSteps />
</>
)
}
26 changes: 26 additions & 0 deletions frontend/src/scenes/onboarding/sdks/web-analytics/react-native.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { CodeSnippet, Language } from 'lib/components/CodeSnippet'
import { WebAnalyticsMobileFinalSteps } from 'scenes/onboarding/sdks/web-analytics/FinalSteps'

import { SDKInstallRNInstructions } from '../sdk-install-instructions'

export function WebAnalyticsRNInstructions(): JSX.Element {
return (
<>
<SDKInstallRNInstructions />
<h3 className="mt-4">Optional: Send a manual event</h3>
<p>Our package will autocapture events for you, but you can manually define events, too!</p>
<CodeSnippet language={Language.JSX}>{`// With hooks
import { usePostHog } from 'posthog-react-native'
const MyComponent = () => {
const posthog = usePostHog()
useEffect(() => {
posthog.capture("MyComponent loaded", { foo: "bar" })
}, [])
}
`}</CodeSnippet>
<WebAnalyticsMobileFinalSteps />
</>
)
}
Loading

0 comments on commit a561868

Please sign in to comment.