Skip to content

Commit 8f5b490

Browse files
committed
feat(product tours): add click tracking to banner actions
1 parent 6015fc5 commit 8f5b490

File tree

5 files changed

+45
-16
lines changed

5 files changed

+45
-16
lines changed

.changeset/two-monkeys-swim.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'posthog-js': patch
3+
---
4+
5+
add banner click tracking for tours

packages/browser/src/extensions/product-tours/components/ProductTourBanner.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { cancelSVG } from '../../surveys/icons'
66
export interface ProductTourBannerProps {
77
step: ProductTourStep
88
onDismiss: () => void
9-
onTriggerTour?: () => void
9+
onActionClick?: () => void
1010
displayFrequency?: ProductTourDisplayFrequency
1111
}
1212

@@ -17,15 +17,16 @@ interface BannerWrapperProps {
1717

1818
interface LinkWrapperProps extends BannerWrapperProps {
1919
href: string
20+
onClick?: () => void
2021
}
2122

2223
interface ButtonWrapperProps extends BannerWrapperProps {
2324
onClick: () => void
2425
}
2526

26-
function LinkWrapper({ class: className, href, children }: LinkWrapperProps): h.JSX.Element {
27+
function LinkWrapper({ class: className, href, onClick, children }: LinkWrapperProps): h.JSX.Element {
2728
return (
28-
<a class={className} href={href} target="_blank" rel="noopener noreferrer">
29+
<a class={className} href={href} target="_blank" rel="noopener noreferrer" onClick={onClick}>
2930
{children}
3031
</a>
3132
)
@@ -58,7 +59,7 @@ function StaticWrapper({ class: className, children }: BannerWrapperProps): h.JS
5859
export function ProductTourBanner({
5960
step,
6061
onDismiss,
61-
onTriggerTour,
62+
onActionClick,
6263
displayFrequency,
6364
}: ProductTourBannerProps): h.JSX.Element {
6465
const config = step.bannerConfig ?? { behavior: 'sticky' }
@@ -97,15 +98,15 @@ export function ProductTourBanner({
9798

9899
if (action?.type === 'link' && action.link) {
99100
return (
100-
<LinkWrapper class={classNames} href={action.link}>
101+
<LinkWrapper class={classNames} href={action.link} onClick={onActionClick}>
101102
{content}
102103
</LinkWrapper>
103104
)
104105
}
105106

106-
if (action?.type === 'trigger_tour' && onTriggerTour) {
107+
if (action?.type === 'trigger_tour' && onActionClick) {
107108
return (
108-
<ButtonWrapper class={classNames} onClick={onTriggerTour}>
109+
<ButtonWrapper class={classNames} onClick={onActionClick}>
109110
{content}
110111
</ButtonWrapper>
111112
)

packages/browser/src/extensions/product-tours/product-tour.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@
335335
}
336336

337337
.ph-tour-button {
338+
text-decoration: none;
338339
display: inline-flex;
339340
align-items: center;
340341
justify-content: center;

packages/browser/src/extensions/product-tours/product-tours.tsx

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,35 @@ export class ProductTourManager {
584584
this._cleanup()
585585
}
586586

587+
private _handleBannerActionClick = (): void => {
588+
if (!this._activeTour) {
589+
return
590+
}
591+
592+
const step = this._getCurrentStep()
593+
if (!step) {
594+
return
595+
}
596+
597+
const action = step.bannerConfig?.action
598+
599+
this._captureEvent(ProductTourEventName.BANNER_ACTION_CLICKED, {
600+
[ProductTourEventProperties.TOUR_ID]: this._activeTour.id,
601+
[ProductTourEventProperties.TOUR_NAME]: this._activeTour.name,
602+
[ProductTourEventProperties.TOUR_ITERATION]: this._activeTour.current_iteration || 1,
603+
[ProductTourEventProperties.TOUR_STEP_ID]: step.id,
604+
[ProductTourEventProperties.TOUR_STEP_ORDER]: this._currentStepIndex,
605+
[ProductTourEventProperties.TOUR_BUTTON_ACTION]: action?.type,
606+
[ProductTourEventProperties.TOUR_BUTTON_LINK]: action?.link,
607+
[ProductTourEventProperties.TOUR_BUTTON_TOUR_ID]: action?.tourId,
608+
})
609+
610+
if (action?.type === 'trigger_tour' && action.tourId) {
611+
this._cleanup()
612+
this.showTourById(action.tourId)
613+
}
614+
}
615+
587616
private _handleButtonClick = (button: ProductTourStepButton): void => {
588617
if (this._activeTour) {
589618
const currentStep = this._activeTour.steps[this._currentStepIndex]
@@ -821,19 +850,11 @@ export class ProductTourManager {
821850

822851
const { shadow } = result
823852

824-
const handleTriggerTour = () => {
825-
const tourId = step.bannerConfig?.action?.tourId
826-
if (tourId) {
827-
this._cleanup()
828-
this.showTourById(tourId)
829-
}
830-
}
831-
832853
render(
833854
<ProductTourBanner
834855
step={step}
835856
onDismiss={() => this.dismissTour('user_clicked_skip')}
836-
onTriggerTour={handleTriggerTour}
857+
onActionClick={this._handleBannerActionClick}
837858
displayFrequency={this._activeTour.display_frequency}
838859
/>,
839860
shadow

packages/browser/src/posthog-product-tours-types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ export enum ProductTourEventName {
197197
BUTTON_CLICKED = 'product tour button clicked',
198198
STEP_SELECTOR_FAILED = 'product tour step selector failed',
199199
BANNER_CONTAINER_SELECTOR_FAILED = 'product tour banner container selector failed',
200+
BANNER_ACTION_CLICKED = 'product tour banner action clicked',
200201
}
201202

202203
export enum ProductTourEventProperties {

0 commit comments

Comments
 (0)