@rebilly/lead-source-tracker 8.28.3 → 8.29.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/README.md +22 -0
- package/dist/build.js +1 -1
- package/package.json +8 -5
package/README.md
CHANGED
|
@@ -29,6 +29,12 @@ You can provide additional cookie attribues using the second argument:
|
|
|
29
29
|
|
|
30
30
|
See https://github.com/js-cookie/js-cookie#cookie-attributes for the full list of supported attributes.
|
|
31
31
|
|
|
32
|
+
The second argument also accepts one non-cookie option, `classifyReferrer`:
|
|
33
|
+
|
|
34
|
+
`RebillyLeadSource.collect(window, { domain: 'rebilly.com', secure: true, classifyReferrer: true })`
|
|
35
|
+
|
|
36
|
+
See [Referrer classification](#referrer-classification-opt-in) below.
|
|
37
|
+
|
|
32
38
|
4. Call `collect` again when submitting lead source information to the Rebilly API. The function returns all saved cookie data as an object.
|
|
33
39
|
|
|
34
40
|
Example:
|
|
@@ -74,6 +80,22 @@ Some data is automatically inferred by `RebillyLeadSource` when data collection
|
|
|
74
80
|
2. `document.location`
|
|
75
81
|
- URL is parsed and saved to leadSource.path
|
|
76
82
|
|
|
83
|
+
### Referrer classification (opt-in)
|
|
84
|
+
|
|
85
|
+
Most visitors arrive without UTM parameters, so `source` and `medium` stay empty and reports show these leads as "direct / none".
|
|
86
|
+
When you pass `classifyReferrer: true` to `collect`, the tracker maps well-known referrer hostnames to `source` and `medium` values.
|
|
87
|
+
|
|
88
|
+
Rules:
|
|
89
|
+
|
|
90
|
+
- Classification fills a field only when nothing else set it. UTM parameters, `#rls-token` attributes, and previously saved cookie values always win.
|
|
91
|
+
- Classification uses the saved first-touch referrer, so a later visit does not change an existing attribution.
|
|
92
|
+
- Unknown referrers stay unclassified. The tracker never guesses.
|
|
93
|
+
- The option is off by default. Existing integrations see no behavior change.
|
|
94
|
+
|
|
95
|
+
Recognized hostnames include search engines (`google`, `bing`, `duckduckgo` → `organic-search`), developer communities (`github`, `stack-overflow`, `reddit`, `hacker-news`, `dev-to` → `community`), social networks (`linkedin`, `x-twitter`, `youtube`, `bluesky`, `facebook`, `instagram`, `tiktok`, `snapchat`, `pinterest`, `threads` → `social`), webmail (`gmail`, `outlook`, `yahoo-mail` → `email`), and AI assistants (`chatgpt`, `perplexity`, `claude`, `gemini`, `copilot` → `ai-assistant`).
|
|
96
|
+
For Google, only search hosts (`google.<tld>`, `www.google.<tld>`) classify as organic search — other Google properties such as `docs.google.com` or `accounts.google.com` stay unclassified.
|
|
97
|
+
See `src/referrerClassification.ts` for the full table.
|
|
98
|
+
|
|
77
99
|
### Query params
|
|
78
100
|
|
|
79
101
|
| key | example | purpose |
|
package/dist/build.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(l,m){typeof exports=="object"&&typeof module<"u"?module.exports=m():typeof define=="function"&&define.amd?define(m):(l=typeof globalThis<"u"?globalThis:l||self,l.RebillyLeadSource=m())})(this,(function(){"use strict";/*! js-cookie v3.0.8 | MIT */function l(e){for(var o=1;o<arguments.length;o++){var i=arguments[o];for(var n in i)n!=="__proto__"&&(e[n]=i[n])}return e}var m={read:function(e){return e[0]==='"'&&(e=e.slice(1,-1)),e.replace(/(%[\dA-F]{2})+/gi,decodeURIComponent)},write:function(e){return encodeURIComponent(e).replace(/%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,decodeURIComponent)}};function g(e,o){function i(r,u,c){if(!(typeof document>"u")){c=l({},o,c),typeof c.expires=="number"&&(c.expires=new Date(Date.now()+c.expires*864e5)),c.expires&&(c.expires=c.expires.toUTCString()),r=encodeURIComponent(r).replace(/%(2[346B]|5E|60|7C)/g,decodeURIComponent).replace(/[()]/g,escape);var s="";for(var a in c)c[a]&&(s+="; "+a,c[a]!==!0&&(s+="="+c[a].split(";")[0]));return document.cookie=r+"="+e.write(u,r)+s}}function n(r){if(!(typeof document>"u"||arguments.length&&!r)){for(var u=document.cookie?document.cookie.split("; "):[],c={},s=0;s<u.length;s++){var a=u[s].split("="),d=a.slice(1).join("=");try{var p=decodeURIComponent(a[0]);if(p in c||(c[p]=e.read(d,p)),r===p)break}catch{}}return r?c[r]:c}}return Object.create({set:i,get:n,remove:function(r,u){i(r,"",l({},u,{expires:-1}))},withAttributes:function(r){return g(this.converter,l({},this.attributes,r))},withConverter:function(r){return g(l({},this.converter,r),this.attributes)}},{attributes:{value:Object.freeze(o)},converter:{value:Object.freeze(e)}})}var h=g(m,{path:"/"});function t(e,o,i){return{test:n=>n===e||n.endsWith(`.${e}`),source:o,medium:i}}const S=[t("chatgpt.com","chatgpt","ai-assistant"),t("chat.openai.com","chatgpt","ai-assistant"),t("perplexity.ai","perplexity","ai-assistant"),t("claude.ai","claude","ai-assistant"),t("gemini.google.com","gemini","ai-assistant"),t("copilot.microsoft.com","copilot","ai-assistant"),t("mail.google.com","gmail","email"),t("outlook.live.com","outlook","email"),t("outlook.office.com","outlook","email"),t("mail.yahoo.com","yahoo-mail","email"),{test:e=>/^(www\.)?google\.[a-z]{2,3}(\.[a-z]{2})?$/.test(e),source:"google",medium:"organic-search"},t("bing.com","bing","organic-search"),t("duckduckgo.com","duckduckgo","organic-search"),t("github.com","github","community"),t("stackoverflow.com","stack-overflow","community"),t("reddit.com","reddit","community"),t("news.ycombinator.com","hacker-news","community"),t("dev.to","dev-to","community"),t("linkedin.com","linkedin","social"),t("lnkd.in","linkedin","social"),t("twitter.com","x-twitter","social"),t("x.com","x-twitter","social"),t("t.co","x-twitter","social"),t("youtube.com","youtube","social"),t("youtu.be","youtube","social"),t("bsky.app","bluesky","social"),t("facebook.com","facebook","social"),t("fb.com","facebook","social"),t("fb.me","facebook","social"),t("instagram.com","instagram","social"),t("tiktok.com","tiktok","social"),t("snapchat.com","snapchat","social"),t("pinterest.com","pinterest","social"),t("pin.it","pinterest","social"),t("threads.net","threads","social"),t("threads.com","threads","social")];function D(e){if(!e)return null;let o;try{o=new URL(e).hostname.toLowerCase()}catch{return null}const i=S.find(n=>n.test(o));return i?{source:i.source,medium:i.medium}:null}const k="rls",y={expires:45},U=["source","medium","campaign","term","content","affiliate","subAffiliate","clickId","salesAgent"],C=["path","referrer"],w=[...C,...U];function x(e,o){const{classifyReferrer:i=!1,...n}=o||{},{document:r}=e;if(I(e))return f({dnt:!0}),{};const u={path:r.location.host+r.location.pathname,...L(r),...F(r),...T(e)},{leadSource:c}=O({leadSource:u},n,i);return c||{}}function f({dnt:e=!1}){const o={dnt:e};return e?R(o):h.remove(k,y),o}function O(e,o,i=!1){const n=b();if(n.dnt||e.dnt)return f({dnt:!0});f({dnt:!1});const r=n.leadSource||{},u=C.reduce((s,a)=>{const d=r[a];return d&&(s[a]=d),s},{}),c={leadSource:{...r,...v(e.leadSource),...u}};if(i){const s=c.leadSource;if(!s.source||!s.medium){const a=D(s.referrer);a&&(s.source=s.source||a.source,s.medium=s.medium||a.medium)}}return Object.assign(y,o||{}),R(c),c}function b(){const e=h.get(k);if(!e)return{};try{const o=JSON.parse(e);return o.dnt?{dnt:!0}:o}catch{return{}}}function R(e){h.set(k,JSON.stringify(e),y)}function L(e){const{dataset:o}=e.querySelector("#rls-token")||{};return v(o)}function T(e){const o=new URLSearchParams(e.location.search),i=w.reduce((n,r)=>(n[r]=o.get(`utm_${r}`)||o.get(r)||o.get(`utm_${r.toLowerCase()}`)||o.get(r.toLowerCase())||null,n),{});return v(i)}function F(e){try{return new URL(e.referrer).hostname!==e.location.hostname?{referrer:e.referrer}:{}}catch{return{}}}function I(e){const i=new URLSearchParams(e.location.search).has("dnt"),{dnt:n}=b(),r=_(e);return i||r||n}function _(e){const{navigator:o}=e;if(e.doNotTrack||o.doNotTrack||o.msDoNotTrack)return e.doNotTrack=="1"||o.doNotTrack=="yes"||o.doNotTrack=="1"||o.msDoNotTrack=="1"}function v(e={}){return w.reduce((o,i)=>{const n=(e[i]||"").trim();return n&&(o[i]=n),o},{})}return typeof window<"u"&&document.addEventListener("DOMContentLoaded",()=>{x(window)}),{collect:x,clear:f}}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebilly/lead-source-tracker",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.29.0",
|
|
4
4
|
"description": "Simple library which is used to collect and store lead source information into a cookie",
|
|
5
5
|
"author": "Rebilly",
|
|
6
6
|
"repository": "https://github.com/Rebilly/rebilly",
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
],
|
|
11
11
|
"scripts": {
|
|
12
12
|
"serve": "pnpm build && node ./dev/server.js",
|
|
13
|
-
"build": "vite build"
|
|
13
|
+
"build": "vite build",
|
|
14
|
+
"test:unit": "vitest run",
|
|
15
|
+
"test:unit:watch": "vitest"
|
|
14
16
|
},
|
|
15
17
|
"browserslist": [
|
|
16
18
|
"> 1%",
|
|
@@ -19,10 +21,11 @@
|
|
|
19
21
|
"devDependencies": {
|
|
20
22
|
"@rebilly/eslint-config": "*",
|
|
21
23
|
"express": "^5.1.0",
|
|
22
|
-
"vite": "^
|
|
23
|
-
"vite-plugin-commonjs": "^0.10.4"
|
|
24
|
+
"vite": "^6.4.3",
|
|
25
|
+
"vite-plugin-commonjs": "^0.10.4",
|
|
26
|
+
"vitest": "^4.1.0"
|
|
24
27
|
},
|
|
25
28
|
"dependencies": {
|
|
26
|
-
"js-cookie": "^3.0.
|
|
29
|
+
"js-cookie": "^3.0.8"
|
|
27
30
|
}
|
|
28
31
|
}
|