Skip to content

feat: Enable some Amplitude autocapture events #3731

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
},
"dependencies": {
"@amplitude/analytics-browser": "^2.11.9",
"@amplitude/analytics-types": "^2.8.4",
"@hookform/resolvers": "^2.8.5",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-checkbox": "^1.1.1",
Expand Down
1 change: 1 addition & 0 deletions src/services/events/__mocks__/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { EventTracker } from '../types'
//

const MOCK_EVENT_TRACKER: EventTracker = {
context: {},
identify: vi.fn(),
track: vi.fn(),
setContext: vi.fn(),
Expand Down
56 changes: 55 additions & 1 deletion src/services/events/amplitude/amplitude.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { Config, CoreClient, Event } from '@amplitude/analytics-types'

import config from 'config'

import { AmplitudeEventTracker, initAmplitude } from './amplitude'
import {
AmplitudeEventTracker,
initAmplitude,
pageViewTrackingSanitization,
} from './amplitude'

const mockIdentifySet = vi.hoisted(() => vi.fn())
const mockIdentifyConstructor = vi.hoisted(() => vi.fn())
Expand All @@ -14,6 +20,7 @@ const mockAmplitude = vi.hoisted(() => {
}
}
return {
add: vi.fn(),
init: vi.fn(),
track: vi.fn(),
identify: vi.fn(),
Expand Down Expand Up @@ -52,6 +59,53 @@ describe('when initAmplitude is called', () => {
})
})

describe('pageViewTrackingSanitization', () => {
it('removes sensitive info from Page Viewed event properties', async () => {
const plugin = pageViewTrackingSanitization()

if (plugin.setup) {
plugin?.setup({} as Config, {} as CoreClient)
}

if (plugin.execute) {
const event = await plugin.execute({
event_type: '[Amplitude] Page Viewed',
event_properties: {
'[Amplitude] Page Counter': 1,
'[Amplitude] Page Domain': 'app.codecov.io',
'[Amplitude] Page Path': '/sensitive/info',
'[Amplitude] Page Location': 'https://app.codecov.io/sensitive/info',
},
} as Event)
expect(event?.event_properties).toMatchObject({
'[Amplitude] Page Counter': 1,
'[Amplitude] Page Domain': 'app.codecov.io',
path: undefined,
})
}
})

it('does not touch other event types', async () => {
const plugin = pageViewTrackingSanitization()

if (plugin.setup) {
plugin?.setup({} as Config, {} as CoreClient)
}

if (plugin.execute) {
const event = await plugin.execute({
event_type: 'Button Clicked',
event_properties: {
'[Amplitude] Page Path': '/sensitive/info',
},
} as Event)
expect(event?.event_properties).toMatchObject({
'[Amplitude] Page Path': '/sensitive/info',
})
}
})
})

describe('AmplitudeEventTracker', () => {
describe('identify', () => {
describe('when identify is called', () => {
Expand Down
34 changes: 33 additions & 1 deletion src/services/events/amplitude/amplitude.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,53 @@
import * as amplitude from '@amplitude/analytics-browser'
import { EnrichmentPlugin } from '@amplitude/analytics-types'

import config from 'config'

import { providerToInternalProvider } from 'shared/utils/provider'

import { eventTracker } from '../events'
import { Event, EventContext, EventTracker, Identity } from '../types'

export const pageViewTrackingSanitization = (): EnrichmentPlugin => {
return {
name: 'page-view-tracking-sanitization',
type: 'enrichment',
setup: async () => undefined,
execute: async (event) => {
if (event.event_type === '[Amplitude] Page Viewed') {
/* eslint-disable camelcase */
event.event_properties = {
'[Amplitude] Page Counter':
event.event_properties?.['[Amplitude] Page Counter'],
'[Amplitude] Page Domain':
event.event_properties?.['[Amplitude] Page Domain'],
path: eventTracker().context.path,
}
}

return event
},
}
}

export function initAmplitude() {
const apiKey = config.AMPLITUDE_API_KEY
if (!apiKey) {
throw new Error(
'AMPLITUDE_API_KEY is not defined. Amplitude events will not be tracked.'
)
}
amplitude.add(pageViewTrackingSanitization())
amplitude.init(apiKey, {
// Disable all autocapture - may change this in the future
autocapture: false,
autocapture: {
attribution: true,
pageViews: true,
sessions: true,
formInteractions: false,
fileDownloads: false,
elementInteractions: false,
},
minIdLength: 1, // Necessary to accommodate our owner ids
serverUrl: 'https://amplitude.codecov.io/2/httpapi',
})
Expand Down
2 changes: 2 additions & 0 deletions src/services/events/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { AmplitudeEventTracker, initAmplitude } from './amplitude/amplitude'
import { Event, EventContext, EventTracker, Identity } from './types'

export class StubbedEventTracker implements EventTracker {
context: EventContext = {}

identify(_identity: Identity): void {}
track(_event: Event): void {}
setContext(_context: EventContext): void {}
Expand Down
2 changes: 2 additions & 0 deletions src/services/events/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ export type EventContext = {
}

export abstract class EventTracker {
context: EventContext = {}

// Identifies the user this session belongs to.
identify(_identity: Identity): void {
throw new Error(
Expand Down
1 change: 1 addition & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9053,6 +9053,7 @@ __metadata:
dependencies:
"@acemarke/react-prod-sourcemaps": "npm:^0.3.1"
"@amplitude/analytics-browser": "npm:^2.11.9"
"@amplitude/analytics-types": "npm:^2.8.4"
"@babel/eslint-parser": "npm:^7.25.9"
"@babel/plugin-proposal-private-property-in-object": "npm:^7.21.11"
"@chromatic-com/storybook": "npm:^1"
Expand Down
Loading