feat(studio): add explorer_banner_exposed impression event (#49747)

<!-- ccr-slack-attribution -->
_Requested by **Pam Chia** · [Slack
thread](https://supabase.slack.com/archives/C076KTY11DF/p1788139328573799?thread_ts=1788139328.573799&cid=C076KTY11DF)_

## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Feature (telemetry). Adds one PostHog event.

Linear issue:
[GROWTH-1154](https://linear.app/supabase/issue/GROWTH-1154/telemetry-explorer-feature-preview-banner-has-no-exposure-event-so)

## What is the current behavior?

The Explorer feature preview banner emits
`explorer_banner_dismiss_button_clicked` and
`explorer_banner_cta_button_clicked` (both from
`apps/studio/components/ui/BannerStack/Banners/BannerExplorer.tsx`,
shipped in #49606), and nothing else. With no impression event there is
no denominator, so no click-through or dismiss rate can be reported.

## What is the new behavior?

`explorer_banner_exposed` fires when the banner content is rendered, at
most once per page load.

The event is declared in `packages/common/telemetry-constants.ts` next
to the two existing Explorer banner events and added to the
`TelemetryEvent` union, following the existing `*_exposed` family. It
carries no custom properties; `project` and `organization` groups are
attached by `apps/studio/lib/telemetry/track.ts`.

**Verification:**

- `prettier --check` on both changed files: passing
- `tsc --noEmit` in `packages/common`, which covers the new event
interface and the `TelemetryEvent` union: passing
- Studio-scoped lint, typecheck, and tests: green on CI
- Browser-tested on the studio-staging preview (Playwright): the
exposure event fires exactly once per page load (201 on the wire), does
not re-fire on client-side navigation or banner hover within the same
page load, fires again after a full reload, and does not fire after
dismissal; the CTA and dismiss click events are unchanged and carry the
`project`/`organization` groups

**Out of scope:**

- Pre-consent drops: every telemetry event waits for consent, so this
event degrades the same way the rest of the `*_exposed` family does
(transient, recovers on the next page load). A family-wide fix is a
separate issue.
- Mirroring the `explorer` flag state into event properties: redundant
once exposure exists.
- The CTA handler not dismissing the banner: raised separately, both
click handlers untouched.
-
[GROWTH-1153](https://linear.app/supabase/issue/GROWTH-1153/telemetry-advisorcategory-omitted-for-health-lints-on-two-of-five)
and its draft PR #49746: separate issue, no overlap.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01Xwj2SotnaHByjbTfqF4Kdm); reworked
per Pam's review._

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Pamela Chia <pamelachiamayyee@gmail.com>
This commit is contained in:
authored and GitHub committed 2026-08-31 15:47:43 +08:00
1 parent 2c76bb371b
commit 5e8a83e11a
2 files changed
+24

No files matched your search

@@ -1,5 +1,6 @@
import { LOCAL_STORAGE_KEYS } from 'common'
import { AnimatePresence, motion } from 'framer-motion'
import { useEffect } from 'react'
import { Badge, Button } from 'ui'
import { BannerCard } from '../BannerCard'
@@ -8,6 +9,8 @@ import { useFeaturePreviewModal } from '@/components/interfaces/App/FeaturePrevi
import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage'
import { useTrack } from '@/lib/telemetry/track'
let hasTrackedExposureThisPageLoad = false
export const BannerExplorer = () => {
const track = useTrack()
const { dismissBanner } = useBannerStack()
@@ -18,6 +21,13 @@ export const BannerExplorer = () => {
false
)
useEffect(() => {
if (hasTrackedExposureThisPageLoad) return
hasTrackedExposureThisPageLoad = true
track('explorer_banner_exposed')
}, [track])
return (
<BannerCard
onDismiss={() => {
+14
View File
@@ -1531,6 +1531,19 @@ export interface DatabaseConnectionsBannerCtaButtonClickedEvent {
groups: TelemetryGroups
}
/**
* The Explorer feature preview banner was rendered in studio project pages, fired at most once
* per page load. Acts as the denominator for the banner's dismiss and CTA rates; dedupe per
* session or per user at query time.
*
* @group Events
* @source studio
*/
export interface ExplorerBannerExposedEvent {
action: 'explorer_banner_exposed'
groups: TelemetryGroups
}
/**
* User clicked the dismiss button on the Explorer feature preview banner in studio project pages.
*
@@ -3834,6 +3847,7 @@ export type TelemetryEvent =
| DatabaseConnectionsBlockerViewClickedEvent
| DatabaseConnectionsBannerDismissButtonClickedEvent
| DatabaseConnectionsBannerCtaButtonClickedEvent
| ExplorerBannerExposedEvent
| ExplorerBannerDismissButtonClickedEvent
| ExplorerBannerCtaButtonClickedEvent
| SessionTerminateButtonClickedEvent