Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Referer Parser Laravel Package

snowplow/referer-parser

Referer-parser for PHP identifies where your traffic comes from by parsing referer URLs. It detects search engines, social networks, email and other sources, extracting search terms and medium details so you can classify visits and attribute conversions accurately.

Deep Wiki
Context7

Getting Started

Install the package and parse your first referrer in under a minute:

composer require snowplow/referer-parser
use Snowplow\RefererParser\Parser;

$parser = new Parser();

$referer = $parser->parse(
    $_SERVER['HTTP_REFERER'] ?? '',
    'https://example.com/pricing'          // current page URL (optional but recommended)
);

$referer->isKnown();   // true if the source is recognised
$referer->getMedium(); // "search", "social", "internal", "unknown", ...
$referer->getSource(); // "Google", "Facebook", "Twitter", ...
$referer->getTerm();   // "gateway oracle cards" (search term, if present)

Where to look first:

  1. README.md — canonical usage and method signatures.
  2. src/Parser.php — the parse($referrerUrl, $pageUrl) entry point and construction options.
  3. src/Referer.php — the result object (isKnown, getSource, getMedium, getTerm, getCampaign, getSearchEngine).
  4. references/referers.yml (or the bundled YAML data file) — the actual source list; this is your extension point.
  5. tests/ — fixtures showing expected output for known/unknown/campaign URLs.

First real use case: attribution capture on an incoming HTTP request. Register Parser as a singleton in AppServiceProvider, then call parse() inside a middleware or a registration/conversion handler and persist source, medium, and term alongside the user or order. That single hook answers "where did this visitor come from?" for the rest of the app.

Implementation Patterns

Bind the parser as a singleton. It reads the YAML reference data on construction, so build it once and let the container share it:

// app/Providers/AppServiceProvider.php
use Snowplow\RefererParser\Parser;

public function register(): void
{
    $this->app->singleton(Parser::class, fn () => new Parser());
}

Middleware for first-touch attribution. Capture on the first request that has a referrer, then freeze it in the session (or write to a dedicated column so it survives session loss):

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Snowplow\RefererParser\Parser;

class CaptureAttribution
{
    public function __construct(private Parser $parser) {}

    public function handle(Request $request, Closure $next)
    {
        if (! $request->session()->has('attribution')) {
            $result = $this->parser->parse(
                $request->headers->get('referer', ''),
                $request->fullUrl()
            );

            $request->session()->put('attribution', [
                'known'  => $result->isKnown(),
                'source' => $result->getSource(),
                'medium' => $result->getMedium(),
                'term'   => $result->getTerm(),
            ]);
        }

        return $next($request);
    }
}

Campaign parameters are parsed from the page URL, not the referrer. When a user lands on ?utm_source=newsletter&utm_medium=email&utm_campaign=spring, pass that URL as the second argument; the campaign object exposes the UTM fields:

$result = $parser->parse($request->headers->get('referer', ''), $request->fullUrl());
$campaign = $result->getCampaign();

if ($campaign) {
    $campaign->getSource();   // newsletter
    $campaign->getMedium();   // email
    $campaign->getName();     // spring   (utm_campaign)
    $campaign->getTerm();     // utm_term
    $campaign->getContent();  // utm_content
}

Treat UTM/campaign data as higher priority than referrer-derived data in your attribution model — it is explicit intent from the marketer, whereas the referrer header is a browser hint.

Persist a normalized row rather than echoing raw headers. A small attributions table (source, medium, term, campaign_source, campaign_medium, campaign_name, raw_referer, landing_url, created_at) gives you something queryable for reporting and keeps PII-laden raw URLs out of analytics events.

Enrich analytics events. If you ship events to Snowplow (the package's origin), map the parsed fields to refr_source, refr_medium, refr_term, mkt_source, mkt_medium, mkt_campaign. Doing it once in a shared event transformer keeps all downstream events consistent.

Test against a fixture set. Snapshot a handful of real-world URLs (Google search, a social profile, a direct hit with no referrer, an internal link, a UTM-tagged landing page) and assert exact outputs. This protects you when reference data changes on upgrade:

public function test_google_search_is_attributed(): void
{
    $parser = new Parser();
    $result = $parser->parse(
        'https://www.google.com/search?q=laravel+queues',
        'https://example.com/'
    );

    $this->assertTrue($result->isKnown());
    $this->assertSame('search', $result->getMedium());
    $this->assertSame('Google', $result->getSource());
}

Custom reference data for niche sources. If your marketing team needs partner domains the bundled list doesn't cover, pass a custom YAML path to the Parser constructor and add your own entries rather than maintaining regex post-processing.

Gotchas and Tips

  • HTTP_REFERER is frequently absent. Direct navigation, bookmarks, mobile apps, and strict referrer policies all produce an empty string. isKnown() returns false and getMedium() typically yields unknown — don't treat that as an error, treat it as a valid bucket ("direct").
  • Pass the page URL for internal detection. Without it the parser cannot tell that https://example.com/other-page is same-site traffic. Skipping the second argument means internal navigation gets misclassified instead of flagged as internal.
  • Modern browsers strip query strings and paths. With Referrer-Policy: strict-origin-when-cross-origin (the default in Chrome/Firefox), cross-origin referrers arrive as bare origins — so getTerm() is usually empty and search-engine detection can degrade. Set a permissive Referrer-Policy if you genuinely need terms, and never make business logic depend on them.
  • Normalize before parsing. Ensure a scheme (https://), strip fragments, and decode as needed. A malformed URL may throw or silently miss — wrap the call in a try/catch at ingestion boundaries (webhooks, imported data) and fall back to an "unknown" record.
  • Case and trailing slashes matter. Reference domains are matched precisely; Google.com vs google.com and a stray trailing dot can change results. Lowercase hostnames upstream.
  • Campaign vs. referrer precedence is your decision. The library reports both; it doesn't choose. Pick a policy (campaign > referrer > direct) and apply it in one place, not scattered across controllers.
  • Privacy and compliance. Referrer URLs and UTM values can contain emails, IDs, and tokens. Sanitize or hash before persisting, and scrub the raw referer from analytics exports.
  • Reference data lags behind new services. A newly popular social platform or regional search engine may be missing. Check isKnown() false-negative rates in staging before assuming a bug — the fix is usually extending the YAML, not the code.
  • Reuse the parser instance. Constructing one per request re-reads the data files; the singleton binding avoids that overhead in hot paths.
  • Don't infer search intent from getTerm() on non-search sources. Only treat it as a keyword when the medium is search; social and internal sources will leave it null or meaningless.
  • Extension point: subclass or wrap Parser if you need to add post-processing (e.g., mapping vendor names to internal channel labels). Keeping that mapping outside the package keeps upgrades painless.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource