@rebilly/lead-source-tracker 8.29.0 → 8.31.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 +28 -4
- package/dist/build.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,11 +29,11 @@ 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
|
|
32
|
+
The second argument also accepts two non-cookie options, `classifyReferrer` and `visitorId`:
|
|
33
33
|
|
|
34
|
-
`RebillyLeadSource.collect(window, { domain: 'rebilly.com', secure: true, classifyReferrer: true })`
|
|
34
|
+
`RebillyLeadSource.collect(window, { domain: 'rebilly.com', secure: true, classifyReferrer: true, visitorId: true })`
|
|
35
35
|
|
|
36
|
-
See [Referrer classification](#referrer-classification-opt-in) below.
|
|
36
|
+
See [Referrer classification](#referrer-classification-opt-in) and [Visitor id](#visitor-id-opt-in) below.
|
|
37
37
|
|
|
38
38
|
4. Call `collect` again when submitting lead source information to the Rebilly API. The function returns all saved cookie data as an object.
|
|
39
39
|
|
|
@@ -96,6 +96,28 @@ Recognized hostnames include search engines (`google`, `bing`, `duckduckgo` →
|
|
|
96
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
97
|
See `src/referrerClassification.ts` for the full table.
|
|
98
98
|
|
|
99
|
+
### Visitor id (opt-in)
|
|
100
|
+
|
|
101
|
+
The tracker does not store a browser identifier unless you ask for one.
|
|
102
|
+
When you pass `visitorId: true` to `collect`, it writes a UUIDv7 ([RFC 9562](https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7)) to `leadSource.clickId` and keeps that value for the cookie lifetime.
|
|
103
|
+
|
|
104
|
+
Rules:
|
|
105
|
+
|
|
106
|
+
- The id is generated only when `leadSource.clickId` is empty. A later visit, `utm_*` parameters, and ad click parameters such as `gclid` do not change it.
|
|
107
|
+
- Incoming `clickId` / `clickid` query params and `#rls-token` `data-click-id` are ignored while the option is on. The cookie holds a generated visitor id, not an ad click id.
|
|
108
|
+
- An existing non-empty `clickId` (including an old ad id) is left as-is.
|
|
109
|
+
- The option is off by default. Existing integrations that use `clickId` for ad attribution see no behavior change.
|
|
110
|
+
- Generation needs `crypto.getRandomValues`. There is no `Math.random()` fallback. If `crypto.getRandomValues` is missing, `clickId` stays unset and the rest of collect still runs.
|
|
111
|
+
- Pass `visitorId: true` on **every** `collect` call. An option-off `collect` (including the package's `DOMContentLoaded` auto-collect) treats `clickId` as updatable again and can overwrite a generated id from `?clickId=` or `#rls-token` `data-click-id`.
|
|
112
|
+
|
|
113
|
+
Read the id without parsing the cookie:
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
const visitorId = RebillyLeadSource.getVisitorId();
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`getVisitorId()` only reads the cookie. It does not generate or write. Call `collect(..., { visitorId: true })` first if you need the id to exist.
|
|
120
|
+
|
|
99
121
|
### Query params
|
|
100
122
|
|
|
101
123
|
| key | example | purpose |
|
|
@@ -108,7 +130,7 @@ See `src/referrerClassification.ts` for the full table.
|
|
|
108
130
|
| `content` | `?content=example` | Change the leadSource `content` field |
|
|
109
131
|
| `affiliate` | `?affiliate=example` | Change the leadSource `affiliate` field |
|
|
110
132
|
| `subAffiliate` or `subaffiliate` | `?subAffiliate=example` | Change the leadSource `subAffiliate` field |
|
|
111
|
-
| `clickId` or `clickid` | `?clickId=example` | Change the leadSource `clickId` field
|
|
133
|
+
| `clickId` or `clickid` | `?clickId=example` | Change the leadSource `clickId` field. Ignored when `visitorId: true` |
|
|
112
134
|
| `salesAgent` or `salesagent` | `?salesAgent=example` | Change the leadSource `salesAgent` field |
|
|
113
135
|
| `path` | `?path=example` | Change the leadSource `path` field. This cannot be updated once it is set the first time |
|
|
114
136
|
| `referrer` | `?referrer=example` | Change the leadSource `referrer` field. This cannot be updated once it is set the first time |
|
|
@@ -149,6 +171,8 @@ The following fields will not be updated after the first time they are saved to
|
|
|
149
171
|
- path
|
|
150
172
|
- referrer
|
|
151
173
|
|
|
174
|
+
When `visitorId: true`, `clickId` is also left unchanged after it is first saved (generated UUIDv7, or whatever value was already in the cookie).
|
|
175
|
+
|
|
152
176
|
The only exception is if the cookie expires (after 45 days) or is cleared by the user.
|
|
153
177
|
|
|
154
178
|
All other fields will update the saved cookie whenever `collect` is called.
|
package/dist/build.js
CHANGED
|
@@ -1 +1 @@
|
|
|
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
|
|
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 r=arguments[o];for(var c in r)c!=="__proto__"&&(e[c]=r[c])}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 h(e,o){function r(n,u,i){if(!(typeof document>"u")){i=l({},o,i),typeof i.expires=="number"&&(i.expires=new Date(Date.now()+i.expires*864e5)),i.expires&&(i.expires=i.expires.toUTCString()),n=encodeURIComponent(n).replace(/%(2[346B]|5E|60|7C)/g,decodeURIComponent).replace(/[()]/g,escape);var a="";for(var s in i)i[s]&&(a+="; "+s,i[s]!==!0&&(a+="="+i[s].split(";")[0]));return document.cookie=n+"="+e.write(u,n)+a}}function c(n){if(!(typeof document>"u"||arguments.length&&!n)){for(var u=document.cookie?document.cookie.split("; "):[],i={},a=0;a<u.length;a++){var s=u[a].split("="),f=s.slice(1).join("=");try{var d=decodeURIComponent(s[0]);if(d in i||(i[d]=e.read(f,d)),n===d)break}catch{}}return n?i[n]:i}}return Object.create({set:r,get:c,remove:function(n,u){r(n,"",l({},u,{expires:-1}))},withAttributes:function(n){return h(this.converter,l({},this.attributes,n))},withConverter:function(n){return h(l({},this.converter,n),this.attributes)}},{attributes:{value:Object.freeze(o)},converter:{value:Object.freeze(e)}})}var g=h(m,{path:"/"});function t(e,o,r){return{test:c=>c===e||c.endsWith(`.${e}`),source:o,medium:r}}const b=[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 r=b.find(c=>c.test(o));return r?{source:r.source,medium:r.medium}:null}function I(e){return[...e].map(o=>o.toString(16).padStart(2,"0")).join("")}function U(){if(typeof crypto>"u"||typeof crypto.getRandomValues!="function")return null;const e=new Uint8Array(16);crypto.getRandomValues(e);const o=Date.now();e[0]=Math.floor(o/1099511627776)&255,e[1]=Math.floor(o/4294967296)&255,e[2]=Math.floor(o/16777216)&255,e[3]=Math.floor(o/65536)&255,e[4]=Math.floor(o/256)&255,e[5]=o&255,e[6]=e[6]&15|112,e[8]=e[8]&63|128;const r=I(e);return`${r.slice(0,8)}-${r.slice(8,12)}-${r.slice(12,16)}-${r.slice(16,20)}-${r.slice(20)}`}const k="rls",y={expires:45},O=["source","medium","campaign","term","content","affiliate","subAffiliate","clickId","salesAgent"],C=["path","referrer"],S=[...C,...O];function x(e,o){const{classifyReferrer:r=!1,visitorId:c=!1,...n}=o||{},{document:u}=e;if($(e))return p({dnt:!0}),{};const i={path:u.location.host+u.location.pathname,...A(u),..._(u),...F(e)};c&&delete i.clickId;const{leadSource:a}=T({leadSource:i},n,r,c);return a||{}}function p({dnt:e=!1}){const o={dnt:e};return e?R(o):g.remove(k,y),o}function L(){var e;return(e=v().leadSource)==null?void 0:e.clickId}function T(e,o,r=!1,c=!1){const n=v();if(n.dnt||e.dnt)return p({dnt:!0});p({dnt:!1});const u=n.leadSource||{},i=C.reduce((s,f)=>{const d=u[f];return d&&(s[f]=d),s},{}),a={leadSource:{...u,...w(e.leadSource),...i}};if(r){const s=a.leadSource;if(!s.source||!s.medium){const f=D(s.referrer);f&&(s.source=s.source||f.source,s.medium=s.medium||f.medium)}}if(c&&!a.leadSource.clickId){const s=U();s&&(a.leadSource.clickId=s)}return Object.assign(y,o||{}),R(a),a}function v(){const e=g.get(k);if(!e)return{};try{const o=JSON.parse(e);return o.dnt?{dnt:!0}:o}catch{return{}}}function R(e){g.set(k,JSON.stringify(e),y)}function A(e){const{dataset:o}=e.querySelector("#rls-token")||{};return w(o)}function F(e){const o=new URLSearchParams(e.location.search),r=S.reduce((c,n)=>(c[n]=o.get(`utm_${n}`)||o.get(n)||o.get(`utm_${n.toLowerCase()}`)||o.get(n.toLowerCase())||null,c),{});return w(r)}function _(e){try{return new URL(e.referrer).hostname!==e.location.hostname?{referrer:e.referrer}:{}}catch{return{}}}function $(e){const r=new URLSearchParams(e.location.search).has("dnt"),{dnt:c}=v(),n=M(e);return r||n||c}function M(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 w(e={}){return S.reduce((o,r)=>{const c=(e[r]||"").trim();return c&&(o[r]=c),o},{})}return typeof window<"u"&&document.addEventListener("DOMContentLoaded",()=>{x(window)}),{collect:x,clear:p,getVisitorId:L}}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebilly/lead-source-tracker",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.31.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",
|