How to Add Referral Tracking System with Laravel

This tutorial was created with Laravel 5.5 on a fresh installation and could be considered outdated.

Referral affiliate tracking seemed like something that would be a pretty common development addition to Laravel, but I did not find much in the way of tutorials to guide me 100% of the way there.

This tutorial will walk you through creating functionality in Laravel that will allow your users to share an affiliate link that will give them credit for new users that register with your site. The principles described here should allow you to extend this tutorial to fit other referral needs.

Many thanks to Andy Brudtkuhl’s guide that brought me 85% of the way there; here is the extra 15%:

1. Setup the DB & Migrations

We’ll need to have at least the base auth scaffolding implemented

php artisan make:auth

Next, let’s generate a new migration that will add a new column to our User table.

php artisan make:migration AddReferredByToUsersTable

In this migration, just add a nullable integer called referred_by. We’ll just be setting the referrer’s user id as the referred_by value for simplicity’s sake.

Schema::table('users', function(Blueprint $table)
{
  $table->integer('referred_by')->nullable();
});

and make sure to drop it nicely

Schema::table('users', function(Blueprint $table)
{
  $table->dropColumn('referred_by');
});

Then, run your migration and check your DB to see that the columns are all set.

php artisan migrate

Protip: Make sure you add referred_by to the $fillable array in the User model (app/User.php), otherwise you’ll see some breakage.

2. Generate Referral Links

Easy peasy, just echo out the current logged-in user’s id appended to your url. The middleware we’ll build can catch it anywhere on the site, so feel free to customize this or build it into a helper function.

Stick this inside a view of your choosing.

@auth //only show for logged in users
  <input type="text" readonly="readonly"
         value="{{ url('/') . '/?ref=' . Auth::user()->id }}">
@endauth

The ?ref value will be what the middleware checks for.

3. Bake Cookies with Middleware

Now let’s create a new cookie if someone visits the referral link. We’ll later use this cookie to update the database during user registration.

For those that aren’t familiar with it, middleware basically runs as a filter for HTTP requests.

This means we can add new middleware that will check to see if we’ve added ?ref to the url and then set a cookie if we don’t have one already.

php artisan make:middleware CheckReferral

After we create our middleware, we need to register it in the kernel (app/Http/Kernel.php). We can specify certain routes or add it to a middleware group, but for this case a simple global registration is sufficient.

Add "\App\Http\Middleware\CheckReferral::class" to the end of the $middleware array.

Now, let’s create that cookie by adding some simple functionality to the new middleware file.

Replace the default handle() functionality with this:

$response = $next($request);

// Check that there is not already a cookie set and that we have 'ref' in the url
if (! $request->hasCookie('referral') && $request->query('ref') ) {
  // Add a cookie to the response that lasts 5 years (in minutes)
  $response->cookie( 'referral', encrypt( $request->query('ref') ), 525600 );
}

return $response;

Protip: By default, Laravel uses encryption in cookies. Use encrypt() to pass values to cookies, otherwise you won’t be able to retrieve them later on. Otherwise, you’ll need to add the cookie name to the $except array in the EncryptCookies (app/Http/Middleware/EncryptCookies.php) middleware.

Now, our registered middleware will check the url for ?ref and create a cookie.

Try it now: Navigate to a the referral url you generated in your view earlier. Then, check your developer tools to see if the cookie has been set. In Chrome, this is currently under the Application tab of the Developer Tools.

4. Assign the Cookie Value During Registration

So, now that our User model can have a referrer_id assigned to it and we have the referral cookie set, let’s finish this up by adding the referral cookie value to the referrer_id during user registration.

Fix up the default create() function in RegisterController (app/Http/Controllers/Auth/RegisterController.php) to look like this:

protected function create(array $data)
{
    $referred_by = Cookie::get('referral');

    return User::create([
        'name' => $data['name'],
        'email' => $data['email'],
        'password' => bcrypt($data['password']),
        'referred_by' => $referred_by,
    ]);
}

If you’re feeling protective, look into validating that $referred_by is a real user id. Remember, this value can be null and by default Cookie::get() will return null if no value is detected.

You’ll need to import the Cookie facade here to use that function.

use Illuminate\Support\Facades\Cookie;

Try it now: After navigating through a valid affiliate url (and confirmed the cookie is set properly), register a new user and confirm that the referrer_id has been set in the database for the new user.

Now what?

Well, that’s all for the sake of this article. Getting into awarding referrals tends to split dramatically from here on out depending on what you’re trying to accomplish.

At the very least, you have a foundation where you at least know who referred who.

Let me know if you have any questions or improvements in the comments below, particularly if you:

  1. Know how to register the Middleware to automatically encrypt cookies without the use of encrypt()
  2. Feel strongly that we should use a hashed user id for referral links.
  3. Got lost anywhere along the way.

EventSprout – Mass Import

EventSprout is an event management and Ecommerce solutions that event organizers use to sell tickets.

In a typical sale, a single user goes to buy a single ticket and the checkout is very simple.

But what if a group wants to buy tickets? Or an organization comprising of dozens or even hundreds of participants? A single checkout process would take hours and with so much information added to one server request, it could break the process altogether.

The solution? Adding mass import functionality for customer support to use at their discretion for these large sales.

In short, the organization would send over an excel file filled out with member information. Everything from name and age to shirt size and address could be filled out before hand and uploaded to EventSprout for mass order creation.

First, I needed to validate that the file was a CSV. Excel files, PDFs, and other images types don’t produce clean data for use in segmenting multiple users and their data.

After validating a proper file had been uploaded, the user would select the event these customers were attending and select whether or not the system should email users after successfully adding them. Easy enough.

Status: It’s Complicated

Though fields like first name, last name, and email are required for every single event on the platform, each event can have unlimited additional questions for participants to fill out such as age, address, gender, shirt size, etc – each requiring their own custom validation rules.

I needed a way to preview a few of the uploaded columns and allow the user to select which column was for each event question. This included the ability to ignore an unnecessary column and ensuring no duplicate columns were selected by accident.

Additionally, there was no simple way to choose which ticket these customers wanted. EventSprout doesn’t know that GA stands for General Admission, so I had to build out a “ticket translator” for the user. For any event, it would generate the proper value of the ticket name, including the groups it was nested under. If this proper name was not added to the ticket column, it would throw an error.

Speaking of Errors

Now, what if a row had an error? Should we invalidate the entire import?

I decided to allow successful orders through and create a new CSV of failed rows – including their error message – so that the user could correct the data and re-upload with ease.

If that all sounds easy enough, let’s remember that this had to work within the existing platform and a ton of core code needed to be modified in order to pass through orders in this way. Code that was in use on an existing Ecommerce platform that handles hundreds of thousands of dollars of transactions for their clients, not in a pre-launch development bubble.

So, in that light, I created unit tests to run against every new commit that tested both the success and failure of mass imported CSVs.

In the end, the packaged product solved the problem nicely to the delight of customer service reps who had to enter all these customers manually before.

Firefly Music Festival – Survey Platform

Like any product or business, getting customer feedback is critical to ensure your solving their needs.

Firefly Music Festival took that effort one step farther by announcing that their 2017 festival would be fan-curated.

Fans would get to cast votes for festival artists, submit poster designs, and even select the name of a Taco truck.

Behind the scenes, the Firefly team wanted to collect demographic information and ensure that no one tried to game the system, all while providing multiple types of surveys across 6 categories each with their own start and end dates.

Survey types included:

  • Text Submission
  • Multiple Field Submission
  • Multiple Choice
  • Image Select
  • Rank the Following Random Selection
  • Upload File
  • Combinations of the above

Some would allow unlimited votes, while others could have a limited number of votes per day.

The complexity of this system did not lend itself to any available 3rd party solution, so I had to build the platform from scratch.

The Core Build

Since this was the first year Firefly was presenting itself as fan-curated, it didn’t make sense to invest in the platform’s full capabilities. There was always a distinct possibility of scrapping the concept for the next year, so I opted to keep the platform lean.

This meant limiting administration and management functionality severely and keeping the platform as a developer solution. The Firefly brand team would plan and organize the content and direction of each survey and I would work to build each of them out as needed.

At its core, users would need to register and fill out base demographic info. In order to prevent spam voters and cheaters, users were ultimately required to confirm their accounts before proceeding through the platform.

When a user submitted a survey, each field of their entry would be added to a master answers table that listed the survey’s ID, the user’s ID, the type of question, the question’s title, the option number of the question (for multiple checkboxes and band ratings), and finally the value itself.

Additionally, a separate table kept track of the surveys a user had filled out in order to prevent users from voting too many times.

This core data structure would easily provide for managing every survey type.

The Survey Builds

Though most surveys were simple text submission or multiple choice and could be easily reproduced, some survey builds were complex and required creative planning in order to fit them into the existing system.

The following surveys broke the mode and required core changes.

Zoom Contest

In years past, Firefly had run a “hide-and-seek” contest called the Zoom Contest.

The contest began on the web page with a zoomed out map of a city. As users tweeted a certain hashtag, the map would zoom in further and further until it hovered above a local business. There, the first fans to find the Firefly representative would win VIP passes to Firefly.

So, I had to build out a system that would allow for back-to-back city contests, track and actively display Tweets, and zoom in randomly around the specific location (to prevent people pinpointing the location too early).

Though the contest did not track any user submissions, it still became a part of this fan-engagement platform.

Big Break Live

Every year, Firefly holds a contest for bands around the globe to submit themselves for selection in the Big Break contest. After internal rounds of vetting, fans can vote on a final selection of bands and one is ultimately chosen to come out to Firefly to perform. It’s an amazing chance for new artists to reach a huge audience.

In 2017, the Firefly brand team renamed Big Break to Big Break Global and created a local content called Big Break Live.

In this contest, only bands within 150 miles of Dover, De could submit their acts.

After vetting, bands would go through multiple rounds of voting – ultimately culminating in a live show for an audience and a panel of judges.

Both of these contests required submission management, multiple voting periods, different votes/day rules, and elimination rules. As the contests progressed, more and more details about the bands would be shown.

I created a separate database table for these bands and their data, opting to use json formatting for their submitted data as some bands would provide more or less detail.

I don’t like wasted database columns.

Talent Survey

Firefly relies heavily on fan feedback when it comes to booking bands and discovering new talent.

The yearly talent survey is sent to everyone and asks them to rate acts from 0-10 and a few other demographic questions.

Fans certainly wouldn’t vote on every one of the hundreds of bands out there, so the survey needed to show 40 random acts in order to ensure voting evened out for all bands.

On top of that, the team wanted to open up voting to as many people as possible so they asked for the survey to not require a login. So, depending on if you were logged in or not, demographic questions were added to the survey and a guest submission was saved. Though not originally built with the intent to save guest submissions, I outfitted the core to handle this process.

The result? Over 15,000 submissions in 2017 and a solid foundation for talent planning for 2018’s festival.

Band Name Generator

Somewhere along the way, the Firefly team had an idea for a viral marketing product that would allow fans to feel personally attached to the 2017 festival and provide wearability to their audience.

In similar fashion to the Wu Tang Clan Name Generator, I built a Firefly Band Name Generator.

In short, a user could enter their name a random band name would be provided – but not purely random. If they entered their name again, the same response would be spit out. Change a single letter and you would have a completely different name – almost like magic.

The magic uses two techniques and no database storage.

First, the team helped me compile two lists: one of adjectives and one of nouns. These would be used to create adjective-noun pairings for the final band name.

Then, the name provided would be broken down and passed through php’s srand() function – which alters the default random number generator. With the random generator altered to fit the name, we can pass through the list of adjectives and nouns and produce a pairing. Since the name always produces the same random number generator, the same pairing is always produced. Neat!

Now that we had a magic band name pairing, we could add the name to an image (not just on top of it) to produce a shareable image.

Just upload the image to Amazon S3, add the image URL to the open graph structure of the page, and Facebook will automatically pull the image when the URL is shared.

All In All

Over the 6 month period of building and launching the product, the platform added 35 different surveys, registered nearly 50,000 users, received 225,000 submitted surveys, and stored a total of 2.1 million individual answers in the database.

Now that’s big data.