From 33772c7e03a06a7154859fb81c588ee515a81ba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matu=CC=81s=CC=8C=20Tomlein?= Date: Tue, 9 Jul 2024 13:21:36 +0200 Subject: [PATCH 1/4] Add a filter function to plugins to filter out events so that they are not tracked --- libraries/tracker-core/src/core.ts | 21 +++- libraries/tracker-core/src/plugins.ts | 6 + libraries/tracker-core/test/core.ts | 160 +++++++++++++++++++++----- trackers/node-tracker/test/tracker.ts | 2 +- 4 files changed, 155 insertions(+), 34 deletions(-) diff --git a/libraries/tracker-core/src/core.ts b/libraries/tracker-core/src/core.ts index 1cb617117..b62afd622 100644 --- a/libraries/tracker-core/src/core.ts +++ b/libraries/tracker-core/src/core.ts @@ -138,7 +138,7 @@ export interface TrackerCore { * @param pb - Payload * @param context - Custom contexts relating to the event * @param timestamp - Timestamp of the event - * @returns Payload after the callback is applied + * @returns Payload after the callback is applied or undefined if the event is skipped */ track: ( /** A PayloadBuilder created by one of the `buildX` functions */ @@ -147,7 +147,7 @@ export interface TrackerCore { context?: Array | null, /** Timestamp override */ timestamp?: Timestamp | null - ) => Payload; + ) => Payload | undefined; /** * Set a persistent key-value pair to be added to every payload @@ -376,13 +376,13 @@ export function trackerCore(configuration: CoreConfiguration = {}): TrackerCore * @param pb - Payload * @param context - Custom contexts relating to the event * @param timestamp - Timestamp of the event - * @returns Payload after the callback is applied + * @returns Payload after the callback is applied or undefined if the event is skipped */ function track( pb: PayloadBuilder, context?: Array | null, timestamp?: Timestamp | null - ): Payload { + ): Payload | undefined { pb.withJsonProcessor(payloadJsonProcessor(encodeBase64)); pb.add('eid', uuid()); pb.addDict(payloadPairs); @@ -404,6 +404,19 @@ export function trackerCore(configuration: CoreConfiguration = {}): TrackerCore } }); + // Call the filter on plugins to determine if the event should be tracked + const skip = corePlugins.find((plugin) => { + try { + return plugin.filter && !plugin.filter(pb.build()); + } catch (ex) { + LOG.error('Plugin filter', ex); + return false; + } + }); + if (skip) { + return undefined; + } + if (typeof callback === 'function') { callback(pb); } diff --git a/libraries/tracker-core/src/plugins.ts b/libraries/tracker-core/src/plugins.ts index e0f195c57..669c7f0fd 100644 --- a/libraries/tracker-core/src/plugins.ts +++ b/libraries/tracker-core/src/plugins.ts @@ -53,6 +53,12 @@ export interface CorePlugin { * @param payload - The final built payload */ afterTrack?: (payload: Payload) => void; + /** + * Called before the payload is sent to the callback to decide whether to send the payload or skip it + * @param payload - The final event payload, can't be modified. + * @returns True if the payload should be sent, false if it should be skipped + */ + filter?: (payloadBuilder: Payload) => boolean; /** * Called when constructing the context for each event * Useful for adding additional context to events diff --git a/libraries/tracker-core/test/core.ts b/libraries/tracker-core/test/core.ts index b238514d6..aac62a570 100644 --- a/libraries/tracker-core/test/core.ts +++ b/libraries/tracker-core/test/core.ts @@ -80,7 +80,7 @@ test('tracker.track API should return the eid attribute', (t) => { page: pageTitle, refr: referrer, }; - const eventPayload = tracker.track(buildPageView({ pageUrl, pageTitle, referrer })); + const eventPayload = tracker.track(buildPageView({ pageUrl, pageTitle, referrer }))!; t.truthy(eventPayload.eid); t.regex(eventPayload.eid as string, UUID_REGEX); compare(eventPayload, expected, t); @@ -96,7 +96,7 @@ test('should track a page view', (t) => { page: pageTitle, refr: referrer, }; - compare(tracker.track(buildPageView({ pageUrl, pageTitle, referrer })), expected, t); + compare(tracker.track(buildPageView({ pageUrl, pageTitle, referrer }))!, expected, t); }); test('should track a page ping', (t) => { const pageUrl = 'http://www.example.com'; @@ -115,7 +115,7 @@ test('should track a page ping', (t) => { compare( tracker.track( buildPagePing({ pageUrl, pageTitle, referrer, minXOffset: 1, maxXOffset: 2, minYOffset: 3, maxYOffset: 4 }) - ), + )!, expected, t ); @@ -130,7 +130,7 @@ test('should track a structured event', (t) => { se_va: '1', }; compare( - tracker.track(buildStructEvent({ category: 'cat', action: 'act', label: 'lab', property: 'prop', value: 1 })), + tracker.track(buildStructEvent({ category: 'cat', action: 'act', label: 'lab', property: 'prop', value: 1 }))!, expected, t ); @@ -170,7 +170,7 @@ test('should track an ecommerce transaction event', (t) => { country, currency, }) - ), + )!, expected, t ); @@ -194,7 +194,7 @@ test('should track an ecommerce transaction item event', (t) => { ti_cu: currency, }; compare( - tracker.track(buildEcommerceTransactionItem({ orderId, sku, name, category, price, quantity, currency })), + tracker.track(buildEcommerceTransactionItem({ orderId, sku, name, category, price, quantity, currency }))!, expected, t ); @@ -213,7 +213,7 @@ test('should track a self-describing event', (t) => { data: inputJson, }), }; - compare(tracker.track(buildSelfDescribingEvent({ event: inputJson })), expected, t); + compare(tracker.track(buildSelfDescribingEvent({ event: inputJson }))!, expected, t); }); test('should track a link click', (t) => { const targetUrl = 'http://www.example.com'; @@ -239,7 +239,7 @@ test('should track a link click', (t) => { }), }; compare( - tracker.track(buildLinkClick({ targetUrl, elementId, elementClasses, elementTarget, elementContent })), + tracker.track(buildLinkClick({ targetUrl, elementId, elementClasses, elementTarget, elementContent }))!, expected, t ); @@ -261,7 +261,7 @@ test('should track a screen view', (t) => { data: inputJson, }), }; - compare(tracker.track(buildScreenView({ name, id })), expected, t); + compare(tracker.track(buildScreenView({ name, id }))!, expected, t); }); test('should track an ad impression', (t) => { const impressionId = 'a0e8f8780ab3'; @@ -295,7 +295,7 @@ test('should track an ad impression', (t) => { compare( tracker.track( buildAdImpression({ impressionId, costModel, cost, targetUrl, bannerId, zoneId, advertiserId, campaignId }) - ), + )!, expected, t ); @@ -334,7 +334,7 @@ test('should track an ad click', (t) => { compare( tracker.track( buildAdClick({ targetUrl, clickId, costModel, cost, bannerId, zoneId, impressionId, advertiserId, campaignId }) - ), + )!, expected, t ); @@ -383,7 +383,7 @@ test('should track an ad conversion', (t) => { advertiserId, campaignId, }) - ), + )!, expected, t ); @@ -407,7 +407,7 @@ test('should track a social interaction', (t) => { data: inputJson, }), }; - compare(tracker.track(buildSocialInteraction({ action, network, target })), expected, t); + compare(tracker.track(buildSocialInteraction({ action, network, target }))!, expected, t); }); test('should track an add-to-cart event', (t) => { const sku = '4q345'; @@ -434,7 +434,7 @@ test('should track an add-to-cart event', (t) => { data: inputJson, }), }; - compare(tracker.track(buildAddToCart({ sku, name, category, unitPrice, quantity, currency })), expected, t); + compare(tracker.track(buildAddToCart({ sku, name, category, unitPrice, quantity, currency }))!, expected, t); }); test('should track a remove-from-cart event', (t) => { const sku = '4q345'; @@ -461,7 +461,7 @@ test('should track a remove-from-cart event', (t) => { data: inputJson, }), }; - compare(tracker.track(buildRemoveFromCart({ sku, name, category, unitPrice, quantity, currency })), expected, t); + compare(tracker.track(buildRemoveFromCart({ sku, name, category, unitPrice, quantity, currency }))!, expected, t); }); test('should track a form focus event', (t) => { const formId = 'parent'; @@ -491,7 +491,7 @@ test('should track a form focus event', (t) => { compare( tracker.track( buildFormFocusOrChange({ schema: 'focus_form', formId, elementId, nodeName, type, elementClasses, value }) - ), + )!, expected, t ); @@ -524,7 +524,7 @@ test('should track a form change event', (t) => { compare( tracker.track( buildFormFocusOrChange({ schema: 'change_form', formId, elementId, nodeName, type, elementClasses, value }) - ), + )!, expected, t ); @@ -555,7 +555,7 @@ test('should track a form submission event', (t) => { data: inputJson, }), }; - compare(tracker.track(buildFormSubmission({ formId, formClasses, elements })), expected, t); + compare(tracker.track(buildFormSubmission({ formId, formClasses, elements }))!, expected, t); }); test('should track a site seach event', (t) => { const terms = ['javascript', 'development']; @@ -581,7 +581,7 @@ test('should track a site seach event', (t) => { data: inputJson, }), }; - compare(tracker.track(buildSiteSearch({ terms, filters, totalResults, pageResults })), expected, t); + compare(tracker.track(buildSiteSearch({ terms, filters, totalResults, pageResults }))!, expected, t); }); test('should track a consent withdrawn event', (t) => { const all = false; @@ -619,7 +619,7 @@ test('should track a consent withdrawn event', (t) => { }), }; const consentEvent = buildConsentWithdrawn({ all, id, version, name, description }); - compare(tracker.track(consentEvent.event, consentEvent.context, timestamp), expected, t); + compare(tracker.track(consentEvent.event, consentEvent.context, timestamp)!, expected, t); }); test('should track a consent granted event', (t) => { const id = '1234'; @@ -657,7 +657,7 @@ test('should track a consent granted event', (t) => { }), }; const consentEvent = buildConsentGranted({ id, version, name, description, expiry }); - compare(tracker.track(consentEvent.event, consentEvent.context, timestamp), expected, t); + compare(tracker.track(consentEvent.event, consentEvent.context, timestamp)!, expected, t); }); test('should track a page view with custom context', (t) => { const pageUrl = 'http://www.example.com'; @@ -682,7 +682,7 @@ test('should track a page view with custom context', (t) => { data: inputContext, }), }; - compare(tracker.track(buildPageView({ pageUrl, pageTitle, referrer }), inputContext), expected, t); + compare(tracker.track(buildPageView({ pageUrl, pageTitle, referrer }), inputContext)!, expected, t); }); test('should track a page view with a timestamp', (t) => { const timestamp = 1000000000000; @@ -691,7 +691,7 @@ test('should track a page view with a timestamp', (t) => { buildPageView({ pageUrl: 'http://www.example.com', pageTitle: 'title', referrer: 'ref' }), [], timestamp - )['dtm'], + )!['dtm'], '1000000000000' ); }); @@ -710,7 +710,7 @@ test('should add individual name-value pairs to the payload', (t) => { }; tracker.addPayloadPair('tna', 'sp'); tracker.addPayloadPair('tv', 'js-2.0.0'); - compare(tracker.track(buildPageView({ pageUrl, pageTitle, referrer })), expected, t); + compare(tracker.track(buildPageView({ pageUrl, pageTitle, referrer }))!, expected, t); }); test('should add a dictionary of name-value pairs to the payload', (t) => { const tracker = trackerCore({ base64: false }); @@ -731,7 +731,7 @@ test('should add a dictionary of name-value pairs to the payload', (t) => { tna: 'sp', aid: 'sp325', }); - compare(tracker.track(buildPageView({ pageUrl, pageTitle, referrer })), expected, t); + compare(tracker.track(buildPageView({ pageUrl, pageTitle, referrer }))!, expected, t); }); test('should reset payload name-value pairs', (t) => { const tracker = trackerCore({ base64: false }); @@ -747,7 +747,7 @@ test('should reset payload name-value pairs', (t) => { }; tracker.addPayloadPair('tna', 'mistake'); tracker.resetPayloadPairs({ tna: 'sp' }); - compare(tracker.track(buildPageView({ pageUrl, pageTitle, referrer })), expected, t); + compare(tracker.track(buildPageView({ pageUrl, pageTitle, referrer }))!, expected, t); }); test('should execute a callback', (t) => { const tracker = trackerCore({ @@ -802,7 +802,7 @@ test('should use setter methods', (t) => { ua: 'SnowplowJavascript/0.0.1', refr: referrer, }; - compare(tracker.track(buildPageView({ pageUrl, pageTitle, referrer })), expected, t); + compare(tracker.track(buildPageView({ pageUrl, pageTitle, referrer }))!, expected, t); }); test('should set true timestamp', (t) => { @@ -812,7 +812,7 @@ test('should set true timestamp', (t) => { const result = tracker.track(buildPageView({ pageUrl, pageTitle, referrer }), undefined, { type: 'ttm', value: 1477403862, - }); + })!; t.true('ttm' in result); t.is(result['ttm'], '1477403862'); t.false('dtm' in result); @@ -828,7 +828,7 @@ test('should set device timestamp as ADT', (t) => { const result = tracker.track(buildSelfDescribingEvent({ event: inputJson }), [inputJson], { type: 'dtm', value: 1477403869, - }); + })!; t.true('dtm' in result); t.is(result['dtm'], '1477403869'); t.false('ttm' in result); @@ -932,3 +932,105 @@ test('should run plugin before and after track callbacks on each track event', ( t.is(beforeCount, fs.length); t.is(afterCount, fs.length); }); + +test('should skip events in case the plugin filter function returns false', (t) => { + let countTracked = 0; + const tracker = trackerCore({ + base64: false, + corePlugins: [ + { + filter: (payload) => { + return payload.e !== 'pv'; + }, + }, + { + filter: (payload) => { + return payload.e !== 'pp'; + }, + }, + { + afterTrack: () => { + countTracked += 1; + }, + }, + ], + }); + + t.falsy( + tracker.track( + buildPageView({ + pageUrl: 'http://www.example.com', + pageTitle: 'title page', + referrer: 'https://www.google.com', + }) + ) + ); + + t.falsy( + tracker.track( + buildPagePing({ + pageUrl: 'http://www.example.com', + pageTitle: 'title page', + referrer: 'https://www.google.com', + maxXOffset: 1, + maxYOffset: 1, + minXOffset: 1, + minYOffset: 1, + }) + ) + ); + + t.truthy( + tracker.track( + buildAddToCart({ + category: 'cat', + name: 'name', + quantity: 1, + sku: 'sku', + unitPrice: 1, + }) + ) + ); + + t.assert(countTracked === 1); +}); + +test('filter is passed full payload including dynamic context', (t) => { + let countTracked = 0; + const tracker = trackerCore({ + base64: false, + corePlugins: [ + { + contexts: () => { + return [ + { + schema: 'iglu:com.acme/user/jsonschema/1-0-0', + data: { + userType: 'tester', + userName: 'Jon', + }, + }, + ] + }, + filter: (payload) => { + return (payload.co as string).includes('com.acme'); + }, + afterTrack: () => { + countTracked += 1; + }, + }, + ], + }); + + t.truthy( + tracker.track( + buildPageView({ + pageUrl: 'http://www.example.com', + pageTitle: 'title page', + referrer: 'https://www.google.com', + }) + ) + ); + + t.assert(countTracked === 1); +}); diff --git a/trackers/node-tracker/test/tracker.ts b/trackers/node-tracker/test/tracker.ts index a0636f4e3..c0fb90f37 100644 --- a/trackers/node-tracker/test/tracker.ts +++ b/trackers/node-tracker/test/tracker.ts @@ -110,7 +110,7 @@ for (const method of testMethods) { const eventPayload = track.track( buildPageView({ pageUrl: 'http://www.example.com', pageTitle: 'example page', referrer: 'http://google.com' }), context - ); + )!; t.truthy(eventPayload.eid); t.regex(eventPayload.eid as string, UUID_REGEX); }); From 530094ff8a5dcde040b87f89cdf1a89f4b71f484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matu=CC=81s=CC=8C=20Tomlein?= Date: Tue, 9 Jul 2024 13:54:42 +0200 Subject: [PATCH 2/4] Update API docs and run rush change --- .../markdown/browser-tracker.md | 3 +-- .../markdown/browser-tracker.newtracker.md | 5 ++-- .../markdown/browser-tracker.newtracker_1.md | 26 ------------------- .../node-tracker.coreplugin.filter.md | 13 ++++++++++ .../markdown/node-tracker.coreplugin.md | 1 + .../docs/node-tracker/node-tracker.api.md | 1 + .../issue-plugin_filter_2024-07-09-11-54.json | 10 +++++++ .../issue-plugin_filter_2024-07-09-11-54.json | 10 +++++++ .../issue-plugin_filter_2024-07-09-11-54.json | 10 +++++++ .../issue-plugin_filter_2024-07-09-11-54.json | 10 +++++++ .../issue-plugin_filter_2024-07-09-11-54.json | 10 +++++++ libraries/tracker-core/src/plugins.ts | 2 +- 12 files changed, 70 insertions(+), 31 deletions(-) delete mode 100644 api-docs/docs/browser-tracker/markdown/browser-tracker.newtracker_1.md create mode 100644 api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.filter.md create mode 100644 common/changes/@snowplow/browser-tracker-core/issue-plugin_filter_2024-07-09-11-54.json create mode 100644 common/changes/@snowplow/browser-tracker/issue-plugin_filter_2024-07-09-11-54.json create mode 100644 common/changes/@snowplow/javascript-tracker/issue-plugin_filter_2024-07-09-11-54.json create mode 100644 common/changes/@snowplow/node-tracker/issue-plugin_filter_2024-07-09-11-54.json create mode 100644 common/changes/@snowplow/tracker-core/issue-plugin_filter_2024-07-09-11-54.json diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.md index df73342ea..d9a8029bd 100644 --- a/api-docs/docs/browser-tracker/markdown/browser-tracker.md +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.md @@ -23,8 +23,7 @@ | [enableAnonymousTracking(configuration, trackers)](./browser-tracker.enableanonymoustracking.md) | Enables anonymous tracking (ie. tracker initialized without anonymousTracking) | | [flushBuffer(configuration, trackers)](./browser-tracker.flushbuffer.md) | Send all events in the outQueue Only need to use this when sending events with a bufferSize of at least 2 | | [newSession(trackers)](./browser-tracker.newsession.md) | Expires current session and starts a new session. | -| [newTracker(trackerId, endpoint)](./browser-tracker.newtracker.md) | Initialise a new tracker | -| [newTracker(trackerId, endpoint, configuration)](./browser-tracker.newtracker_1.md) | Initialise a new tracker | +| [newTracker(trackerId, endpoint, configuration)](./browser-tracker.newtracker.md) | Initialise a new tracker | | [preservePageViewId(trackers)](./browser-tracker.preservepageviewid.md) | Stop regenerating pageViewId (available from web_page context) | | [removeGlobalContexts(contexts, trackers)](./browser-tracker.removeglobalcontexts.md) | All provided contexts will no longer be sent with every event | | [setBufferSize(newBufferSize, trackers)](./browser-tracker.setbuffersize.md) | Set the buffer size Can be useful if you want to stop batching requests to ensure events start sending closer to event creation | diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.newtracker.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.newtracker.md index 446ff6375..23d477b89 100644 --- a/api-docs/docs/browser-tracker/markdown/browser-tracker.newtracker.md +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.newtracker.md @@ -9,7 +9,7 @@ Initialise a new tracker Signature: ```typescript -declare function newTracker(trackerId: string, endpoint: string): BrowserTracker; +declare function newTracker(trackerId: string, endpoint: string, configuration?: TrackerConfiguration): BrowserTracker | null | undefined; ``` ## Parameters @@ -18,8 +18,9 @@ declare function newTracker(trackerId: string, endpoint: string): BrowserTracker | --- | --- | --- | | trackerId | string | The tracker id - also known as tracker namespace | | endpoint | string | Collector endpoint in the form collector.mysite.com | +| configuration | TrackerConfiguration | The initialisation options of the tracker | Returns: -BrowserTracker +BrowserTracker \| null \| undefined diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.newtracker_1.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.newtracker_1.md deleted file mode 100644 index ac03fc02a..000000000 --- a/api-docs/docs/browser-tracker/markdown/browser-tracker.newtracker_1.md +++ /dev/null @@ -1,26 +0,0 @@ - - -[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [newTracker](./browser-tracker.newtracker_1.md) - -## newTracker() function - -Initialise a new tracker - -Signature: - -```typescript -declare function newTracker(trackerId: string, endpoint: string, configuration: TrackerConfiguration): BrowserTracker; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| trackerId | string | The tracker id - also known as tracker namespace | -| endpoint | string | Collector endpoint in the form collector.mysite.com | -| configuration | TrackerConfiguration | The initialisation options of the tracker | - -Returns: - -BrowserTracker - diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.filter.md b/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.filter.md new file mode 100644 index 000000000..c5d39c6d2 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.filter.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [CorePlugin](./node-tracker.coreplugin.md) > [filter](./node-tracker.coreplugin.filter.md) + +## CorePlugin.filter property + +Called before the payload is sent to the callback to decide whether to send the payload or skip it + +Signature: + +```typescript +filter?: (payload: Payload) => boolean; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.md b/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.md index 2106026ce..fd32c8130 100644 --- a/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.md +++ b/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.md @@ -20,5 +20,6 @@ interface CorePlugin | [afterTrack?](./node-tracker.coreplugin.aftertrack.md) | (payload: Payload) => void | (Optional) Called just after the trackerCore callback fires | | [beforeTrack?](./node-tracker.coreplugin.beforetrack.md) | (payloadBuilder: PayloadBuilder) => void | (Optional) Called just before the trackerCore callback fires | | [contexts?](./node-tracker.coreplugin.contexts.md) | () => SelfDescribingJson\[\] | (Optional) Called when constructing the context for each event Useful for adding additional context to events | +| [filter?](./node-tracker.coreplugin.filter.md) | (payload: Payload) => boolean | (Optional) Called before the payload is sent to the callback to decide whether to send the payload or skip it | | [logger?](./node-tracker.coreplugin.logger.md) | (logger: Logger) => void | (Optional) Passed a logger instance which can be used to send log information to the active logger | diff --git a/api-docs/docs/node-tracker/node-tracker.api.md b/api-docs/docs/node-tracker/node-tracker.api.md index 610668e54..de73dcc6c 100644 --- a/api-docs/docs/node-tracker/node-tracker.api.md +++ b/api-docs/docs/node-tracker/node-tracker.api.md @@ -179,6 +179,7 @@ export interface CorePlugin { afterTrack?: (payload: Payload) => void; beforeTrack?: (payloadBuilder: PayloadBuilder) => void; contexts?: () => SelfDescribingJson[]; + filter?: (payload: Payload) => boolean; // Warning: (ae-forgotten-export) The symbol "Logger" needs to be exported by the entry point index.module.d.ts logger?: (logger: Logger) => void; } diff --git a/common/changes/@snowplow/browser-tracker-core/issue-plugin_filter_2024-07-09-11-54.json b/common/changes/@snowplow/browser-tracker-core/issue-plugin_filter_2024-07-09-11-54.json new file mode 100644 index 000000000..927053c15 --- /dev/null +++ b/common/changes/@snowplow/browser-tracker-core/issue-plugin_filter_2024-07-09-11-54.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@snowplow/browser-tracker-core", + "comment": "Add a filter function to plugins to filter out events so that they are not tracked (#1326)", + "type": "none" + } + ], + "packageName": "@snowplow/browser-tracker-core" +} \ No newline at end of file diff --git a/common/changes/@snowplow/browser-tracker/issue-plugin_filter_2024-07-09-11-54.json b/common/changes/@snowplow/browser-tracker/issue-plugin_filter_2024-07-09-11-54.json new file mode 100644 index 000000000..035e343b1 --- /dev/null +++ b/common/changes/@snowplow/browser-tracker/issue-plugin_filter_2024-07-09-11-54.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@snowplow/browser-tracker", + "comment": "Add a filter function to plugins to filter out events so that they are not tracked (#1326)", + "type": "none" + } + ], + "packageName": "@snowplow/browser-tracker" +} \ No newline at end of file diff --git a/common/changes/@snowplow/javascript-tracker/issue-plugin_filter_2024-07-09-11-54.json b/common/changes/@snowplow/javascript-tracker/issue-plugin_filter_2024-07-09-11-54.json new file mode 100644 index 000000000..3ef2242ed --- /dev/null +++ b/common/changes/@snowplow/javascript-tracker/issue-plugin_filter_2024-07-09-11-54.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@snowplow/javascript-tracker", + "comment": "Add a filter function to plugins to filter out events so that they are not tracked (#1326)", + "type": "none" + } + ], + "packageName": "@snowplow/javascript-tracker" +} \ No newline at end of file diff --git a/common/changes/@snowplow/node-tracker/issue-plugin_filter_2024-07-09-11-54.json b/common/changes/@snowplow/node-tracker/issue-plugin_filter_2024-07-09-11-54.json new file mode 100644 index 000000000..53f8e7c04 --- /dev/null +++ b/common/changes/@snowplow/node-tracker/issue-plugin_filter_2024-07-09-11-54.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@snowplow/node-tracker", + "comment": "Add a filter function to plugins to filter out events so that they are not tracked (#1326)", + "type": "none" + } + ], + "packageName": "@snowplow/node-tracker" +} \ No newline at end of file diff --git a/common/changes/@snowplow/tracker-core/issue-plugin_filter_2024-07-09-11-54.json b/common/changes/@snowplow/tracker-core/issue-plugin_filter_2024-07-09-11-54.json new file mode 100644 index 000000000..28b4a64ac --- /dev/null +++ b/common/changes/@snowplow/tracker-core/issue-plugin_filter_2024-07-09-11-54.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@snowplow/tracker-core", + "comment": "Add a filter function to plugins to filter out events so that they are not tracked (#1326)", + "type": "none" + } + ], + "packageName": "@snowplow/tracker-core" +} \ No newline at end of file diff --git a/libraries/tracker-core/src/plugins.ts b/libraries/tracker-core/src/plugins.ts index 669c7f0fd..8cbd336a4 100644 --- a/libraries/tracker-core/src/plugins.ts +++ b/libraries/tracker-core/src/plugins.ts @@ -58,7 +58,7 @@ export interface CorePlugin { * @param payload - The final event payload, can't be modified. * @returns True if the payload should be sent, false if it should be skipped */ - filter?: (payloadBuilder: Payload) => boolean; + filter?: (payload: Payload) => boolean; /** * Called when constructing the context for each event * Useful for adding additional context to events From b41556ff86accaf07010201c5656fffdb3a5808b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matu=CC=81s=CC=8C=20Tomlein?= Date: Wed, 10 Jul 2024 09:29:28 +0200 Subject: [PATCH 3/4] Clarify docstring --- libraries/tracker-core/src/plugins.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/tracker-core/src/plugins.ts b/libraries/tracker-core/src/plugins.ts index 8cbd336a4..4d1f6c2d9 100644 --- a/libraries/tracker-core/src/plugins.ts +++ b/libraries/tracker-core/src/plugins.ts @@ -44,7 +44,7 @@ export interface CorePlugin { */ activateCorePlugin?: (core: TrackerCore) => void; /** - * Called just before the trackerCore callback fires + * Called before the `filter` method is called and before the trackerCore callback fires (if the filter passes) * @param payloadBuilder - The payloadBuilder which will be sent to the callback, can be modified */ beforeTrack?: (payloadBuilder: PayloadBuilder) => void; From b5f8daf868864e224bc928ea432b4759b20906d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matu=CC=81s=CC=8C=20Tomlein?= Date: Thu, 11 Jul 2024 15:43:20 +0200 Subject: [PATCH 4/4] Explicitly check for false as output from the filter function --- libraries/tracker-core/src/core.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/tracker-core/src/core.ts b/libraries/tracker-core/src/core.ts index b62afd622..41c7d4a54 100644 --- a/libraries/tracker-core/src/core.ts +++ b/libraries/tracker-core/src/core.ts @@ -407,7 +407,7 @@ export function trackerCore(configuration: CoreConfiguration = {}): TrackerCore // Call the filter on plugins to determine if the event should be tracked const skip = corePlugins.find((plugin) => { try { - return plugin.filter && !plugin.filter(pb.build()); + return plugin.filter && plugin.filter(pb.build()) === false; } catch (ex) { LOG.error('Plugin filter', ex); return false;