Skip to content

Commit

Permalink
🆕 $Properties match PostHog reserved keys. Refactored api_key set. …
Browse files Browse the repository at this point in the history
…More complete tests. Added properties:

- viewport_width
- viewport_height
- raw_user_agent
- browser_language
- os_version
- device_type
- lib
  • Loading branch information
mountainash committed Apr 7, 2024
1 parent c5e42c6 commit 9587bb9
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 54 deletions.
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Common use is currently for [Cloudflare Zaraz](https://www.cloudflare.com/applic

## TODO:

- *Basics*
- [x] pull users PostHog API key from environment
- [x] send page views to PostHog
- [x] send URL
Expand All @@ -16,10 +17,16 @@ Common use is currently for [Cloudflare Zaraz](https://www.cloudflare.com/applic
- [x] send events to PostHog
- [x] send user data to PostHog
- [x] send custom data to PostHog
- [ ] add MC to <https://managedcomponents.dev/components/>
- [ ] get Zaraz Settings passed in
- *Extra Features*
- [ ] Session Replay
- [ ] Feature Flags
- [ ] A/B Testing
- [ ] Surveys
- [x] [add MC to](https://github.com/managed-components/docs/pull/10) <https://managedcomponents.dev/components/>
- [ ] add MC to <https://github.com/PostHog/integrations-repository/blob/main/integrations.json>
- [ ] mention MC on [PostHog Docs](https://posthog.com/docs/advanced/proxy/cloudflare)
- [ ] mention MC on [Discord](https://discord.com/channels/595317990191398933/917505178016579605/1225745641351675925)
- [x] mention MC on [Discord](https://discord.com/channels/595317990191398933/917505178016579605/1225745641351675925)
- [x] use bun bundler [#1](https://github.com/mountainash/posthog-managed-component/issues/1)

## Documentation
Expand Down
8 changes: 7 additions & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,17 @@ export default [
},
},
{
files: ['*d.ts'],
files: ['**/*d.ts'],
rules: {
'no-undef': 'off',
},
},
{
files: ['**/*test.ts'],
rules: {
'no-console': 'error',
},
},
// ref: https://github.com/prettier/eslint-plugin-prettier?tab=readme-ov-file#configuration-new-eslintconfigjs
eslintPluginPrettierRecommended,
]
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "posthog",
"version": "1.2.0",
"version": "1.3.0",
"description": "A managed component for PostHog analytics",
"main": "dist/index.js",
"homepage": "https://github.com/mountainash/posthog-managed-component#readme",
Expand Down Expand Up @@ -28,8 +28,9 @@
"posthog",
"analytics",
"cloudflare",
"zaraz",
"workers",
"zaraz"
"3rd-party-script"
],
"author": "mountainash",
"license": "Apache-2.0",
Expand Down
50 changes: 39 additions & 11 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@ const dummyClient = {
userAgent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36',
language: 'en-GB',
referer: '',
referer: new URL('https://www.washingtonbrown.com.au/contact/'),
ip: '127.0.0.1',
screenHeight: 1080,
screenWidth: 2560,
screenHeight: 1080,
viewportWidth: 800,
viewportHeight: 600,
fetch: () => undefined,
set: () => undefined,
execute: () => undefined,
Expand Down Expand Up @@ -86,17 +88,43 @@ describe('PostHog MC track event handler works correctly', () => {
String(new Date(fakeEvent.client.timestamp).toISOString())
)
// expect(body?.properties?.$insert_id).toMatch(uuidPattern)
expect(body?.properties?.ip).toEqual(fakeEvent.client.ip)
expect(body?.properties?.referrer).toEqual('unknown')
expect(body?.properties?.referring_domain).toEqual('unknown')
expect(body?.properties?.current_url).toEqual(fakeEvent.client.url.href)
expect(body?.properties?.screen_height).toEqual(
expect(body?.properties?.$ip).toEqual(fakeEvent.client.ip)
expect(body?.properties?.$referrer).toEqual(fakeEvent.client.referer.href)
expect(body?.properties?.$referring_domain).toEqual(
fakeEvent.client.referer.hostname
) // careful: different number of 'r's in referer/referrer
expect(body?.properties?.title).toEqual('Zaraz "Test" /t Page')
expect(body?.properties?.$current_url).toEqual(fakeEvent.client.url.href)
expect(body?.properties?.$host).toEqual(fakeEvent.client.url.hostname)
expect(body?.properties?.$pathname).toEqual(fakeEvent.client.url.pathname)
expect(body?.properties?.current_url_search).toEqual(
fakeEvent.client.url.search
)
expect(body?.properties?.$screen_width).toEqual(
fakeEvent.client.screenWidth
)
expect(body?.properties?.$screen_height).toEqual(
fakeEvent.client.screenHeight
)
expect(body?.properties?.screen_width).toEqual(fakeEvent.client.screenWidth)
expect(body?.properties?.browser).toEqual('Chrome')
expect(body?.properties?.browser_version).toEqual('108.0.0.0')
expect(body?.properties?.os).toEqual('Mac OS')
expect(body?.properties?.$viewport_width).toEqual(
fakeEvent.client.viewportWidth
)
expect(body?.properties?.$viewport_height).toEqual(
fakeEvent.client.viewportHeight
)
expect(body?.properties?.$raw_user_agent).toEqual(
fakeEvent.client.userAgent
)
expect(body?.properties?.$browser).toEqual('Chrome')
expect(body?.properties?.$browser_version).toEqual(108)
expect(body?.properties?.$browser_language).toEqual(
fakeEvent.client.language
)
expect(body?.properties?.$os).toEqual('Mac OS')
expect(body?.properties?.$os_version).toEqual('10.15.7')
expect(body?.properties?.device).toEqual('Macintosh')
expect(body?.properties?.$device_type).toEqual(undefined) // there's no Desktop type in UAParser
expect(body?.properties?.$lib).toEqual('webcm')
expect(body?.properties?.someData).toEqual(fakeEvent.payload.someData)
})

Expand Down
77 changes: 39 additions & 38 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@ import { isValidHttpUrl } from './utils'

const MC_COOKIE_NAME = 'mc_posthog'

const getAPIEndpoint = (POSTHOG_URL: string) => {
POSTHOG_URL = POSTHOG_URL || 'https://us-proxy-direct.i.posthog.com'
return `${POSTHOG_URL}/capture/`
}

const handleCookieData = (client: Client, $identified_id?: string) => {
const cookie = client.get(MC_COOKIE_NAME)
let cookieData: { [k: string]: string | undefined } = {}
Expand Down Expand Up @@ -74,36 +69,52 @@ const getRequestBodyProperties = (event: MCEvent) => {
).getResult()

return {
ip: client.ip,
referrer: client.referer || 'unknown',
referring_domain: isValidHttpUrl(client.referer)
? new URL(client.referer).host
$ip: client.ip,
$referrer: client.referer,
$referring_domain: isValidHttpUrl(client.referer)
? new URL(client.referer).hostname
: 'unknown',
current_page_title: client.title,
current_url: client.url.href,
current_domain: client.url.hostname,
current_url_path: client.url.pathname,
title: client.title,
$current_url: client.url.href,
$host: client.url.hostname,
$pathname: client.url.pathname,
current_url_search: client.url.search,
screen_height: client.screenHeight,
screen_width: client.screenWidth,
browser: browser.name,
browser_version: browser.version,
os: os.name,
$screen_width: client.screenWidth,
$screen_height: client.screenHeight,
$viewport_width: client.viewportWidth,
$viewport_height: client.viewportHeight,
$raw_user_agent: client.userAgent,
$browser: browser.name,
$browser_version: Number(browser.version?.split('.')[0]),
$browser_language: client.language,
$os: os.name,
$os_version: os.version,
device: device.model,
$device_type: device.type,
$lib: 'webcm',
}
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const fetchObject = (url: string, requestBody: any) => {
const fetchObject = (settings: ComponentSettings, requestBody: any) => {
const { POSTHOG_URL, POSTHOG_API_KEY } = settings

const protocolhostname =
POSTHOG_URL || 'https://us-proxy-direct.i.posthog.com'
const endpoint = `${protocolhostname}/capture/`

return {
url: getAPIEndpoint(url),
url: endpoint,
opts: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
HTTP_X_FORWARDED_FOR: requestBody.properties.ip,
HTTP_X_FORWARDED_FOR: requestBody.properties['$ip'] || '1.1.1.1',
},
body: JSON.stringify(requestBody),
body: JSON.stringify({
api_key: POSTHOG_API_KEY,
...requestBody,
}),
},
}
}
Expand All @@ -115,14 +126,12 @@ export const getTrackEventArgs = (
event: MCEvent
) => {
const customFields = event.payload
const { POSTHOG_URL, POSTHOG_API_KEY } = settings

const properties = getRequestBodyProperties(event)
const distinctID = getDistinctId(event)
const timeStamp = getTimestamp(event.client)

const requestBody = {
api_key: POSTHOG_API_KEY,
event: event.type === 'pageview' ? '$pageview' : event.type,
timestamp: timeStamp,
distinct_id: distinctID,
Expand All @@ -133,21 +142,19 @@ export const getTrackEventArgs = (
// ref: https://posthog.com/docs/api/post-only-endpoints#single-event
}

return fetchObject(POSTHOG_URL, requestBody)
return fetchObject(settings, requestBody)
}

export const setAliasEventArgs = (
settings: ComponentSettings,
event: MCEvent
) => {
const alias = event.payload
const { POSTHOG_URL, POSTHOG_API_KEY } = settings

const distinctID = getDistinctId(event)
const timeStamp = getTimestamp(event.client)

const requestBody = {
api_key: POSTHOG_API_KEY,
event: '$create_alias',
timestamp: timeStamp,
distinct_id: distinctID,
Expand All @@ -157,21 +164,19 @@ export const setAliasEventArgs = (
// ref: https://posthog.com/docs/api/post-only-endpoints#alias
}

return fetchObject(POSTHOG_URL, requestBody)
return fetchObject(settings, requestBody)
}

export const setIdentifyEventArgs = (
settings: ComponentSettings,
event: MCEvent
) => {
const customFields = event.payload
const { POSTHOG_URL, POSTHOG_API_KEY } = settings

const distinctID = getDistinctId(event)
const timeStamp = getTimestamp(event.client)

const requestBody = {
api_key: POSTHOG_API_KEY,
event: '$identify',
timestamp: timeStamp,
distinct_id: distinctID,
Expand All @@ -181,38 +186,34 @@ export const setIdentifyEventArgs = (
// ref: https://posthog.com/docs/api/post-only-endpoints#identify
}

return fetchObject(POSTHOG_URL, requestBody)
return fetchObject(settings, requestBody)
}

export const getAssignGroupPropertiesEventArgs = (
settings: ComponentSettings,
event: MCEvent
) => {
const { $group_key, $group_name } = event.payload
const { POSTHOG_URL, POSTHOG_API_KEY } = settings
const distinctID = getDistinctId(event)

const requestBody = {
api_key: POSTHOG_API_KEY,
event: '$event', // API's key
distinct_id: distinctID,
properties: {
$groups: { [$group_key]: $group_name }, // API's key
},
}

return fetchObject(POSTHOG_URL, requestBody)
return fetchObject(settings, requestBody)
}

export const getSetGroupPropertiesEventArgs = (
settings: ComponentSettings,
event: MCEvent
) => {
const customFields = event.payload
const { POSTHOG_URL, POSTHOG_API_KEY } = settings

const requestBody = {
api_key: POSTHOG_API_KEY,
event: '$groupidentify', // API's key
distinct_id: 'groups_setup_id',
properties: {
Expand All @@ -231,7 +232,7 @@ export const getSetGroupPropertiesEventArgs = (
// }
}

return fetchObject(POSTHOG_URL, requestBody)
return fetchObject(settings, requestBody)
}

export default async (manager: Manager, settings: ComponentSettings) => {
Expand All @@ -248,7 +249,7 @@ export default async (manager: Manager, settings: ComponentSettings) => {
manager.addEventListener('pageview', async (event: MCEvent) => {
console.info('"pageview" event received', JSON.stringify(event, null, 2))
const { url, opts } = getTrackEventArgs(settings, event)
// console.log('Sending:', url, opts)
console.log('Sending:', url, opts)
const response = await manager.fetch(url, opts)
if (!response?.ok) {
console.error(
Expand Down

0 comments on commit 9587bb9

Please sign in to comment.