Skip to content

excludeReferrers blocks ALL campaign parameter tracking instead of just referrer attribution #1381

@tmchow

Description

@tmchow

Expected Behavior

When using the excludeReferrers configuration option in the Web Attribution Plugin, it should:

  • Exclude the specified referrer domains from being tracked in the referrer and referring_domain attribution fields
  • Continue to track UTM parameters and click IDs (gclid, fbclid, etc.) when they are present in the URL, regardless of the referrer

The intent of excludeReferrers should be to prevent self-referrals from your own domain from creating false attribution, while still capturing legitimate campaign parameters that exist in the URL.

Current Behavior

When a referrer matches an excludeReferrers pattern, the plugin completely blocks ALL campaign parameter tracking, including:

  • UTM parameters (utm_source, utm_medium, utm_campaign, etc.)
  • Click IDs (gclid, fbclid, etc.)
  • All other campaign attribution data

This results in missing attribution data even when valid campaign parameters are present in the URL.

Possible Solution

The bug is in @amplitude/analytics-client-common/lib/esm/attribution/helpers.js in the isNewCampaign() function (lines 19-23):

if (isExcludedReferrer(options.excludeReferrers, current.referring_domain)) {
    logger.debug("This is not a new campaign because ".concat(current.referring_domain, " is in the exclude referrer list."));
    return false;  // ← BUG: Returns false immediately, blocking ALL campaign tracking
}

The excludeReferrers check happens before checking if there are actual new campaign parameters (line 29). This causes the function to return false immediately, preventing any attribution tracking.

Suggested Fix:

The excludeReferrers check should only affect the hasNewDomain calculation, not the entire isNewCampaign result. Campaign parameters should still be tracked even when the referrer is excluded. For example:

export var isNewCampaign = function (current, previous, options, logger, isNewSession) {
    // ... existing setup code ...
    
    var hasNewCampaign = JSON.stringify(currentCampaign) !== JSON.stringify(previousCampaign);
    
    // Only apply excludeReferrers to domain-based attribution, not parameter-based attribution
    var isReferrerExcluded = isExcludedReferrer(options.excludeReferrers, current.referring_domain);
    var hasNewDomain = !isReferrerExcluded && 
                       domainWithoutSubdomain(referring_domain || '') !== domainWithoutSubdomain(prevReferringDomain || '');
    
    // If referrer is excluded, log it but still check for campaign parameter changes
    if (isReferrerExcluded) {
        logger.debug("Referrer " + current.referring_domain + " is excluded, but checking for campaign parameter changes.");
    }
    
    var result = !previous || hasNewCampaign || hasNewDomain;
    // ... rest of function
}

Steps to Reproduce

  1. Configure the Web Attribution Plugin with excludeReferrers to exclude your own domain:
import { webAttributionPlugin } from '@amplitude/plugin-web-attribution-browser';

const webAttribution = webAttributionPlugin({
  excludeReferrers: [/yourdomain\.com$/]
});

amplitude.add(webAttribution);
await amplitude.init('YOUR_API_KEY');
  1. User lands on your site from a Google Ad with campaign parameters:

    • URL: https://yourdomain.com/?utm_source=google&utm_medium=cpc&gclid=123
    • document.referrer: https://www.google.com
    • Result: Attribution tracked correctly ✅
  2. User navigates to another page internally:

    • URL: https://yourdomain.com/other-page?utm_source=google&utm_medium=cpc&gclid=123 (parameters preserved)
    • document.referrer: https://yourdomain.com (matches excludeReferrers pattern)
    • Expected: UTM parameters and gclid should still be tracked
    • Actual: No attribution tracking happens at all ❌
  3. Check Amplitude events - you'll see the campaign parameters are missing from the internal navigation events, even though they were in the URL.

Additional Scenario: Server-Side Redirects

This bug is particularly problematic when using server-side redirects (e.g., Next.js redirects in next.config.js):

  1. User clicks Google Ad landing on: https://yourdomain.com/pricing?utm_source=google&utm_medium=cpc&gclid=123
  2. Server performs redirect (with query parameters preserved): https://yourdomain.com/product/pricing?utm_source=google&utm_medium=cpc&gclid=123
  3. After redirect:
    • document.referrer: https://yourdomain.com/pricing (the pre-redirect URL on your own domain)
    • Current URL: https://yourdomain.com/product/pricing?utm_source=google&utm_medium=cpc&gclid=123
    • Expected: UTM parameters and gclid should be tracked from the URL
    • Actual: No attribution tracking happens because referrer matches excludeReferrers

This means any page that's reached via a server-side redirect loses all campaign attribution if you use excludeReferrers, even on the very first page load from an external ad campaign.

Real-world impact: When using Google Tag Manager's Conversion Linker (which preserves gclid in cookies but not UTMs), users see gclid values in their analytics but no UTM parameters, because GTM re-appends gclid but Amplitude's plugin doesn't track the URL parameters when the referrer is excluded.

Environment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions