Skip to content

Commit 5682a33

Browse files
authored
Improved referrer parser matching on direct (internal) traffic (#536)
ref https://linear.app/ghost/issue/PROD-1960/ Updated referrer parsing matching on site domain such that internal traffic is more consistently identified as 'direct'/internal, rather than treating it as a referrer w/ a source.
1 parent d45b0cd commit 5682a33

File tree

2 files changed

+66
-1
lines changed

2 files changed

+66
-1
lines changed

packages/referrer-parser/lib/ReferrerParser.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,12 +186,29 @@ export class ReferrerParser {
186186
return false;
187187
}
188188

189-
if (this.siteUrl.hostname === url.hostname) {
189+
// Handle subdomain variations (www.example.com vs example.com)
190+
const siteHostname = this.siteUrl.hostname;
191+
const urlHostname = url.hostname;
192+
193+
// Check for exact match first
194+
if (siteHostname === urlHostname) {
190195
if (url.pathname.startsWith(this.siteUrl.pathname)) {
191196
return true;
192197
}
193198
return false;
194199
}
200+
201+
// Check for www subdomain variations
202+
const siteWithoutWww = siteHostname.replace(/^www\./, '');
203+
const urlWithoutWww = urlHostname.replace(/^www\./, '');
204+
205+
if (siteWithoutWww === urlWithoutWww) {
206+
if (url.pathname.startsWith(this.siteUrl.pathname)) {
207+
return true;
208+
}
209+
return false;
210+
}
211+
195212
return false;
196213
} catch (e) {
197214
return false;

packages/referrer-parser/test/ReferrerParser.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,20 @@ describe('ReferrerParser', () => {
227227
assertPropertyEquals(result, 'referrerMedium', null);
228228
assertPropertyEquals(result, 'referrerUrl', null);
229229
});
230+
231+
it('identifies internal traffic for subdomain variations (regression test for levernews.com)', () => {
232+
// Test case: site configured as www.levernews.com, referrer is levernews.com
233+
// This should return null values (internal traffic) instead of showing levernews.com as referrerSource
234+
const leverParser = new ReferrerParser({
235+
siteUrl: 'https://www.levernews.com'
236+
});
237+
238+
const result = leverParser.parse('https://levernews.com/article');
239+
should.exist(result);
240+
assertPropertyEquals(result, 'referrerSource', null);
241+
assertPropertyEquals(result, 'referrerMedium', null);
242+
assertPropertyEquals(result, 'referrerUrl', null);
243+
});
230244
});
231245

232246
describe('getDataFromUrl', () => {
@@ -344,6 +358,40 @@ describe('ReferrerParser', () => {
344358
const result = parser.isSiteDomain({} as URL);
345359
should.equal(result, false);
346360
});
361+
362+
it('handles www subdomain variations', () => {
363+
// Test www.example.com configured, levernews.com referrer
364+
const parser1 = new ReferrerParser({
365+
siteUrl: 'https://www.levernews.com'
366+
});
367+
const url1 = new URL('https://levernews.com/article');
368+
const result1 = parser1.isSiteDomain(url1);
369+
should.equal(result1, true);
370+
371+
// Test levernews.com configured, www.levernews.com referrer
372+
const parser2 = new ReferrerParser({
373+
siteUrl: 'https://levernews.com'
374+
});
375+
const url2 = new URL('https://www.levernews.com/article');
376+
const result2 = parser2.isSiteDomain(url2);
377+
should.equal(result2, true);
378+
379+
// Test both with www
380+
const parser3 = new ReferrerParser({
381+
siteUrl: 'https://www.levernews.com'
382+
});
383+
const url3 = new URL('https://www.levernews.com/article');
384+
const result3 = parser3.isSiteDomain(url3);
385+
should.equal(result3, true);
386+
387+
// Test both without www
388+
const parser4 = new ReferrerParser({
389+
siteUrl: 'https://levernews.com'
390+
});
391+
const url4 = new URL('https://levernews.com/article');
392+
const result4 = parser4.isSiteDomain(url4);
393+
should.equal(result4, true);
394+
});
347395
});
348396

349397
describe('isGhostNewsletter', () => {

0 commit comments

Comments
 (0)