Skip to content
This repository has been archived by the owner on Nov 4, 2021. It is now read-only.

Commit

Permalink
Set UTM etc when creating persons (#214)
Browse files Browse the repository at this point in the history
* Set UTM etc when creating persons

* fix test

* Use slightly faster COUNT(*)

* Rename userShouldSetUTM to ensurePersonUpdateOnUtm for clarity

* Refactor ensurePersonUpdateOnUtm a bit

* Prettier

* only use $set and $set_once

* fix

* Add new prop

* remove new team prop

* use sets

* fix type

Co-authored-by: Michael Matloka <[email protected]>
Co-authored-by: Marius Andra <[email protected]>
  • Loading branch information
3 people authored Feb 26, 2021
1 parent de40ab6 commit d2a1b21
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 6 deletions.
5 changes: 3 additions & 2 deletions src/ingestion/process-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
} from '../types'
import { castTimestampOrNow, UUID, UUIDT } from '../utils'
import { KAFKA_EVENTS, KAFKA_SESSION_RECORDING_EVENTS } from './topics'
import { elementsToString, sanitizeEventName, timeoutGuard } from './utils'
import { elementsToString, personInitialAndUTMProperties, sanitizeEventName, timeoutGuard } from './utils'

export class EventsProcessor {
pluginsServer: PluginsServer
Expand Down Expand Up @@ -326,7 +326,6 @@ export class EventsProcessor {
sentAt: DateTime | null
): Promise<IEvent> {
event = sanitizeEventName(event)

const elements: Record<string, any>[] | undefined = properties['$elements']
let elementsList: Element[] = []
if (elements && elements.length) {
Expand Down Expand Up @@ -371,6 +370,8 @@ export class EventsProcessor {
} catch {}
}

properties = personInitialAndUTMProperties(properties)

if (properties['$set'] || properties['$set_once']) {
await this.updatePersonProperties(
teamId,
Expand Down
19 changes: 19 additions & 0 deletions src/ingestion/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Properties } from '@posthog/plugin-scaffold'
import * as Sentry from '@sentry/node'
import crypto from 'crypto'

Expand Down Expand Up @@ -163,3 +164,21 @@ export function timeoutGuard(message: string, timeout = defaultConfig.TASK_TIMEO
Sentry.captureMessage(message)
}, timeout)
}

const campaignParams = new Set(['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'])
const initialParams = new Set(['$browser', '$browser_version', '$current_url', '$os', '$referring_domain', '$referrer'])
const combinedParams = new Set([...campaignParams, ...initialParams])

/** If we get new UTM params, make sure we set those **/
export function personInitialAndUTMProperties(properties: Properties): Properties {
const propertiesCopy = { ...properties }
const maybeSet = Object.entries(properties).filter(([key, value]) => campaignParams.has(key))
const maybeSetInitial = Object.entries(properties)
.filter(([key, value]) => combinedParams.has(key))
.map(([key, value]) => [`$initial_${key.replace('$', '')}`, value])
if (Object.keys(maybeSet).length > 0) {
propertiesCopy.$set = { ...(properties.$set || {}), ...Object.fromEntries(maybeSet) }
propertiesCopy.$set_once = { ...(properties.$set_once || {}), ...Object.fromEntries(maybeSetInitial) }
}
return propertiesCopy
}
77 changes: 73 additions & 4 deletions tests/shared/process-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,13 @@ export const createProcessEventTests = (
properties: {
distinct_id: 2,
token: team.api_token,
$browser: 'Chrome',
$current_url: 'https://test.com',
$os: 'Mac OS X',
$browser_version: 80,
$initial_referring_domain: 'https://google.com',
$initial_referrer_url: 'https://google.com/?q=posthog',
utm_medium: 'twitter',
$elements: [
{ tag_name: 'a', nth_child: 1, nth_of_type: 2, attr__class: 'btn btn-sm' },
{ tag_name: 'div', nth_child: 1, nth_of_type: 2, $el_text: '💻' },
Expand All @@ -230,12 +237,23 @@ export const createProcessEventTests = (
)

if (database === 'clickhouse') {
expect(queryCounter).toBe(9)
expect(queryCounter).toBe(11)
} else if (database === 'postgresql') {
expect(queryCounter).toBe(12)
expect(queryCounter).toBe(14)
}

let persons = await server.db.fetchPersons()
expect(persons[0].properties).toEqual({
$initial_browser: 'Chrome',
$initial_browser_version: 80,
$initial_utm_medium: 'twitter',
$initial_current_url: 'https://test.com',
$initial_os: 'Mac OS X',
utm_medium: 'twitter',
})

// capture a second time to verify e.g. event_names is not ['$autocapture', '$autocapture']
// Also pass new utm params in to override
await processEvent(
'2',
'127.0.0.1',
Expand All @@ -245,6 +263,7 @@ export const createProcessEventTests = (
properties: {
distinct_id: 2,
token: team.api_token,
utm_medium: 'instagram',
$elements: [
{ tag_name: 'a', nth_child: 1, nth_of_type: 2, attr__class: 'btn btn-sm' },
{ tag_name: 'div', nth_child: 1, nth_of_type: 2, $el_text: '💻' },
Expand All @@ -258,9 +277,17 @@ export const createProcessEventTests = (
)

const events = await server.db.fetchEvents()
const persons = await server.db.fetchPersons()
persons = await server.db.fetchPersons()
expect(events.length).toEqual(2)
expect(persons.length).toEqual(1)
expect(persons[0].properties).toEqual({
$initial_browser: 'Chrome',
$initial_browser_version: 80,
$initial_utm_medium: 'twitter',
$initial_current_url: 'https://test.com',
$initial_os: 'Mac OS X',
utm_medium: 'instagram',
})

const [person] = persons
const distinctIds = await server.db.fetchDistinctIdValues(person)
Expand All @@ -285,10 +312,52 @@ export const createProcessEventTests = (
team = await getFirstTeam(server)
expect(team.event_names).toEqual(['$autocapture'])
expect(team.event_names_with_usage).toEqual([{ event: '$autocapture', volume: null, usage_count: null }])
expect(team.event_properties).toEqual(['distinct_id', 'token', '$ip'])
expect(team.event_properties).toEqual([
'distinct_id',
'token',
'$browser',
'$current_url',
'$os',
'$browser_version',
'$initial_referring_domain',
'$initial_referrer_url',
'utm_medium',
'$ip',
])
expect(team.event_properties_with_usage).toEqual([
{ key: 'distinct_id', usage_count: null, volume: null },
{ key: 'token', usage_count: null, volume: null },
{ key: '$browser', usage_count: null, volume: null },
{
key: '$current_url',
usage_count: null,
volume: null,
},
{
key: '$os',
usage_count: null,
volume: null,
},
{
key: '$browser_version',
usage_count: null,
volume: null,
},
{
key: '$initial_referring_domain',
usage_count: null,
volume: null,
},
{
key: '$initial_referrer_url',
usage_count: null,
volume: null,
},
{
key: 'utm_medium',
usage_count: null,
volume: null,
},
{ key: '$ip', usage_count: null, volume: null },
])
})
Expand Down

0 comments on commit d2a1b21

Please sign in to comment.