Skill Tracer
Skills › Marketing Skills › conversion-tracking › thank-you-page.js

thank-you-page.js

85 lines · skills/conversion-tracking/assets/snippets/thank-you-page.js at 88c79f6

1/*! Thank-you page conversion detection (MIT)
2 * Detects: arrival on a confirmation page. Pushes dataLayer event: thank_you_page_view
3 * From the conversion-tracking skill in Marketing Skills */
4(function () {
5 if (window.__ctDetectThankYouPage) return;
6 window.__ctDetectThankYouPage = true;
7 window.dataLayer = window.dataLayer || [];
8
9 /* ---------------------------------------------------------------
10 EDIT THIS. Paths that mean "the conversion happened".
11 Matched against location.pathname, case-insensitively, as a
12 prefix. '/thank-you' matches '/thank-you' and '/thank-you/order/9'.
13 --------------------------------------------------------------- */
14 var THANK_YOU_PATHS = [
15 '/thank-you',
16 '/thanks',
17 '/confirmation',
18 '/success'
19 ];
21 // Set true only if your confirmation page is genuinely reachable more than
22 // once per conversion and you want every view counted. Leave false.
23 var COUNT_EVERY_VIEW = false;
25 var fired = {};
27 function matches(path) {
28 var p = String(path || '').toLowerCase();
29 for (var i = 0; i < THANK_YOU_PATHS.length; i++) {
30 var want = String(THANK_YOU_PATHS[i] || '').toLowerCase();
31 if (want && p.indexOf(want) === 0) return want;
32 }
33 return null;
34 }
36 function check() {
37 try {
38 var path = window.location.pathname;
39 var matched = matches(path);
40 if (!matched) return;
42 // A refresh or a back-button return to the confirmation page would
43 // otherwise count a second conversion for the same lead. Keyed on the
44 // full path so two different confirmations still both count.
45 if (!COUNT_EVERY_VIEW && fired[path]) return;
46 fired[path] = true;
48 window.dataLayer.push({
49 event: 'thank_you_page_view',
50 page_path: path,
51 matched_rule: matched
52 });
53 } catch (e) {
54 // Never throw back into the page.
55 }
56 }
58 // Single-page apps are the reason this is not just a one-shot call. A
59 // React, Vue or Next site changes the URL without a page load, so no
60 // pageview ever fires and a thank-you page TRIGGER silently counts zero.
61 // Wrapping history means we see those route changes too.
62 function wrapHistory(method) {
63 var original = window.history[method];
64 if (typeof original !== 'function') return;
65 window.history[method] = function () {
66 var result = original.apply(this, arguments);
67 try { setTimeout(check, 0); } catch (e) { /* ignore */ }
68 return result;
69 };
70 }
72 try {
73 wrapHistory('pushState');
74 wrapHistory('replaceState');
75 window.addEventListener('popstate', function () { setTimeout(check, 0); });
76 } catch (e) {
77 // History API unavailable — the initial check below still runs.
78 }
80 if (document.readyState === 'loading') {
81 document.addEventListener('DOMContentLoaded', check);
82 } else {
83 check();
84 }
85})();