Skip to content

Commit

Permalink
track additional browse events in posthog (#2011)
Browse files Browse the repository at this point in the history
* fire a posthog event when clicking the "Topic" link on the homepage in "Browse by Topic"

* add events for homepage browse topics section

* wrap new events in posthog api key check

* track topic_clicked vs subtopic_clicked on topics listing page

* properly set subtopic name

* properly track clicking a subtopic vs related topic on the topic channel page

* consolidate posthog events to a constants file
  • Loading branch information
gumaerc authored Feb 5, 2025
1 parent 7967bcf commit d185a7a
Show file tree
Hide file tree
Showing 12 changed files with 144 additions and 47 deletions.
28 changes: 13 additions & 15 deletions frontends/main/src/app-pages/ChannelPage/TopicChannelTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { propsNotNil, backgroundSrcSetCSS } from "ol-utilities"
import invariant from "tiny-invariant"
import backgroundSteps from "@/public/images/backgrounds/background_steps.jpg"
import { usePostHog } from "posthog-js/react"
import { PostHogEvents } from "@/common/constants"

const ChildrenContainer = styled.div(({ theme }) => ({
paddingTop: "40px",
Expand Down Expand Up @@ -79,14 +80,18 @@ const BannerSkeleton = styled(Skeleton)(({ theme }) => ({
}))

type TopicChipsInternalProps = {
title: string
topicId: number
parentTopicId: number
isTopLevelTopic: boolean
}

const TopicChipsInternal: React.FC<TopicChipsInternalProps> = (props) => {
const posthog = usePostHog()
const { title, topicId, parentTopicId } = props
const { topicId, parentTopicId, isTopLevelTopic } = props
const title = isTopLevelTopic ? "Subtopics" : "Related Topics"
const posthogEvent = isTopLevelTopic
? PostHogEvents.SubTopicClicked
: PostHogEvents.RelatedTopicClicked
const subTopicsQuery = useLearningResourceTopics({
parent_topic_id: [parentTopicId],
})
Expand All @@ -106,7 +111,7 @@ const TopicChipsInternal: React.FC<TopicChipsInternalProps> = (props) => {
href={topic.channel_url ?? ""}
onClick={() => {
if (process.env.NEXT_PUBLIC_POSTHOG_API_KEY) {
posthog.capture("related_topic_link_clicked", { topic })
posthog.capture(posthogEvent, { topic })
}
}}
label={topic.name}
Expand All @@ -127,24 +132,17 @@ const TopicChips: React.FC<TopicChipsProps> = (props) => {
return null
}
const isTopLevelTopic = topic?.parent === null
const parentTopicId = isTopLevelTopic ? topic.id : topic?.parent

if (isTopLevelTopic) {
if (parentTopicId) {
return (
<TopicChipsInternal
title="Subtopics"
topicId={topic.id}
parentTopicId={topic.id}
parentTopicId={parentTopicId}
isTopLevelTopic={isTopLevelTopic}
/>
)
} else if (topic?.parent) {
return (
<TopicChipsInternal
title="Related Topics"
topicId={topic.id}
parentTopicId={topic?.parent}
/>
)
} else return null
}
}

type SubTopicBreadcrumbsProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import backgroundSteps from "@/public/images/backgrounds/background_steps.jpg"
import { aggregateProgramCounts, aggregateCourseCounts } from "@/common/utils"
import { useChannelCounts } from "api/hooks/channels"
import { usePostHog } from "posthog-js/react"
import { PostHogEvents } from "@/common/constants"

const SCHOOL_ICONS: Record<string, React.ReactNode> = {
// School of Architecture and Planning
Expand Down Expand Up @@ -155,7 +156,9 @@ const SchoolDepartments: React.FC<SchoolDepartmentProps> = ({
new URL(department.channel_url).pathname
}
onClick={() => {
posthog.capture("department_link_clicked", { department })
posthog.capture(PostHogEvents.DepartmentLinkClicked, {
department,
})
}}
>
<ListItemText
Expand Down
21 changes: 20 additions & 1 deletion frontends/main/src/app-pages/HomePage/BrowseTopicsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { ButtonLink } from "@mitodl/smoot-design"
import { useLearningResourceTopics } from "api/hooks/learningResources"
import { RiArrowRightLine } from "@remixicon/react"
import RootTopicIcon from "@/components/RootTopicIcon/RootTopicIcon"
import { usePostHog } from "posthog-js/react"
import { PostHogEvents } from "@/common/constants"

const Section = styled.section`
background: #fff url("/images/backgrounds/open-bg-texture-with-gradient.svg")
Expand Down Expand Up @@ -104,6 +106,7 @@ const SeeAllButton = styled(ButtonLink)`
`

const BrowseTopicsSection: React.FC = () => {
const posthog = usePostHog()
const { data: topics } = useLearningResourceTopics({ is_toplevel: true })

return (
Expand All @@ -119,6 +122,13 @@ const BrowseTopicsSection: React.FC = () => {
<TopicBox
key={id}
href={channelUrl ? new URL(channelUrl!).pathname : ""}
onClick={() => {
if (process.env.NEXT_PUBLIC_POSTHOG_API_KEY) {
posthog.capture(PostHogEvents.HomeTopicClicked, {
topic: name,
})
}
}}
>
<TopicBoxContent>
<RootTopicIcon icon={icon} />
Expand All @@ -130,7 +140,16 @@ const BrowseTopicsSection: React.FC = () => {
},
)}
</Topics>
<SeeAllButton href="/topics/" size="large" responsive>
<SeeAllButton
href="/topics/"
onClick={() => {
if (process.env.NEXT_PUBLIC_POSTHOG_API_KEY) {
posthog.capture(PostHogEvents.HomeSeeAllTopicsClicked)
}
}}
size="large"
responsive
>
See all
</SeeAllButton>
</Container>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ import { aggregateProgramCounts, aggregateCourseCounts } from "@/common/utils"
import { useChannelCounts } from "api/hooks/channels"
import backgroundSteps from "@/public/images/backgrounds/background_steps.jpg"
import { usePostHog } from "posthog-js/react"
import type { PostHog } from "posthog-js"
import { PostHogEvents } from "@/common/constants"

const captureTopicClicked = (
posthog: PostHog,
event: string,
topic: string,
) => {
if (process.env.NEXT_PUBLIC_POSTHOG_API_KEY) {
posthog.capture(event, { topic })
}
}

type ChannelSummary = {
id: number | string
Expand All @@ -37,12 +49,20 @@ type TopicBoxHeaderProps = {
icon?: string
href?: string
className?: string
posthog?: PostHog
}
const TopicBoxHeader = styled(
({ title, icon, href, className }: TopicBoxHeaderProps) => {
({ title, icon, href, className, posthog }: TopicBoxHeaderProps) => {
return (
<Typography variant="h5" component="h2" className={className}>
<Link href={href ?? ""}>
<Link
href={href ?? ""}
onClick={() => {
if (posthog) {
captureTopicClicked(posthog, PostHogEvents.TopicClicked, title)
}
}}
>
<RootTopicIcon icon={icon} aria-hidden="true" />
<span>
<span className="topic-title">{title}</span>
Expand Down Expand Up @@ -131,15 +151,10 @@ const TopicBox = ({
{ label: "Programs", count: programCount },
].filter((item) => item.count)
const { title, href, icon, channels } = topicGroup
const captureTopicClicked = (topic: string) => {
if (process.env.NEXT_PUBLIC_POSTHOG_API_KEY) {
posthog.capture("topic_clicked", { topic })
}
}

return (
<li className={className}>
<TopicBoxHeader title={title} href={href} icon={icon} />
<TopicBoxHeader title={title} href={href} icon={icon} posthog={posthog} />
<TopicBoxBody>
<TopicCounts>
{counts.map((item) => (
Expand All @@ -156,7 +171,11 @@ const TopicBox = ({
key={c.id}
href={c.channel_url && new URL(c.channel_url).pathname}
onClick={() => {
captureTopicClicked(title)
captureTopicClicked(
posthog,
PostHogEvents.SubTopicClicked,
c.name,
)
}}
label={c.name}
/>
Expand All @@ -170,7 +189,11 @@ const TopicBox = ({
key={c.id}
href={c.channel_url && new URL(c.channel_url).pathname}
onClick={() => {
captureTopicClicked(title)
captureTopicClicked(
posthog,
PostHogEvents.SubTopicClicked,
c.name,
)
}}
label={c.name}
/>
Expand Down
5 changes: 4 additions & 1 deletion frontends/main/src/app-pages/UnitsListingPage/UnitCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from "ol-components"
import Link from "next/link"
import { usePostHog } from "posthog-js/react"
import { PostHogEvents } from "@/common/constants"

const CardStyled = styled(Card)({
height: "100%",
Expand Down Expand Up @@ -132,7 +133,9 @@ const UnitCard: React.FC<UnitCardProps> = (props) => {
href={href}
onClick={() => {
if (process.env.NEXT_PUBLIC_POSTHOG_API_KEY) {
posthog.capture("provider_link_clicked", { provider: unit })
posthog.capture(PostHogEvents.ProviderLinkClicked, {
provider: unit,
})
}
}}
data-card-link
Expand Down
28 changes: 28 additions & 0 deletions frontends/main/src/common/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export const PostHogEvents = {
SearchUpdate: "search_update",
CallToActionClicked: "cta_clicked",
LearningResourceDrawerOpen: "lrd_open",
LearningResourceDrawerView: "lrd_view",
HeroBrowseTopics: "clicked_hero_browse_topics",
LRAddToList: "lr_add_to_list",
ProviderLinkClicked: "provider_link_clicked",
HomeTopicClicked: "home_topic_clicked",
HomeSeeAllTopicsClicked: "home_see_all_topics_clicked",
TopicClicked: "topic_clicked",
SubTopicClicked: "sub_topic_clicked",
RelatedTopicClicked: "related_topic_clicked",
DepartmentLinkClicked: "department_link_clicked",
ClosedNavDrawer: "closed_nav_drawer",
OpenedNavDrawer: "opened_nav_drawer",
ClickedNavBrowseCourses: "clicked_nav_browse_courses",
ClickedNavBrowsePrograms: "clicked_nav_browse_programs",
ClickedNavBrowseLearningMaterials: "clicked_nav_browse_learning_materials",
ClickedNavBrowseTopics: "clicked_nav_browse_topics",
ClickedNavBrowseDepartments: "clicked_nav_browse_departments",
ClickedNavBrowseProviders: "clicked_nav_browse_providers",
ClickedNavBrowseNew: "clicked_nav_browse_new",
ClickedNavBrowseUpcoming: "clicked_nav_browse_upcoming",
ClickedNavBrowsePopular: "clicked_nav_browse_popular",
ClickedNavBrowseFree: "clicked_nav_browse_free",
ClickedNavBrowseCertificate: "clicked_nav_browse_certificate",
} as const
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
import { manageListDialogs } from "@/page-components/ManageListDialogs/ManageListDialogs"
import { ListType } from "api/constants"
import { useFormik } from "formik"
import { PostHogEvents } from "@/common/constants"

const LIST_LIMIT = 100

Expand Down Expand Up @@ -101,7 +102,7 @@ const AddToListDialogInner: React.FC<AddToListDialogInnerProps> = ({
onSubmit: async (values) => {
if (resource) {
if (process.env.NEXT_PUBLIC_POSTHOG_API_KEY) {
posthog.capture("lr_add_to_list", {
posthog.capture(PostHogEvents.LRAddToList, {
listType: listType,
resourceId: resource?.id,
readableId: resource?.readable_id,
Expand Down
27 changes: 14 additions & 13 deletions frontends/main/src/page-components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
} from "@/common/urls"
import { useUserMe } from "api/hooks/user"
import { usePostHog } from "posthog-js/react"
import { PostHogEvents } from "@/common/constants"

const Bar = styled(AppBar)(({ theme }) => ({
padding: "16px 8px",
Expand Down Expand Up @@ -188,23 +189,23 @@ const navData: NavData = {
description:
"Single courses on a specific subject, taught by MIT instructors",
href: SEARCH_COURSE,
posthogEvent: "clicked_nav_browse_courses",
posthogEvent: PostHogEvents.ClickedNavBrowseCourses,
},
{
title: "Programs",
icon: <RiStackLine />,
description:
"A series of courses for in-depth learning across a range of topics",
href: SEARCH_PROGRAM,
posthogEvent: "clicked_nav_browse_programs",
posthogEvent: PostHogEvents.ClickedNavBrowsePrograms,
},
{
title: "Learning Materials",
icon: <RiBookMarkedLine />,
description:
"Free learning and teaching materials, including videos, podcasts, lecture notes, and more",
href: SEARCH_LEARNING_MATERIAL,
posthogEvent: "clicked_nav_browse_learning_materials",
posthogEvent: PostHogEvents.ClickedNavBrowseLearningMaterials,
},
],
},
Expand All @@ -215,19 +216,19 @@ const navData: NavData = {
title: "By Topic",
icon: <RiPresentationLine />,
href: TOPICS,
posthogEvent: "clicked_nav_browse_topics",
posthogEvent: PostHogEvents.ClickedNavBrowseTopics,
},
{
title: "By Department",
icon: <RiNodeTree />,
href: DEPARTMENTS,
posthogEvent: "clicked_nav_browse_departments",
posthogEvent: PostHogEvents.ClickedNavBrowseDepartments,
},
{
title: "By Provider",
icon: <RiVerifiedBadgeLine />,
href: UNITS,
posthogEvent: "clicked_nav_browse_providers",
posthogEvent: PostHogEvents.ClickedNavBrowseProviders,
},
],
},
Expand All @@ -238,31 +239,31 @@ const navData: NavData = {
title: "Recently Added",
icon: <RiFileAddLine />,
href: SEARCH_NEW,
posthogEvent: "clicked_nav_browse_new",
posthogEvent: PostHogEvents.ClickedNavBrowseNew,
},
{
title: "Upcoming",
icon: <RiTimeLine />,
href: SEARCH_UPCOMING,
posthogEvent: "clicked_nav_browse_upcoming",
posthogEvent: PostHogEvents.ClickedNavBrowseUpcoming,
},
{
title: "Popular",
href: SEARCH_POPULAR,
icon: <RiHeartLine />,
posthogEvent: "clicked_nav_browse_popular",
posthogEvent: PostHogEvents.ClickedNavBrowsePopular,
},
{
title: "Free",
icon: <RiPriceTag3Line />,
href: SEARCH_FREE,
posthogEvent: "clicked_nav_browse_free",
posthogEvent: PostHogEvents.ClickedNavBrowseFree,
},
{
title: "With Certificate",
icon: <RiAwardLine />,
href: SEARCH_CERTIFICATE,
posthogEvent: "clicked_nav_browse_certificate",
posthogEvent: PostHogEvents.ClickedNavBrowseCertificate,
},
],
},
Expand All @@ -275,8 +276,8 @@ const Header: FunctionComponent = () => {
const desktopTrigger = React.useRef<HTMLButtonElement>(null)
const mobileTrigger = React.useRef<HTMLButtonElement>(null)
const drawerToggleEvent = drawerOpen
? "closed_nav_drawer"
: "opened_nav_drawer"
? PostHogEvents.ClosedNavDrawer
: PostHogEvents.OpenedNavDrawer
const posthogCapture = (event: string) => {
if (process.env.NEXT_PUBLIC_POSTHOG_API_KEY) {
posthog.capture(event)
Expand Down
Loading

0 comments on commit d185a7a

Please sign in to comment.