@aranova/tracking-next 0.17.0 → 0.17.1
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/README.md +35 -0
- package/dist/index.d.mts +38 -3
- package/dist/index.d.ts +38 -3
- package/dist/index.js +104 -43
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +104 -43
- package/dist/index.mjs.map +1 -1
- package/dist/middleware.js +8 -4
- package/dist/middleware.js.map +1 -1
- package/dist/middleware.mjs +8 -4
- package/dist/middleware.mjs.map +1 -1
- package/dist/phone.js +45 -41
- package/dist/phone.js.map +1 -1
- package/dist/phone.mjs +45 -41
- package/dist/phone.mjs.map +1 -1
- package/dist/server.js +8 -4
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +8 -4
- package/dist/server.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -169,6 +169,41 @@ export function LeadForm() {
|
|
|
169
169
|
|
|
170
170
|
`fields[].value` can be any JSON value: string, number, boolean, null, array, or object. Only send reviewed, allowlisted, non-sensitive values; do not send names, emails, phone numbers entered by the visitor, addresses, payment data, medical details, passwords, file contents, or free-text messages.
|
|
171
171
|
|
|
172
|
+
### Phone clicks (`tel:` taps) — manual or auto-capture
|
|
173
|
+
|
|
174
|
+
Opt into **auto-capture** and every `tel:` link is tracked with no per-link code. Add
|
|
175
|
+
`autoCapture` to the `phone_click` registration — a single delegated click listener does the rest:
|
|
176
|
+
|
|
177
|
+
```tsx
|
|
178
|
+
manual: {
|
|
179
|
+
phone_click: { autoCapture: {} }, // default selector: a[href^="tel:"]
|
|
180
|
+
// or narrow it: { autoCapture: { selector: "a.call" } }
|
|
181
|
+
},
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
<a href="tel:+14165550199" data-aranova-section="header">
|
|
186
|
+
(416) 555-0199
|
|
187
|
+
</a>
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The number is read from the `href` (normalized to E.164); `section` comes from an optional
|
|
191
|
+
`data-aranova-section`. **Unlike `cta_click`, a `phone_click` also fires the Google Ads
|
|
192
|
+
conversion** for a linked phone-call goal (a `CLICK_TO_CALL` action) — auto-fired the moment the
|
|
193
|
+
tap is captured, so you never call `trackConversion` (firing needs the sales client wired with the
|
|
194
|
+
same config; see below).
|
|
195
|
+
|
|
196
|
+
Prefer to instrument links yourself? Fire it from a click handler — this fires the conversion the
|
|
197
|
+
same way:
|
|
198
|
+
|
|
199
|
+
```tsx
|
|
200
|
+
tracking.trackEvent("phone_click", {
|
|
201
|
+
phone_number: "+14165550199",
|
|
202
|
+
page: { path: window.location.pathname },
|
|
203
|
+
section: "header",
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
172
207
|
### CTA clicks — manual or auto-capture
|
|
173
208
|
|
|
174
209
|
Fire `cta_click` yourself for full control over the name:
|
package/dist/index.d.mts
CHANGED
|
@@ -436,9 +436,28 @@ type PhoneClickMetadata = z.infer<typeof phoneClickMetadataSchema>;
|
|
|
436
436
|
/**
|
|
437
437
|
* Registration config for `phone_click`.
|
|
438
438
|
*
|
|
439
|
-
*
|
|
439
|
+
* The event stays manually fireable; `autoCapture` additionally attaches a
|
|
440
|
+
* delegated click listener that fires it for any `tel:` link matching
|
|
441
|
+
* `selector` (default `a[href^="tel:"]`) — link your phone number, get the
|
|
442
|
+
* analytics event (and, for a linked phone-click goal, the conversion) for free.
|
|
440
443
|
*/
|
|
441
|
-
declare const phoneClickConfigSchema: z.ZodObject<{
|
|
444
|
+
declare const phoneClickConfigSchema: z.ZodObject<{
|
|
445
|
+
autoCapture: z.ZodOptional<z.ZodObject<{
|
|
446
|
+
selector: z.ZodOptional<z.ZodString>;
|
|
447
|
+
}, "strict", z.ZodTypeAny, {
|
|
448
|
+
selector?: string | undefined;
|
|
449
|
+
}, {
|
|
450
|
+
selector?: string | undefined;
|
|
451
|
+
}>>;
|
|
452
|
+
}, "strict", z.ZodTypeAny, {
|
|
453
|
+
autoCapture?: {
|
|
454
|
+
selector?: string | undefined;
|
|
455
|
+
} | undefined;
|
|
456
|
+
}, {
|
|
457
|
+
autoCapture?: {
|
|
458
|
+
selector?: string | undefined;
|
|
459
|
+
} | undefined;
|
|
460
|
+
}>;
|
|
442
461
|
type PhoneClickConfig = z.infer<typeof phoneClickConfigSchema>;
|
|
443
462
|
|
|
444
463
|
/**
|
|
@@ -994,7 +1013,23 @@ declare const EVENT_REGISTRY: {
|
|
|
994
1013
|
phone_number: string;
|
|
995
1014
|
section?: string | null | undefined;
|
|
996
1015
|
}>;
|
|
997
|
-
readonly configSchema: z.ZodObject<{
|
|
1016
|
+
readonly configSchema: z.ZodObject<{
|
|
1017
|
+
autoCapture: z.ZodOptional<z.ZodObject<{
|
|
1018
|
+
selector: z.ZodOptional<z.ZodString>;
|
|
1019
|
+
}, "strict", z.ZodTypeAny, {
|
|
1020
|
+
selector?: string | undefined;
|
|
1021
|
+
}, {
|
|
1022
|
+
selector?: string | undefined;
|
|
1023
|
+
}>>;
|
|
1024
|
+
}, "strict", z.ZodTypeAny, {
|
|
1025
|
+
autoCapture?: {
|
|
1026
|
+
selector?: string | undefined;
|
|
1027
|
+
} | undefined;
|
|
1028
|
+
}, {
|
|
1029
|
+
autoCapture?: {
|
|
1030
|
+
selector?: string | undefined;
|
|
1031
|
+
} | undefined;
|
|
1032
|
+
}>;
|
|
998
1033
|
};
|
|
999
1034
|
readonly cta_click: {
|
|
1000
1035
|
readonly kind: "manual";
|
package/dist/index.d.ts
CHANGED
|
@@ -436,9 +436,28 @@ type PhoneClickMetadata = z.infer<typeof phoneClickMetadataSchema>;
|
|
|
436
436
|
/**
|
|
437
437
|
* Registration config for `phone_click`.
|
|
438
438
|
*
|
|
439
|
-
*
|
|
439
|
+
* The event stays manually fireable; `autoCapture` additionally attaches a
|
|
440
|
+
* delegated click listener that fires it for any `tel:` link matching
|
|
441
|
+
* `selector` (default `a[href^="tel:"]`) — link your phone number, get the
|
|
442
|
+
* analytics event (and, for a linked phone-click goal, the conversion) for free.
|
|
440
443
|
*/
|
|
441
|
-
declare const phoneClickConfigSchema: z.ZodObject<{
|
|
444
|
+
declare const phoneClickConfigSchema: z.ZodObject<{
|
|
445
|
+
autoCapture: z.ZodOptional<z.ZodObject<{
|
|
446
|
+
selector: z.ZodOptional<z.ZodString>;
|
|
447
|
+
}, "strict", z.ZodTypeAny, {
|
|
448
|
+
selector?: string | undefined;
|
|
449
|
+
}, {
|
|
450
|
+
selector?: string | undefined;
|
|
451
|
+
}>>;
|
|
452
|
+
}, "strict", z.ZodTypeAny, {
|
|
453
|
+
autoCapture?: {
|
|
454
|
+
selector?: string | undefined;
|
|
455
|
+
} | undefined;
|
|
456
|
+
}, {
|
|
457
|
+
autoCapture?: {
|
|
458
|
+
selector?: string | undefined;
|
|
459
|
+
} | undefined;
|
|
460
|
+
}>;
|
|
442
461
|
type PhoneClickConfig = z.infer<typeof phoneClickConfigSchema>;
|
|
443
462
|
|
|
444
463
|
/**
|
|
@@ -994,7 +1013,23 @@ declare const EVENT_REGISTRY: {
|
|
|
994
1013
|
phone_number: string;
|
|
995
1014
|
section?: string | null | undefined;
|
|
996
1015
|
}>;
|
|
997
|
-
readonly configSchema: z.ZodObject<{
|
|
1016
|
+
readonly configSchema: z.ZodObject<{
|
|
1017
|
+
autoCapture: z.ZodOptional<z.ZodObject<{
|
|
1018
|
+
selector: z.ZodOptional<z.ZodString>;
|
|
1019
|
+
}, "strict", z.ZodTypeAny, {
|
|
1020
|
+
selector?: string | undefined;
|
|
1021
|
+
}, {
|
|
1022
|
+
selector?: string | undefined;
|
|
1023
|
+
}>>;
|
|
1024
|
+
}, "strict", z.ZodTypeAny, {
|
|
1025
|
+
autoCapture?: {
|
|
1026
|
+
selector?: string | undefined;
|
|
1027
|
+
} | undefined;
|
|
1028
|
+
}, {
|
|
1029
|
+
autoCapture?: {
|
|
1030
|
+
selector?: string | undefined;
|
|
1031
|
+
} | undefined;
|
|
1032
|
+
}>;
|
|
998
1033
|
};
|
|
999
1034
|
readonly cta_click: {
|
|
1000
1035
|
readonly kind: "manual";
|
package/dist/index.js
CHANGED
|
@@ -784,8 +784,8 @@ function thresholdMet(goal, eventType, metadata) {
|
|
|
784
784
|
return typeof metadata.page_name === "string" && metadata.page_name === t.page_name;
|
|
785
785
|
case "page_view":
|
|
786
786
|
case "form_start":
|
|
787
|
+
case "phone_click":
|
|
787
788
|
return true;
|
|
788
|
-
// no threshold — fire whenever the detector emits
|
|
789
789
|
default:
|
|
790
790
|
return false;
|
|
791
791
|
}
|
|
@@ -1406,7 +1406,11 @@ var phoneClickMetadataSchema = import_zod8.z.object({
|
|
|
1406
1406
|
}).strict(),
|
|
1407
1407
|
section: import_zod8.z.string().nullable().optional()
|
|
1408
1408
|
}).strict();
|
|
1409
|
-
var phoneClickConfigSchema = import_zod8.z.object({
|
|
1409
|
+
var phoneClickConfigSchema = import_zod8.z.object({
|
|
1410
|
+
autoCapture: import_zod8.z.object({
|
|
1411
|
+
selector: import_zod8.z.string().optional()
|
|
1412
|
+
}).strict().optional()
|
|
1413
|
+
}).strict();
|
|
1410
1414
|
|
|
1411
1415
|
// ../tracking-core/src/events/scroll-depth.ts
|
|
1412
1416
|
var import_zod9 = require("zod");
|
|
@@ -1907,6 +1911,99 @@ function attachCtaClickCapture(client, config) {
|
|
|
1907
1911
|
};
|
|
1908
1912
|
}
|
|
1909
1913
|
|
|
1914
|
+
// ../tracking-core/src/phone.ts
|
|
1915
|
+
var import_libphonenumber_js = require("libphonenumber-js");
|
|
1916
|
+
var DEFAULT_PHONE_COUNTRY = "CA";
|
|
1917
|
+
function parsePhone(raw, country) {
|
|
1918
|
+
const region = country ?? DEFAULT_PHONE_COUNTRY;
|
|
1919
|
+
const parsed = (0, import_libphonenumber_js.parsePhoneNumberFromString)(raw ?? "", region);
|
|
1920
|
+
if (!parsed) {
|
|
1921
|
+
return { e164: null, national: "", international: "", country: region, isValid: false };
|
|
1922
|
+
}
|
|
1923
|
+
const isValid = parsed.isValid();
|
|
1924
|
+
return {
|
|
1925
|
+
// E.164 is only surfaced for a *valid* number — a possible-but-invalid input
|
|
1926
|
+
// (e.g. too few digits) still parses but must not be transmitted.
|
|
1927
|
+
e164: isValid ? parsed.number : null,
|
|
1928
|
+
national: parsed.formatNational(),
|
|
1929
|
+
international: parsed.formatInternational(),
|
|
1930
|
+
country: parsed.country ?? region,
|
|
1931
|
+
isValid
|
|
1932
|
+
};
|
|
1933
|
+
}
|
|
1934
|
+
function toE164(raw, country) {
|
|
1935
|
+
return parsePhone(raw, country).e164;
|
|
1936
|
+
}
|
|
1937
|
+
function formatPhone(value, format = "national", country) {
|
|
1938
|
+
const parsed = parsePhone(value, country);
|
|
1939
|
+
if (typeof format === "function") return format(parsed);
|
|
1940
|
+
switch (format) {
|
|
1941
|
+
case "international":
|
|
1942
|
+
return parsed.international || value;
|
|
1943
|
+
case "e164":
|
|
1944
|
+
return parsed.e164 ?? value;
|
|
1945
|
+
case "national":
|
|
1946
|
+
default:
|
|
1947
|
+
return parsed.national || value;
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
function formatPhoneAsTyped(raw, country) {
|
|
1951
|
+
return new import_libphonenumber_js.AsYouType(country ?? DEFAULT_PHONE_COUNTRY).input(raw ?? "");
|
|
1952
|
+
}
|
|
1953
|
+
|
|
1954
|
+
// ../tracking-core/src/triggers/phone-click-capture.ts
|
|
1955
|
+
var DEFAULT_TEL_SELECTOR = 'a[href^="tel:"]';
|
|
1956
|
+
function safeDecodeURIComponent(value) {
|
|
1957
|
+
try {
|
|
1958
|
+
return decodeURIComponent(value);
|
|
1959
|
+
} catch {
|
|
1960
|
+
return value;
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
function resolvePhoneNumber(el) {
|
|
1964
|
+
const href = el instanceof HTMLAnchorElement ? el.href : el.getAttribute("href") ?? "";
|
|
1965
|
+
const raw = safeDecodeURIComponent(href.replace(/^tel:/i, "").split(";")[0]).trim();
|
|
1966
|
+
return toE164(raw) ?? raw;
|
|
1967
|
+
}
|
|
1968
|
+
function attachPhoneClickCapture(client, config) {
|
|
1969
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
1970
|
+
return () => {
|
|
1971
|
+
};
|
|
1972
|
+
}
|
|
1973
|
+
const autoCapture = config.autoCapture;
|
|
1974
|
+
if (!autoCapture) {
|
|
1975
|
+
return () => {
|
|
1976
|
+
};
|
|
1977
|
+
}
|
|
1978
|
+
const selector = autoCapture.selector ?? DEFAULT_TEL_SELECTOR;
|
|
1979
|
+
function onClick(event) {
|
|
1980
|
+
const target = event.target;
|
|
1981
|
+
if (!(target instanceof Element)) return;
|
|
1982
|
+
let matched = null;
|
|
1983
|
+
try {
|
|
1984
|
+
matched = target.closest(selector);
|
|
1985
|
+
} catch {
|
|
1986
|
+
return;
|
|
1987
|
+
}
|
|
1988
|
+
if (matched === null) return;
|
|
1989
|
+
const metadata = {
|
|
1990
|
+
phone_number: resolvePhoneNumber(matched),
|
|
1991
|
+
page: { path: window.location.pathname },
|
|
1992
|
+
section: matched.getAttribute("data-aranova-section")
|
|
1993
|
+
};
|
|
1994
|
+
client.trackEvent({
|
|
1995
|
+
eventType: "phone_click",
|
|
1996
|
+
metadata,
|
|
1997
|
+
pageUrl: window.location.href,
|
|
1998
|
+
occurredAt: null
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
2001
|
+
document.addEventListener("click", onClick, true);
|
|
2002
|
+
return () => {
|
|
2003
|
+
document.removeEventListener("click", onClick, true);
|
|
2004
|
+
};
|
|
2005
|
+
}
|
|
2006
|
+
|
|
1910
2007
|
// ../tracking-core/src/resources/sales/errors.ts
|
|
1911
2008
|
var AranovaApiError = class extends Error {
|
|
1912
2009
|
constructor(message, options) {
|
|
@@ -2234,46 +2331,6 @@ async function fetchServices(config) {
|
|
|
2234
2331
|
return salesRequest(config, "GET", "/services");
|
|
2235
2332
|
}
|
|
2236
2333
|
|
|
2237
|
-
// ../tracking-core/src/phone.ts
|
|
2238
|
-
var import_libphonenumber_js = require("libphonenumber-js");
|
|
2239
|
-
var DEFAULT_PHONE_COUNTRY = "CA";
|
|
2240
|
-
function parsePhone(raw, country) {
|
|
2241
|
-
const region = country ?? DEFAULT_PHONE_COUNTRY;
|
|
2242
|
-
const parsed = (0, import_libphonenumber_js.parsePhoneNumberFromString)(raw ?? "", region);
|
|
2243
|
-
if (!parsed) {
|
|
2244
|
-
return { e164: null, national: "", international: "", country: region, isValid: false };
|
|
2245
|
-
}
|
|
2246
|
-
const isValid = parsed.isValid();
|
|
2247
|
-
return {
|
|
2248
|
-
// E.164 is only surfaced for a *valid* number — a possible-but-invalid input
|
|
2249
|
-
// (e.g. too few digits) still parses but must not be transmitted.
|
|
2250
|
-
e164: isValid ? parsed.number : null,
|
|
2251
|
-
national: parsed.formatNational(),
|
|
2252
|
-
international: parsed.formatInternational(),
|
|
2253
|
-
country: parsed.country ?? region,
|
|
2254
|
-
isValid
|
|
2255
|
-
};
|
|
2256
|
-
}
|
|
2257
|
-
function toE164(raw, country) {
|
|
2258
|
-
return parsePhone(raw, country).e164;
|
|
2259
|
-
}
|
|
2260
|
-
function formatPhone(value, format = "national", country) {
|
|
2261
|
-
const parsed = parsePhone(value, country);
|
|
2262
|
-
if (typeof format === "function") return format(parsed);
|
|
2263
|
-
switch (format) {
|
|
2264
|
-
case "international":
|
|
2265
|
-
return parsed.international || value;
|
|
2266
|
-
case "e164":
|
|
2267
|
-
return parsed.e164 ?? value;
|
|
2268
|
-
case "national":
|
|
2269
|
-
default:
|
|
2270
|
-
return parsed.national || value;
|
|
2271
|
-
}
|
|
2272
|
-
}
|
|
2273
|
-
function formatPhoneAsTyped(raw, country) {
|
|
2274
|
-
return new import_libphonenumber_js.AsYouType(country ?? DEFAULT_PHONE_COUNTRY).input(raw ?? "");
|
|
2275
|
-
}
|
|
2276
|
-
|
|
2277
2334
|
// ../tracking-core/src/phone-field.ts
|
|
2278
2335
|
function phoneField(name, raw, country) {
|
|
2279
2336
|
return { name, type: "phone", value: toE164(raw, country) };
|
|
@@ -2610,7 +2667,7 @@ function GoogleAdsTracking(props) {
|
|
|
2610
2667
|
var import_navigation = require("next/navigation");
|
|
2611
2668
|
|
|
2612
2669
|
// package.json
|
|
2613
|
-
var version = "0.17.
|
|
2670
|
+
var version = "0.17.1";
|
|
2614
2671
|
|
|
2615
2672
|
// src/factory.tsx
|
|
2616
2673
|
var import_react4 = require("react");
|
|
@@ -2911,6 +2968,10 @@ function createTracking(options) {
|
|
|
2911
2968
|
if (ctaClick) {
|
|
2912
2969
|
detachers.push(attachCtaClickCapture(detectorClient, ctaClick));
|
|
2913
2970
|
}
|
|
2971
|
+
const phoneClick = triggers.manual?.phone_click;
|
|
2972
|
+
if (phoneClick) {
|
|
2973
|
+
detachers.push(attachPhoneClickCapture(detectorClient, phoneClick));
|
|
2974
|
+
}
|
|
2914
2975
|
return () => {
|
|
2915
2976
|
for (let i = detachers.length - 1; i >= 0; i--) {
|
|
2916
2977
|
detachers[i]();
|