ScriptV2: `transformRequest` (#5488)
* Commit as Plausible Bot This way commits by it can be excluded from protections * ScriptV2: Add support for `config.transformRequest` transformRequest allows users to either manipulate or ignore requests to plausible with a minimal footprint. Some use-cases we're aware of and are planning for: 1. Ignoring requests similar to previous exclusion rules in WordPress 2. Normalizing urls for requests * Allow passing `options.url` for overriding url when calling track Previous naming `u` was unintuitive, but is kept around (untyped) for backwards compatibility reasons * chore: Bump tracker_script_version to 17 * Changelog * Update types * Docs * Add test showing interaction with engagement events * README.md
This commit is contained in:
parent
d215e50982
commit
c3dd21431c
|
|
@ -58,7 +58,9 @@ jobs:
|
|||
uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5
|
||||
with:
|
||||
message: "Released tracker script version ${{ steps.package.outputs.version }}"
|
||||
add: "tracker/npm_package"
|
||||
github_token: ${{ secrets.PLAUSIBLE_BOT_GITHUB_TOKEN }}
|
||||
add: |
|
||||
- tracker/npm_package
|
||||
|
||||
- name: Notify team on success
|
||||
if: ${{ success() }}
|
||||
|
|
|
|||
|
|
@ -7,4 +7,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## Unreleased
|
||||
|
||||
Initial release.
|
||||
- Support for `config.transformRequest`
|
||||
- Support for passing `url` as option when calling `track`
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ See also [plausible.d.ts](https://github.com/plausible/analytics/blob/master/tra
|
|||
| `formSubmissions` | Whether to track form submissions. | `false` |
|
||||
| `captureOnLocalhost` | Whether to capture events on localhost. | `false` |
|
||||
| `customProperties` | Object or function that returns custom properties for a given event. | `{}` |
|
||||
| `transformRequest` | Function that allows transforming or ignoring requests | |
|
||||
|
||||
#### Using `customProperties`
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "macobo-test-tracker",
|
||||
"version": "0.1.6",
|
||||
"version": "0.2.0",
|
||||
"description": "Plausible Analytics official frontend tracking library",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: Testing done in the tracker folder\" && exit 1"
|
||||
|
|
|
|||
|
|
@ -34,6 +34,13 @@ export interface PlausibleConfig {
|
|||
// Custom properties to add to all events tracked.
|
||||
// If passed as a function, it will be called when `track` is called.
|
||||
customProperties?: CustomProperties | ((eventName: string) => CustomProperties)
|
||||
|
||||
// A function that can be used to transform the payload before it is sent to the API.
|
||||
// If the function returns null or any other falsy value, the event will be ignored.
|
||||
//
|
||||
// This can be used to avoid sending certain types of events, or modifying any event
|
||||
// parameters, e.g. to clean URLs of values that should not be recorded.
|
||||
transformRequest?: (payload: PlausibleRequestPayload) => PlausibleRequestPayload | null
|
||||
}
|
||||
|
||||
export interface PlausibleEventOptions {
|
||||
|
|
@ -56,7 +63,7 @@ export interface PlausibleEventOptions {
|
|||
|
||||
// Overrides the URL of the page that the event is being tracked on.
|
||||
// If not provided, `location.href` will be used.
|
||||
u?: string
|
||||
url?: string
|
||||
}
|
||||
|
||||
export type CustomProperties = Record<string, string>
|
||||
|
|
@ -67,3 +74,20 @@ export type PlausibleEventRevenue = {
|
|||
// Currency is an ISO 4217 string representing the currency code, e.g. "USD" or "EUR"
|
||||
currency: string
|
||||
}
|
||||
|
||||
export type PlausibleRequestPayload = {
|
||||
// Event name
|
||||
n: string,
|
||||
// URL of the event
|
||||
u: string,
|
||||
// Domain of the event
|
||||
d: string,
|
||||
// Referrer
|
||||
r?: string | null,
|
||||
// Custom properties
|
||||
p?: CustomProperties,
|
||||
// Revenue information
|
||||
$?: PlausibleEventRevenue,
|
||||
// Whether the event is interactive
|
||||
i?: boolean,
|
||||
} & Record<string, unknown>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"tracker_script_version": 16,
|
||||
"tracker_script_version": 17,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"deploy": "node compile.js",
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ export function track(eventName, options) {
|
|||
payload.v = COMPILE_TRACKER_SCRIPT_VERSION
|
||||
|
||||
if (COMPILE_MANUAL) {
|
||||
var customURL = options && options.u
|
||||
var customURL = options && (options.u || options.url)
|
||||
|
||||
payload.u = customURL ? customURL : location.href
|
||||
} else {
|
||||
|
|
@ -111,6 +111,14 @@ export function track(eventName, options) {
|
|||
payload.h = 1
|
||||
}
|
||||
|
||||
if ((COMPILE_PLAUSIBLE_WEB || COMPILE_PLAUSIBLE_NPM) && typeof config.transformRequest === 'function') {
|
||||
payload = config.transformRequest(payload)
|
||||
|
||||
if (!payload) {
|
||||
return onIgnoredEvent(eventName, options, 'transformRequest')
|
||||
}
|
||||
}
|
||||
|
||||
if (isPageview) {
|
||||
postPageviewTrack(payload)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@
|
|||
|
||||
<a id="outbound-link" href="https://example.com">Outbound link</a>
|
||||
|
||||
<a id="manual-pageview" onclick="window.track('pageview', { u: '/:test-plausible' })">Manual pageview</a>
|
||||
<a id="manual-pageview-1" onclick="window.track('pageview', { u: '/:test-plausible' })">Manual pageview</a>
|
||||
<a id="manual-pageview-2" onclick="window.track('pageview', { url: '/:test-plausible-2' })">Manual pageview 2</a>
|
||||
|
||||
<a id="custom-event" onclick="window.track('Custom event', { props: { author: 'Karl' } })">Custom event</a>
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@
|
|||
|
||||
<a id="outbound-link" href="https://example.com">Outbound link</a>
|
||||
|
||||
<a id="manual-pageview" onclick="plausible('pageview', { u: '/:test-plausible' })">Manual pageview</a>
|
||||
<a id="manual-pageview-1" onclick="plausible('pageview', { u: '/:test-plausible' })">Manual pageview</a>
|
||||
<a id="manual-pageview-2" onclick="plausible('pageview', { url: '/:test-plausible-2' })">Manual pageview 2</a>
|
||||
|
||||
<a id="custom-event" onclick="plausible('Custom event', { props: { author: 'Karl' } })">Custom event</a>
|
||||
|
||||
|
|
|
|||
|
|
@ -11,15 +11,21 @@ import { test } from '@playwright/test'
|
|||
|
||||
// Wrapper around calling `plausible.init` in the page context for users of `testPlausibleConfiguration`
|
||||
export async function callInit(page, config, parent) {
|
||||
// Stringify the customProperties function to work around evaluate not being able to serialize functions
|
||||
// Stringify the customProperties and transformRequest functions to work around evaluate not being able to serialize functions
|
||||
if (config && typeof config.customProperties === 'function') {
|
||||
config.customProperties = { "_wrapFunction": config.customProperties.toString() }
|
||||
}
|
||||
if (config && typeof config.transformRequest === 'function') {
|
||||
config.transformRequest = { "_wrapFunction": config.transformRequest.toString() }
|
||||
}
|
||||
|
||||
await page.evaluate(({ config, parent }) => {
|
||||
if (config && config.customProperties && config.customProperties._wrapFunction) {
|
||||
config.customProperties = new Function(`return (${config.customProperties._wrapFunction})`)();
|
||||
}
|
||||
if (config && config.transformRequest && config.transformRequest._wrapFunction) {
|
||||
config.transformRequest = new Function(`return (${config.transformRequest._wrapFunction})`)();
|
||||
}
|
||||
eval(parent).init(config)
|
||||
}, { config, parent })
|
||||
}
|
||||
|
|
@ -187,12 +193,15 @@ export function testPlausibleConfiguration({ openPage, initPlausible, fixtureNam
|
|||
action: async () => {
|
||||
await openPage(page, {}, { skipPlausibleInit: true })
|
||||
await initPlausible(page, { autoCapturePageviews: false })
|
||||
await page.click('#manual-pageview')
|
||||
await page.click('#manual-pageview-1')
|
||||
await page.click('#manual-pageview-2')
|
||||
await hideAndShowCurrentTab(page, { delay: 200 })
|
||||
},
|
||||
expectedRequests: [
|
||||
{ n: 'pageview', u: '/:test-plausible', d: 'example.com' },
|
||||
{ n: 'engagement', u: '/:test-plausible', d: 'example.com' },
|
||||
{ n: 'pageview', u: '/:test-plausible-2', d: 'example.com' },
|
||||
{ n: 'engagement', u: '/:test-plausible-2', d: 'example.com' },
|
||||
],
|
||||
})
|
||||
})
|
||||
|
|
@ -232,5 +241,64 @@ export function testPlausibleConfiguration({ openPage, initPlausible, fixtureNam
|
|||
expectedRequests: [{ n: 'pageview', d: 'example.com', u: expecting.stringContaining(fixtureName)}]
|
||||
})
|
||||
})
|
||||
|
||||
test('supports ignoring requests with `transformRequest`', async ({ page }) => {
|
||||
await expectPlausibleInAction(page, {
|
||||
action: async () => {
|
||||
await openPage(page, {}, { skipPlausibleInit: true })
|
||||
await initPlausible(page, { transformRequest: () => null })
|
||||
await page.click('#custom-event')
|
||||
},
|
||||
expectedRequests: [],
|
||||
refutedRequests: [{ n: 'Custom event' }, { n: 'pageview' }]
|
||||
})
|
||||
})
|
||||
|
||||
test('supports modifying the request payload with `transformRequest`', async ({ page }) => {
|
||||
const transformRequest = (payload) => {
|
||||
payload.p = payload.p || {}
|
||||
payload.p.eventName = payload.n
|
||||
payload.i = false
|
||||
|
||||
return payload
|
||||
}
|
||||
|
||||
await expectPlausibleInAction(page, {
|
||||
action: async () => {
|
||||
await openPage(page, {}, { skipPlausibleInit: true })
|
||||
await initPlausible(page, { transformRequest })
|
||||
await page.click('#custom-event')
|
||||
},
|
||||
expectedRequests: [
|
||||
{ n: 'pageview', p: { eventName: 'pageview' }, i: false },
|
||||
{ n: 'Custom event', p: { eventName: 'Custom event', author: 'Karl' }, i: false }
|
||||
]
|
||||
})
|
||||
})
|
||||
|
||||
test('transformRequest props are sent with engagement events', async ({ page }) => {
|
||||
const transformRequest = (payload) => {
|
||||
payload.p = payload.p || {}
|
||||
|
||||
window.requestCount = (window.requestCount || 0) + 1
|
||||
payload.p.requestCount = window.requestCount
|
||||
|
||||
return payload
|
||||
}
|
||||
|
||||
await expectPlausibleInAction(page, {
|
||||
action: async () => {
|
||||
await openPage(page, {}, { skipPlausibleInit: true })
|
||||
await initPlausible(page, { transformRequest })
|
||||
await page.click('#custom-event')
|
||||
await hideAndShowCurrentTab(page, { delay: 200 })
|
||||
},
|
||||
expectedRequests: [
|
||||
{ n: 'pageview', p: { requestCount: 1 } },
|
||||
{ n: 'Custom event', p: { author: 'Karl', requestCount: 2 } },
|
||||
{ n: 'engagement', p: { requestCount: 1 } }
|
||||
]
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue