matomo-tracker-for-react 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +373 -0
- package/README.md +194 -0
- package/es/MatomoContext.d.ts +5 -0
- package/es/MatomoContext.d.ts.map +1 -0
- package/es/MatomoContext.js +4 -0
- package/es/MatomoContext.js.map +1 -0
- package/es/MatomoProvider.d.ts +5 -0
- package/es/MatomoProvider.d.ts.map +1 -0
- package/es/MatomoProvider.js +94 -0
- package/es/MatomoProvider.js.map +1 -0
- package/es/MatomoTracker.d.ts +49 -0
- package/es/MatomoTracker.d.ts.map +1 -0
- package/es/MatomoTracker.js +330 -0
- package/es/MatomoTracker.js.map +1 -0
- package/es/constants.d.ts +11 -0
- package/es/constants.d.ts.map +1 -0
- package/es/constants.js +13 -0
- package/es/constants.js.map +1 -0
- package/es/index.d.ts +15 -0
- package/es/index.d.ts.map +1 -0
- package/es/index.js +6 -0
- package/es/index.js.map +1 -0
- package/es/tracker-types.d.ts +76 -0
- package/es/tracker-types.d.ts.map +1 -0
- package/es/tracker-types.js +2 -0
- package/es/tracker-types.js.map +1 -0
- package/es/types.d.ts +19 -0
- package/es/types.d.ts.map +1 -0
- package/es/types.js +3 -0
- package/es/types.js.map +1 -0
- package/es/useMatomo.d.ts +4 -0
- package/es/useMatomo.d.ts.map +1 -0
- package/es/useMatomo.js +30 -0
- package/es/useMatomo.js.map +1 -0
- package/lib/MatomoContext.d.ts +5 -0
- package/lib/MatomoContext.d.ts.map +1 -0
- package/lib/MatomoContext.js +6 -0
- package/lib/MatomoContext.js.map +1 -0
- package/lib/MatomoProvider.d.ts +5 -0
- package/lib/MatomoProvider.d.ts.map +1 -0
- package/lib/MatomoProvider.js +122 -0
- package/lib/MatomoProvider.js.map +1 -0
- package/lib/MatomoTracker.d.ts +49 -0
- package/lib/MatomoTracker.d.ts.map +1 -0
- package/lib/MatomoTracker.js +332 -0
- package/lib/MatomoTracker.js.map +1 -0
- package/lib/constants.d.ts +11 -0
- package/lib/constants.d.ts.map +1 -0
- package/lib/constants.js +16 -0
- package/lib/constants.js.map +1 -0
- package/lib/index.d.ts +15 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +29 -0
- package/lib/index.js.map +1 -0
- package/lib/tracker-types.d.ts +76 -0
- package/lib/tracker-types.d.ts.map +1 -0
- package/lib/tracker-types.js +3 -0
- package/lib/tracker-types.js.map +1 -0
- package/lib/types.d.ts +19 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +19 -0
- package/lib/types.js.map +1 -0
- package/lib/useMatomo.d.ts +4 -0
- package/lib/useMatomo.d.ts.map +1 -0
- package/lib/useMatomo.js +35 -0
- package/lib/useMatomo.js.map +1 -0
- package/package.json +58 -0
- package/src/MatomoContext.tsx +6 -0
- package/src/MatomoProvider.tsx +93 -0
- package/src/MatomoTracker.ts +415 -0
- package/src/constants.ts +12 -0
- package/src/index.ts +20 -0
- package/src/tracker-types.ts +89 -0
- package/src/types.ts +29 -0
- package/src/useMatomo.ts +55 -0
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
import { TRACK_TYPES } from "./constants";
|
|
2
|
+
import {
|
|
3
|
+
AddEcommerceItemParams,
|
|
4
|
+
RemoveEcommerceItemParams,
|
|
5
|
+
CustomDimension,
|
|
6
|
+
SetEcommerceViewParams,
|
|
7
|
+
TrackEcommerceOrderParams,
|
|
8
|
+
TrackEventParams,
|
|
9
|
+
TrackLinkParams,
|
|
10
|
+
TrackPageViewParams,
|
|
11
|
+
TrackParams,
|
|
12
|
+
TrackSiteSearchParams,
|
|
13
|
+
UserOptions,
|
|
14
|
+
} from "./tracker-types";
|
|
15
|
+
|
|
16
|
+
declare global {
|
|
17
|
+
interface Window {
|
|
18
|
+
_paq?: Array<any[]>;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
class MatomoTracker {
|
|
23
|
+
private mutationObserver?: MutationObserver;
|
|
24
|
+
private isInitialized = false;
|
|
25
|
+
|
|
26
|
+
constructor(userOptions: UserOptions) {
|
|
27
|
+
if (typeof window === "undefined") {
|
|
28
|
+
// Don't run in SSR or non-browser environments
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (!userOptions.urlBase) {
|
|
32
|
+
throw new Error("Matomo urlBase is required.");
|
|
33
|
+
}
|
|
34
|
+
if (userOptions.siteId === undefined || userOptions.siteId === null) {
|
|
35
|
+
throw new Error("Matomo siteId is required.");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this.initialize(userOptions);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private initialize({
|
|
42
|
+
urlBase,
|
|
43
|
+
siteId,
|
|
44
|
+
userId,
|
|
45
|
+
trackerUrl,
|
|
46
|
+
srcUrl,
|
|
47
|
+
disabled = false,
|
|
48
|
+
heartBeat,
|
|
49
|
+
linkTracking = true,
|
|
50
|
+
configurations = {},
|
|
51
|
+
}: UserOptions) {
|
|
52
|
+
if (disabled) {
|
|
53
|
+
// If disabled, make all tracking calls no-ops by not initializing _paq or the script
|
|
54
|
+
this.pushInstruction = (..._args: any[]): MatomoTracker => this; // No-op
|
|
55
|
+
// Make other methods no-op as well
|
|
56
|
+
const noOp = () => {};
|
|
57
|
+
this.trackEvent = noOp as any;
|
|
58
|
+
this.trackPageView = noOp as any;
|
|
59
|
+
this.trackSiteSearch = noOp as any;
|
|
60
|
+
this.trackLink = noOp as any;
|
|
61
|
+
// ... and so on for all public methods
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const normalizedUrlBase = urlBase.endsWith("/") ? urlBase : `${urlBase}/`;
|
|
66
|
+
|
|
67
|
+
window._paq = window._paq || [];
|
|
68
|
+
|
|
69
|
+
// Prevent re-initialization if _paq already has Matomo commands beyond simple presence
|
|
70
|
+
if (
|
|
71
|
+
this.isInitialized ||
|
|
72
|
+
(window._paq.length > 0 &&
|
|
73
|
+
window._paq.some((cmd) => cmd[0] === "setTrackerUrl"))
|
|
74
|
+
) {
|
|
75
|
+
// If siteId or userId needs to be updated on an existing instance:
|
|
76
|
+
if (siteId) this.pushInstruction("setSiteId", siteId);
|
|
77
|
+
if (userId) this.pushInstruction("setUserId", userId);
|
|
78
|
+
// Potentially re-apply other configurations if needed, or assume they are sticky
|
|
79
|
+
this.isInitialized = true;
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this.pushInstruction(
|
|
84
|
+
"setTrackerUrl",
|
|
85
|
+
trackerUrl ?? `${normalizedUrlBase}matomo.php`
|
|
86
|
+
);
|
|
87
|
+
this.pushInstruction("setSiteId", siteId);
|
|
88
|
+
|
|
89
|
+
if (userId) {
|
|
90
|
+
this.pushInstruction("setUserId", userId);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
Object.entries(configurations).forEach(([name, instructions]) => {
|
|
94
|
+
if (name === "disableCookies" && typeof instructions === "boolean") {
|
|
95
|
+
this.pushInstruction("disableCookies"); // Matomo's disableCookies takes no arguments if called this way
|
|
96
|
+
} else if (instructions instanceof Array) {
|
|
97
|
+
this.pushInstruction(name, ...instructions);
|
|
98
|
+
} else {
|
|
99
|
+
this.pushInstruction(name, instructions);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
if (!heartBeat || (heartBeat && heartBeat.active)) {
|
|
104
|
+
this.enableHeartBeatTimer((heartBeat && heartBeat.seconds) ?? 15);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this.enableLinkTracking(linkTracking);
|
|
108
|
+
|
|
109
|
+
const doc = document;
|
|
110
|
+
const scriptElement = doc.createElement("script");
|
|
111
|
+
const scripts = doc.getElementsByTagName("script")[0];
|
|
112
|
+
|
|
113
|
+
scriptElement.type = "text/javascript";
|
|
114
|
+
scriptElement.async = true;
|
|
115
|
+
scriptElement.defer = true;
|
|
116
|
+
scriptElement.src = srcUrl || `${normalizedUrlBase}matomo.js`;
|
|
117
|
+
|
|
118
|
+
if (scripts && scripts.parentNode) {
|
|
119
|
+
scripts.parentNode.insertBefore(scriptElement, scripts);
|
|
120
|
+
}
|
|
121
|
+
this.isInitialized = true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
enableHeartBeatTimer(seconds: number): void {
|
|
125
|
+
this.pushInstruction("enableHeartBeatTimer", seconds);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
enableLinkTracking(active: boolean): void {
|
|
129
|
+
this.pushInstruction("enableLinkTracking", active);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private trackEventsForElements(elements: HTMLElement[]) {
|
|
133
|
+
if (elements.length) {
|
|
134
|
+
elements.forEach((element) => {
|
|
135
|
+
element.addEventListener("click", () => {
|
|
136
|
+
const { matomoCategory, matomoAction, matomoName, matomoValue } =
|
|
137
|
+
element.dataset;
|
|
138
|
+
if (matomoCategory && matomoAction) {
|
|
139
|
+
this.trackEvent({
|
|
140
|
+
category: matomoCategory,
|
|
141
|
+
action: matomoAction,
|
|
142
|
+
name: matomoName,
|
|
143
|
+
value: matomoValue ? Number(matomoValue) : undefined,
|
|
144
|
+
});
|
|
145
|
+
} else {
|
|
146
|
+
throw new Error(
|
|
147
|
+
`Error: data-matomo-category and data-matomo-action are required.`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Tracks events based on data attributes
|
|
156
|
+
trackEvents(): void {
|
|
157
|
+
if (typeof window === "undefined" || !document) return;
|
|
158
|
+
|
|
159
|
+
const matchString = '[data-matomo-event="click"]';
|
|
160
|
+
let firstTime = false;
|
|
161
|
+
if (!this.mutationObserver) {
|
|
162
|
+
firstTime = true;
|
|
163
|
+
this.mutationObserver = new MutationObserver((mutations) => {
|
|
164
|
+
mutations.forEach((mutation) => {
|
|
165
|
+
mutation.addedNodes.forEach((node) => {
|
|
166
|
+
// only track HTML elements
|
|
167
|
+
if (!(node instanceof HTMLElement)) return;
|
|
168
|
+
|
|
169
|
+
// check the inserted element for being a code snippet
|
|
170
|
+
if (node.matches(matchString)) {
|
|
171
|
+
this.trackEventsForElements([node]);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const elements = Array.from(
|
|
175
|
+
node.querySelectorAll<HTMLElement>(matchString)
|
|
176
|
+
);
|
|
177
|
+
this.trackEventsForElements(elements);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
this.mutationObserver.observe(document, { childList: true, subtree: true });
|
|
183
|
+
|
|
184
|
+
// Now track all already existing elements
|
|
185
|
+
if (firstTime) {
|
|
186
|
+
const elements = Array.from(
|
|
187
|
+
document.querySelectorAll<HTMLElement>(matchString)
|
|
188
|
+
);
|
|
189
|
+
this.trackEventsForElements(elements);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
stopObserving(): void {
|
|
194
|
+
if (this.mutationObserver) {
|
|
195
|
+
this.mutationObserver.disconnect();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Tracks events
|
|
200
|
+
// https://matomo.org/docs/event-tracking/#tracking-events
|
|
201
|
+
trackEvent({
|
|
202
|
+
category,
|
|
203
|
+
action,
|
|
204
|
+
name,
|
|
205
|
+
value,
|
|
206
|
+
...otherParams
|
|
207
|
+
}: TrackEventParams): void {
|
|
208
|
+
if (category && action) {
|
|
209
|
+
this.track({
|
|
210
|
+
data: [TRACK_TYPES.TRACK_EVENT, category, action, name, value],
|
|
211
|
+
...otherParams,
|
|
212
|
+
});
|
|
213
|
+
} else {
|
|
214
|
+
throw new Error(`Error: category and action are required.`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Tracks site search
|
|
219
|
+
// https://developer.matomo.org/guides/tracking-javascript-guide#internal-search-tracking
|
|
220
|
+
trackSiteSearch({
|
|
221
|
+
keyword,
|
|
222
|
+
category,
|
|
223
|
+
count,
|
|
224
|
+
...otherParams
|
|
225
|
+
}: TrackSiteSearchParams): void {
|
|
226
|
+
if (keyword) {
|
|
227
|
+
this.track({
|
|
228
|
+
data: [TRACK_TYPES.TRACK_SEARCH, keyword, category, count],
|
|
229
|
+
...otherParams,
|
|
230
|
+
});
|
|
231
|
+
} else {
|
|
232
|
+
throw new Error(`Error: keyword is required.`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Tracks outgoing links to other sites and downloads
|
|
237
|
+
// https://developer.matomo.org/guides/tracking-javascript-guide#enabling-download-outlink-tracking
|
|
238
|
+
trackLink({
|
|
239
|
+
href,
|
|
240
|
+
linkType = "link",
|
|
241
|
+
customDimensions,
|
|
242
|
+
}: TrackLinkParams): void {
|
|
243
|
+
if (
|
|
244
|
+
customDimensions &&
|
|
245
|
+
Array.isArray(customDimensions) &&
|
|
246
|
+
customDimensions.length
|
|
247
|
+
) {
|
|
248
|
+
customDimensions.forEach((customDimension: CustomDimension) =>
|
|
249
|
+
this.pushInstruction(
|
|
250
|
+
"setCustomDimension",
|
|
251
|
+
customDimension.id,
|
|
252
|
+
customDimension.value
|
|
253
|
+
)
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
this.pushInstruction(TRACK_TYPES.TRACK_LINK, href, linkType);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Tracks page views
|
|
260
|
+
// https://developer.matomo.org/guides/spa-tracking#tracking-a-new-page-view
|
|
261
|
+
trackPageView(params?: TrackPageViewParams): void {
|
|
262
|
+
this.track({ data: [TRACK_TYPES.TRACK_VIEW], ...params });
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Adds a product to an Ecommerce order to be tracked via trackEcommerceOrder.
|
|
266
|
+
// https://matomo.org/docs/ecommerce-analytics
|
|
267
|
+
// https://matomo.org/docs/ecommerce-analytics/#1-addecommerceitemproductsku-productname-productcategory-price-quantity
|
|
268
|
+
addEcommerceItem({
|
|
269
|
+
sku,
|
|
270
|
+
productName,
|
|
271
|
+
productCategory,
|
|
272
|
+
productPrice = 0.0,
|
|
273
|
+
productQuantity = 1,
|
|
274
|
+
}: AddEcommerceItemParams): void {
|
|
275
|
+
this.pushInstruction(
|
|
276
|
+
"addEcommerceItem",
|
|
277
|
+
sku,
|
|
278
|
+
productName,
|
|
279
|
+
productCategory,
|
|
280
|
+
productPrice,
|
|
281
|
+
productQuantity
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Removes a product from an Ecommerce order to be tracked via trackEcommerceOrder.
|
|
286
|
+
// https://matomo.org/docs/ecommerce-analytics
|
|
287
|
+
removeEcommerceItem({ sku }: RemoveEcommerceItemParams): void {
|
|
288
|
+
this.pushInstruction("removeEcommerceItem", sku);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Removes all products from an Ecommerce order to be tracked via trackEcommerceOrder.
|
|
292
|
+
// https://matomo.org/docs/ecommerce-analytics
|
|
293
|
+
clearEcommerceCart(): void {
|
|
294
|
+
this.pushInstruction("clearEcommerceCart");
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Tracks an Ecommerce order containing items added via addEcommerceItem.
|
|
298
|
+
// https://matomo.org/docs/ecommerce-analytics/#2-trackecommerceorderorderid-revenue-subtotal-tax-shipping-discount
|
|
299
|
+
trackEcommerceOrder({
|
|
300
|
+
orderId,
|
|
301
|
+
orderRevenue,
|
|
302
|
+
orderSubTotal,
|
|
303
|
+
taxAmount,
|
|
304
|
+
shippingAmount,
|
|
305
|
+
discountOffered = false,
|
|
306
|
+
}: TrackEcommerceOrderParams): void {
|
|
307
|
+
this.track({
|
|
308
|
+
data: [
|
|
309
|
+
TRACK_TYPES.TRACK_ECOMMERCE_ORDER,
|
|
310
|
+
orderId,
|
|
311
|
+
orderRevenue,
|
|
312
|
+
orderSubTotal,
|
|
313
|
+
taxAmount,
|
|
314
|
+
shippingAmount,
|
|
315
|
+
discountOffered,
|
|
316
|
+
],
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Tracks updates to an Ecommerce Cart before an actual purchase.
|
|
321
|
+
// This will replace currently tracked information of the cart. Always include all items of the updated cart!
|
|
322
|
+
// https://matomo.org/docs/ecommerce-analytics/#example-tracking-an-ecommerce-cart-update-containing-two-products
|
|
323
|
+
trackEcommerceCartUpdate(amount: number): void {
|
|
324
|
+
this.pushInstruction(TRACK_TYPES.TRACK_ECOMMERCE_CART_UPDATE, amount);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Marks the next page view as an Ecommerce product page.
|
|
328
|
+
// https://matomo.org/docs/ecommerce-analytics/#example-tracking-a-product-page-view
|
|
329
|
+
setEcommerceView({
|
|
330
|
+
sku,
|
|
331
|
+
productName,
|
|
332
|
+
productCategory,
|
|
333
|
+
productPrice,
|
|
334
|
+
}: SetEcommerceViewParams): void {
|
|
335
|
+
this.pushInstruction(
|
|
336
|
+
"setEcommerceView",
|
|
337
|
+
sku,
|
|
338
|
+
productName,
|
|
339
|
+
productCategory,
|
|
340
|
+
productPrice
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Marks the next tracked page view as an Ecommerce category page.
|
|
345
|
+
// https://matomo.org/docs/ecommerce-analytics/#example-tracking-a-category-page-view
|
|
346
|
+
setEcommerceCategoryView(productCategory: string): void {
|
|
347
|
+
this.setEcommerceView({ productCategory, productName: false, sku: false });
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Sends the tracked page/view/search to Matomo
|
|
351
|
+
private track({
|
|
352
|
+
data = [],
|
|
353
|
+
documentTitle, // Changed: use passed documentTitle or fallback to window.document.title later
|
|
354
|
+
href,
|
|
355
|
+
customDimensions = false,
|
|
356
|
+
}: TrackParams): void {
|
|
357
|
+
if (typeof window === "undefined") return;
|
|
358
|
+
|
|
359
|
+
if (data.length) {
|
|
360
|
+
if (
|
|
361
|
+
customDimensions &&
|
|
362
|
+
Array.isArray(customDimensions) &&
|
|
363
|
+
customDimensions.length
|
|
364
|
+
) {
|
|
365
|
+
customDimensions.forEach(
|
|
366
|
+
(
|
|
367
|
+
customDimension: CustomDimension // Corrected type
|
|
368
|
+
) =>
|
|
369
|
+
this.pushInstruction(
|
|
370
|
+
"setCustomDimension",
|
|
371
|
+
customDimension.id,
|
|
372
|
+
customDimension.value
|
|
373
|
+
)
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
this.pushInstruction("setCustomUrl", href ?? window.location.href);
|
|
378
|
+
// Use provided documentTitle, fallback to actual document.title only if not provided
|
|
379
|
+
this.pushInstruction(
|
|
380
|
+
"setDocumentTitle",
|
|
381
|
+
documentTitle ?? window.document.title
|
|
382
|
+
);
|
|
383
|
+
this.pushInstruction(...(data as [string, ...any[]]));
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Pushes an instruction to Matomo for execution, this is equivalent to pushing entries into the `_paq` array.
|
|
389
|
+
*
|
|
390
|
+
* For example:
|
|
391
|
+
*
|
|
392
|
+
* ```ts
|
|
393
|
+
* pushInstruction('setDocumentTitle', document.title)
|
|
394
|
+
* ```
|
|
395
|
+
* Is the equivalent of:
|
|
396
|
+
*
|
|
397
|
+
* ```ts
|
|
398
|
+
* _paq.push(['setDocumentTitle', document.title]);
|
|
399
|
+
* ```
|
|
400
|
+
*
|
|
401
|
+
* @param name The name of the instruction to be executed.
|
|
402
|
+
* @param args The arguments to pass along with the instruction.
|
|
403
|
+
*/
|
|
404
|
+
pushInstruction(name: string, ...args: any[]): MatomoTracker {
|
|
405
|
+
if (typeof window !== "undefined" && window._paq) {
|
|
406
|
+
window._paq.push([name, ...args]);
|
|
407
|
+
} else if (typeof window !== "undefined" && name === "setTrackerUrl") {
|
|
408
|
+
// Allow setting up _paq if it's the first instruction (like setTrackerUrl)
|
|
409
|
+
window._paq = [[name, ...args]];
|
|
410
|
+
}
|
|
411
|
+
return this;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
export default MatomoTracker;
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// eslint-disable-next-line import/prefer-default-export
|
|
2
|
+
export const TRACK_TYPES = {
|
|
3
|
+
TRACK_EVENT: "trackEvent",
|
|
4
|
+
TRACK_LINK: "trackLink",
|
|
5
|
+
TRACK_SEARCH: "trackSiteSearch",
|
|
6
|
+
TRACK_VIEW: "trackPageView",
|
|
7
|
+
TRACK_ECOMMERCE_ORDER: "trackEcommerceOrder",
|
|
8
|
+
TRACK_ECOMMERCE_CART_UPDATE: "trackEcommerceCartUpdate",
|
|
9
|
+
// Add other Matomo instructions if needed, e.g., for goals
|
|
10
|
+
TRACK_GOAL: "trackGoal",
|
|
11
|
+
SET_USER_ID: "setUserId",
|
|
12
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export { default as MatomoProvider } from "./MatomoProvider";
|
|
2
|
+
export { default as useMatomo } from "./useMatomo";
|
|
3
|
+
export { default as MatomoContext } from "./MatomoContext"; // Optional: if users need direct context access
|
|
4
|
+
|
|
5
|
+
// Export types for consumers
|
|
6
|
+
export * from "./types"; // Exports React-specific types and re-exports tracker-types
|
|
7
|
+
// Explicitly export core tracker types if not fully covered by ./types
|
|
8
|
+
export type {
|
|
9
|
+
CustomDimension,
|
|
10
|
+
UserOptions, // This is the core UserOptions, MatomoProviderProps is different
|
|
11
|
+
TrackPageViewParams, // Core type
|
|
12
|
+
TrackEventParams, // Core type
|
|
13
|
+
TrackLinkParams, // Core type
|
|
14
|
+
TrackSiteSearchParams, // Core type, though not directly used by simplified hook
|
|
15
|
+
TrackEcommerceOrderParams, // Core type
|
|
16
|
+
AddEcommerceItemParams, // Core type
|
|
17
|
+
RemoveEcommerceItemParams, // Core type
|
|
18
|
+
SetEcommerceViewParams, // Core type
|
|
19
|
+
TrackGoalParams, // Core type
|
|
20
|
+
} from "./tracker-types";
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export interface CustomDimension {
|
|
2
|
+
id: number;
|
|
3
|
+
value: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface UserOptions {
|
|
7
|
+
urlBase: string;
|
|
8
|
+
siteId: number; // Matomo site ID is typically a number
|
|
9
|
+
userId?: string;
|
|
10
|
+
trackerUrl?: string;
|
|
11
|
+
srcUrl?: string;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
heartBeat?: {
|
|
14
|
+
active: boolean;
|
|
15
|
+
seconds?: number;
|
|
16
|
+
};
|
|
17
|
+
linkTracking?: boolean;
|
|
18
|
+
configurations?: {
|
|
19
|
+
[key: string]: any;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface TrackPageViewParams {
|
|
24
|
+
documentTitle?: string;
|
|
25
|
+
href?: string | Location;
|
|
26
|
+
customDimensions?: boolean | CustomDimension[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface TrackParams extends TrackPageViewParams {
|
|
30
|
+
data: any[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface TrackEventParams {
|
|
34
|
+
category: string;
|
|
35
|
+
action: string;
|
|
36
|
+
name?: string;
|
|
37
|
+
value?: number;
|
|
38
|
+
// Allow other params to be passed through for flexibility with customDimensions, etc.
|
|
39
|
+
documentTitle?: string;
|
|
40
|
+
href?: string | Location;
|
|
41
|
+
customDimensions?: boolean | CustomDimension[];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface TrackLinkParams {
|
|
45
|
+
href: string;
|
|
46
|
+
linkType?: "download" | "link";
|
|
47
|
+
// Allow other params
|
|
48
|
+
customDimensions?: boolean | CustomDimension[];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface TrackSiteSearchParams extends TrackPageViewParams {
|
|
52
|
+
keyword: string;
|
|
53
|
+
category?: string;
|
|
54
|
+
count?: number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface TrackEcommerceOrderParams {
|
|
58
|
+
orderId: string;
|
|
59
|
+
orderRevenue: number;
|
|
60
|
+
orderSubTotal?: number;
|
|
61
|
+
taxAmount?: number;
|
|
62
|
+
shippingAmount?: number;
|
|
63
|
+
discountOffered?: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface AddEcommerceItemParams {
|
|
67
|
+
sku: string;
|
|
68
|
+
productName?: string;
|
|
69
|
+
productCategory?: string;
|
|
70
|
+
productPrice?: number;
|
|
71
|
+
productQuantity?: number;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface RemoveEcommerceItemParams {
|
|
75
|
+
sku: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface SetEcommerceViewParams {
|
|
79
|
+
sku: string | boolean;
|
|
80
|
+
productName?: string | boolean;
|
|
81
|
+
productCategory?: string;
|
|
82
|
+
productPrice?: number;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Added for useMatomo hook
|
|
86
|
+
export interface TrackGoalParams {
|
|
87
|
+
goalId: number | string;
|
|
88
|
+
revenue?: number;
|
|
89
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
// Re-export tracker types for convenience if needed by consumers of the React package
|
|
4
|
+
export * from "./tracker-types";
|
|
5
|
+
|
|
6
|
+
export interface MatomoProviderProps {
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
urlBase: string;
|
|
9
|
+
siteId: string | number;
|
|
10
|
+
trackCookies?: boolean;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface MatomoInstance {
|
|
15
|
+
trackEvent: (
|
|
16
|
+
category: string,
|
|
17
|
+
action: string,
|
|
18
|
+
name?: string,
|
|
19
|
+
value?: number
|
|
20
|
+
) => void;
|
|
21
|
+
trackPageView: (customTitle?: string) => void;
|
|
22
|
+
trackGoal: (goalId: number | string, revenue?: number) => void;
|
|
23
|
+
setUserId: (userId: string) => void;
|
|
24
|
+
trackLink: (url: string, linkType: "link" | "download") => void;
|
|
25
|
+
pushInstruction: (instruction: any[]) => void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// For useMatomo hook return type
|
|
29
|
+
export type UseMatomo = MatomoInstance;
|
package/src/useMatomo.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { useContext, useCallback } from "react";
|
|
2
|
+
import MatomoContext from "./MatomoContext";
|
|
3
|
+
import { UseMatomo } from "./types";
|
|
4
|
+
|
|
5
|
+
function useMatomo(): UseMatomo {
|
|
6
|
+
const context = useContext(MatomoContext);
|
|
7
|
+
|
|
8
|
+
if (context === null) {
|
|
9
|
+
throw new Error("useMatomo must be used within a MatomoProvider");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const trackPageView = useCallback(
|
|
13
|
+
(customTitle?: string) => context.trackPageView(customTitle),
|
|
14
|
+
[context]
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const trackEvent = useCallback(
|
|
18
|
+
(category: string, action: string, name?: string, value?: number) =>
|
|
19
|
+
context.trackEvent(category, action, name, value),
|
|
20
|
+
[context]
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const trackGoal = useCallback(
|
|
24
|
+
(goalId: number | string, revenue?: number) =>
|
|
25
|
+
context.trackGoal(goalId, revenue),
|
|
26
|
+
[context]
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const setUserId = useCallback(
|
|
30
|
+
(userId: string) => context.setUserId(userId),
|
|
31
|
+
[context]
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const trackLink = useCallback(
|
|
35
|
+
(url: string, linkType: "link" | "download") =>
|
|
36
|
+
context.trackLink(url, linkType),
|
|
37
|
+
[context]
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const pushInstruction = useCallback(
|
|
41
|
+
(instruction: any[]) => context.pushInstruction(instruction),
|
|
42
|
+
[context]
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
trackEvent,
|
|
47
|
+
trackPageView,
|
|
48
|
+
trackGoal,
|
|
49
|
+
setUserId,
|
|
50
|
+
trackLink,
|
|
51
|
+
pushInstruction,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default useMatomo;
|