analytics icon indicating copy to clipboard operation
analytics copied to clipboard

Add high level filter

Open vitonsky opened this issue 5 months ago • 1 comments

Hi, I glad you've implemented this high level abstraction over analytics services for me, because it's nice idea!

I have started thought about this idea when I've start creating my own implementation of plausible client https://github.com/vitonsky/plausible-client and my idea was to implement abstraction to aggregate all analytics services we use in project under single API to make only one call.

One of important features of this abstraction I needed in is a filter and transformer on high level, to implement flexible moderation of events.

Proposal

Some of my use cases is require to enrich events data at high level. Trivial example is add user ID and some specific data about current client like tags related to A/B testing group, etc.

In my solution mentioned above i can do it like that

import { Plausible, enableAutoOutboundTracking } from 'plausible-client';

const plausible = new Plausible({
  apiHost: 'https://plausible.io',
  domain: 'example.org',
  transform(event, eventName) {
    event.props = {
      ...event.props,
      group: 'clients',
      userId: event.props.uid ? "uuid:" + event.props.uid : undefined,
      isPreferDarkTheme: window.matchMedia("(prefers-color-scheme: dark)").matches,
    };

    return event;
  }
});

Another case is high level filtering for all events based on user preferences and groups. In my solution it works like that

import { Plausible, enableAutoOutboundTracking } from 'plausible-client';

const plausible = new Plausible({
  apiHost: 'https://plausible.io',
  domain: 'example.org',
  filter(event, eventName) {
    // Skip all events while development
    if (location.hostname === 'localhost') {
      console.warn('Analytics event is skipped, since run on localhost', event);
      return false;
    }

    // Skip all events for users who don't want to be tracked
    if (window.localStorage.plausible_ignore === 'true') return false;

    // Skip events by event props
    if (event.props.group === 'no-track') return false;

    // Skip events by its name, for users who does not participate in preview program
    if (!event.props.previewEnabled && eventName.startsWith('preview:')) return false;

    // Pass all events otherwise
    return true;
  }
});

As I said, I glad you've implemented this idea with high level abstraction. Now, let's implement this features to rule data on high level, instead of copying this logic for every service config.

If code designed fine, implementation of this features will be trivial. Look at my implementation that takes a few lines of code: https://github.com/vitonsky/plausible-client/blob/8d2e3877067c655c8b5fafcd52bd1fa2262fa491/src/Plausible.ts#L73-L79

vitonsky avatar Jul 09 '25 06:07 vitonsky

The library was designed with filters/transforms in mind

There is a lifecycle that every plugin flows through https://getanalytics.io/lifecycle/#track-events

If you hook into the [page/track/identify]Start you can cancel/transform events

You can intercept any of these calls on a global or per-plugin basis and abort calls or transform the data however you wish

See https://getanalytics.io/tutorials/enriching-data/ for transforming data.

Here are some abort examples https://github.com/DavidWells/analytics/blob/f71336dbddbde41567668b937d1267fa8d68b48b/examples/demo/src/utils/analytics/just-ga.js#L6-L11

DavidWells avatar Jul 10 '25 21:07 DavidWells