Uniform plugins

Plugins can extend tracking capabilities, and are added to the Uniform context object.

Uniform comes with the following plugins. These plugins aren't enabled by default. You must enable them by adding the required plugins to the Uniform context object.

The Context DevTools plugin causes the Uniform tracker to expose visitor classification data that the Context DevTools can display. For information on how to configure and use this plugin, see the Context DevTools guide.

  1. Add the following import at the top of the file:

    import { enableContextDevTools } from "@uniformdev/context";
  2. Find the code where the Uniform context object is created. It will look something like the following:

    const context = new Context({ manifest, });
  3. Add the following code:

    const context = new Context({ manifest, plugins: [ enableContextDevTools(), ] });

The console log plugin causes the Uniform tracker to write to the console.

  1. Add the following import at the top of the file:

    import { createConsoleLogDrain } from "@uniformdev/context";
  2. Find the code where the Uniform context object is created. It will look something like the following:

    const context = new Context({ manifest, });
  3. Add the following code:

    const context = new Context({ manifest, plugins: [ createConsoleLogDrain("debug"), ] });

    About this step

    The example above sets the logging output severity level to debug. For information on other severity levels, see the output severity reference.

The Uniform tracker emits events at various points as it controls classification, personalization, and other processes. You can assign listeners directly to the tracker to handle these events, but custom plugins offer a more reusable option.

This section provides examples of custom plugins.

This example demonstrates how visitor scores can be sent to a third-party API. In this example, the Uniform tracker maintains an enrichment role. Depending on the content the visitor views, they may have scores for multiple roles. This plug-in sends the name of the role with highest score to the third-party API.

  1. Find the code where the Uniform context object is created. It will look something like the following:

    const context = new Context({ manifest, });
  2. Add the following code to the file where the Uniform context object is created:

    function enableSendScores() { return { init: (context) => { const isRoleEnrichment = (key) => key.split("_")[0] == "role"; const getRoleName = (key) => key.split("_")[1]; // //Returns the name of the role with the largest score. const getRole = (scores) => { let role = undefined; Object.keys(scores).forEach(key => { if (!isRoleEnrichment(key)) return; const score = scores[key]; if (score > 0 && !role) { role = key; } else if (score > scores[role]) { role = key; } }); if (!role) return; return getRoleName(role); } // //Listen for the context event. context.events.on("scoresUpdated", (scores) => { const role = getRole(scores); if (!role) return; // //TODO: make API call using the role value. }); }, } }

    About this step

    By convention, a function is used to define the plugin. For information on the contract for a Context plugin, see the ContextPlugin reference.

  3. Add the following code:

    const context = new Context({ manifest, plugins: [ enableSendScores(), ] });

Here is an example of a custom plugin for Google Analytics.

import { ContextPlugin, PersonalizationEvent, TestEvent } from '@uniformdev/context'; declare global { interface Window { __UF_PATCHED_GTAG__?: boolean; } } export const enableGoogleGtagAnalytics = (options?: { /** If true, disables reflecting events passed to gtag into Uniform Context as event signals */ disableEventSignals?: boolean; /** Override the window object that will have the gtag property added to it */ theWindow?: { gtag?: Gtag.Gtag; __UF_PATCHED_GTAG__?: boolean }; /** Whether to emit every personalize and test that occurs, or only if something has actually changed * false (default): only emit events when a test assigns a variant the first time, or a personalization chooses different variants than before * true: emit an event every time a personalization or test is evaluated (e.g. for vDOM frameworks, each time a re-render occurs) */ emitAll?: boolean; }): ContextPlugin => { const { disableEventSignals, theWindow = typeof window !== 'undefined' ? window : undefined, emitAll, } = options || {}; const isGtagConfigured = (): boolean => { return typeof theWindow !== 'undefined' && typeof theWindow.gtag === 'function'; }; return { init: (context) => { // Handle emitting personalization results to GA4 const onPersonalizationResult = (result: PersonalizationEvent) => { if (!isGtagConfigured()) { context.log('warn', 700); return; } // only emit analytics events when the placement actually changes // (e.g. not every re-render) if (!emitAll && !result.changed) { return; } theWindow!.gtag?.('event', result.name, { event_category: 'Uniform Personalization', event_label: result.variantIds.join(', '), is_control_group: result.control ? 1 : 0, }); }; // Handle emitting test results to GA4 const onTestResult = (result: TestEvent) => { if (!isGtagConfigured()) { context.log('warn', 700); return; } // only emit analytics events when the placement actually changes // (e.g. not every re-render) if (!emitAll && !result.variantAssigned) { return; } theWindow!.gtag?.('event', result.name, { event_category: 'Uniform AB Testing', event_label: result.variantId ?? 'No Variant', }); }; context.events.on('personalizationResult', onPersonalizationResult); context.events.on('testResult', onTestResult); // Handle redirecting events from GA4 to event signals in Uniform Context if (!disableEventSignals && isGtagConfigured() && !theWindow?.__UF_PATCHED_GTAG__) { const defaultGtag = theWindow!.gtag; theWindow!.gtag = (...args: any[]) => { // @ts-ignore - we're passing the args through to the default gtag defaultGtag(...args); // if we get an event passed to gtag, emit it to Context. // Except our own test and personalization tracking events if ( args[0] === 'event' && !['Uniform AB Testing', 'Uniform Personalization'].includes(args[2]?.event_category) ) { context.update({ events: [{ event: args[1] }] }); } }; context.log('debug', 701); theWindow!.__UF_PATCHED_GTAG__ = true; } return () => { context.events.off('personalizationResult', onPersonalizationResult); context.events.off('testResult', onTestResult); }; }, }; };