From 46987f87a22ca64eb81a22b304989808a0d544e8 Mon Sep 17 00:00:00 2001 From: royderks <10717410+royderks@users.noreply.github.com> Date: Fri, 8 May 2020 14:38:59 +0200 Subject: [PATCH] Expose the trackLink method in the react package as well, add a new method to enable link tracking in SPA without SSR as Matomo cant properly handle this --- packages/js/README.md | 5 +- packages/js/bundle.min.js | 2 +- packages/js/src/MatomoTracker.ts | 3 +- packages/js/src/types.ts | 3 +- packages/react/README.md | 59 ++++++++++++++++--- packages/react/src/types.ts | 3 + packages/react/src/useMatomo.ts | 9 +++ .../src/utils/useOutboundClickListener.tsx | 37 ++++++++++++ 8 files changed, 108 insertions(+), 13 deletions(-) create mode 100644 packages/react/src/utils/useOutboundClickListener.tsx diff --git a/packages/js/README.md b/packages/js/README.md index fb62c8f1..8142b382 100644 --- a/packages/js/README.md +++ b/packages/js/README.md @@ -47,6 +47,7 @@ const MatomoInstance = new window.MatomoTracker({ active: true, // optional, default value: true seconds: 10 // optional, default value: `15 } + linkTracking: false // optional, default value: true }) ``` @@ -69,7 +70,7 @@ MatomoInstance.trackEvent({ }) MatomoInstance.trackLink({ - 'https://link-to-other-website.org' + href: 'https://link-to-other-website.org', }) ``` @@ -112,7 +113,7 @@ MatomoInstance.trackEvent({ MatomoInstance.trackLink({ href: 'https://link-to-your-file.pdf', - linkType: 'download' // optional, default value 'link' + linkType: 'download', // optional, default value 'link' }) ``` diff --git a/packages/js/bundle.min.js b/packages/js/bundle.min.js index c460c75a..384255b8 100644 --- a/packages/js/bundle.min.js +++ b/packages/js/bundle.min.js @@ -1 +1 @@ -var MatomoTracker=function(t){"use strict";var i=function(){return(i=Object.assign||function(t){for(var e,r=1,o=arguments.length;r - + , ) ``` @@ -46,7 +46,11 @@ const MyPage = () => { trackEvent({ category: 'sample-page', action: 'click-event' }) } - return + return ( + + ) } ``` @@ -80,7 +84,11 @@ const MyPage = () => { trackEvent({ category: 'sample-page', action: 'click-event' }) } - return + return ( + + ) } ``` @@ -111,10 +119,45 @@ const MyPage = () => { }) } - return + return ( + + ) } ``` +## SPA Link Tracking + +Matomo provides the option to track outbound link, however, this implementation is flaky for a SPA (Single Page Application) **without** SSR (Server Side Rendering) across different versions of Matomo. Therefore you can use the `enableLinkTracking` method to listen to outbound clicks on anchor elements. This method should be placed on a component directly below your `MatomoProvider` on a component that's rendered on every page view. Also, make sure to disable the `enableLinkTracking` option on the instance passed to the provider to prevent Matomo from catching some link clicks: + +```js +import { MatomoProvider, createInstance } from '@datapunt/matomo-tracker-react' + +const instance = createInstance({ + urlBase: "https://LINK.TO.DOMAIN", + enableLinkTracking: false // Important! +}); + +ReactDOM.render( + + + +) + +const MyApp = () => { + const { enableLinkTracking } = useMatomo() + + enableLinkTracking() + + return ( + // Render components + ) +} + +``` + ## References - [Matomo JavaScript Tracking Guide](https://developer.matomo.org/guides/tracking-javascript-guide) +``` diff --git a/packages/react/src/types.ts b/packages/react/src/types.ts index 8531cada..e0ddab36 100644 --- a/packages/react/src/types.ts +++ b/packages/react/src/types.ts @@ -4,6 +4,7 @@ export interface MatomoInstance { trackEvent?: Function trackPageView?: Function trackSiteSearch?: Function + trackLink?: Function } export interface InstanceParams extends types.UserOptions {} @@ -13,3 +14,5 @@ export interface TrackPageViewParams extends types.TrackPageViewParams {} export interface TrackEventParams extends types.TrackEventParams {} export interface TrackSiteSearchParams extends types.TrackSiteSearchParams {} + +export interface TrackLinkParams extends types.TrackLinkParams {} diff --git a/packages/react/src/useMatomo.ts b/packages/react/src/useMatomo.ts index fdcb4141..59a22e3e 100644 --- a/packages/react/src/useMatomo.ts +++ b/packages/react/src/useMatomo.ts @@ -5,7 +5,9 @@ import { TrackPageViewParams, TrackEventParams, TrackSiteSearchParams, + TrackLinkParams, } from './types' +import useOutboundClickListener from './utils/useOutboundClickListener' function useMatomo() { const instance: MatomoInstance = React.useContext(MatomoContext) @@ -19,10 +21,17 @@ function useMatomo() { const trackSiteSearch = (params: TrackSiteSearchParams) => instance.trackSiteSearch && instance.trackSiteSearch(params) + const trackLink = (params: TrackLinkParams) => + instance.trackLink && instance.trackLink(params) + + const enableLinkTracking = () => useOutboundClickListener(instance) + return { trackEvent, trackPageView, trackSiteSearch, + trackLink, + enableLinkTracking, } } diff --git a/packages/react/src/utils/useOutboundClickListener.tsx b/packages/react/src/utils/useOutboundClickListener.tsx new file mode 100644 index 00000000..21a01f46 --- /dev/null +++ b/packages/react/src/utils/useOutboundClickListener.tsx @@ -0,0 +1,37 @@ +import React from 'react' +import { MatomoInstance } from '../types' + +const useOutboundClickListener = ({ trackLink }: MatomoInstance) => { + const handleOutboundClick = (event: MouseEvent) => { + if (!event.target) { + return + } + + const { target } = event + const { nodeName } = target as HTMLElement + + if (nodeName === 'A' && trackLink) { + const { href } = target as HTMLAnchorElement // We know from the nodeName that the element is an anchor + // Check if the click target differs from the current hostname, meaning it's external + if ( + href && + !href.match( + new RegExp( + `^(http://www.|https://www.|http://|https://)+(${window.location.hostname})`, + ), + ) + ) { + trackLink({ href }) + } + } + } + + React.useEffect(() => { + window.document.addEventListener('click', handleOutboundClick) + + return () => + window.document.removeEventListener('click', handleOutboundClick) + }, []) +} + +export default useOutboundClickListener