Tectonic shifts in the Direct-To-Consumer Landscape are surfacing

Originally posted on Medium.

The signs are everywhere. On a macro level, 2018 was a year where DTC brands continued to flourish and redefine the commerce landscape. Under the surface though, it was hard not to notice some of the cracks beginning to form in the foundation. As we find ourselves approaching the end of a full decade of disruption from DTC brands, 2019 will be a year of adaptation to the new realities of an evolving landscape, one in which the very idea of what constitutes a brand continues to shift and mutate.

The brands that excel in the next decade will have learned to navigate the following new realities:

Unrelenting competitive pressure from above and below

It’s never been easier to launch a DTC brand and it will keep getting easier to do so. While there is still real competitive advantage in making great product, the next decade will see this advantage erode significantly. In the apparel industry, the minimums required from manufacturers are on a race to one. At the same time, speed to market will increase to the point where just-in-time manufacturing becomes the new norm in apparel. Technology will do the same in the apparel manufacturing industry as it has for other industries: aggregating power to a few dominant players. These new giants will also be your new competitors. The brands that have managed to stay above the fast fashion fray by offering higher quality product will lose the protective moats surrounding their supply chains.

Thanks to Shopify and its growing marketplace of apps, developers and designers, a new entrant can spin up a best-in-breed online shopping experience in a snap. Existing competitive advantages like the out-of-box experience, rapid delivery and easy returns are on the path to commoditization. These aren’t core competencies any more, they are table stakes.

In the beginning of the DTC era, there was plenty of empty space to expand into. With the lower costs of entry, newer DTC entrants are increasingly looking to target smaller slices of the market with narrower, more customized product offerings. These niche players will not be VC-funded and will be quite content taking their time growing into upper seven to low eight figure businesses. Larger players in these spaces will be fending off these “gnats” with fly swatters made of mesh that isn’t fine enough for the job. Lawrence Lenihan, Co-Chairman of Resonance Companies, refers to this coming phenomenon as the “Economies of Small”.

As if that weren’t enough, the 800-lb gorilla in the room, Amazon, continues to eat up more and more space in the expanding online retail universe. FTI projects that its market share of online retail will expand to 50% by 2023. You can bet that after devouring the low margin, high volume end of the private label spectrum, it will turn its sights upmarket.

Consumer attention is aggregated among a few massive media players

The unrelenting onslaught of software eating the world has left marketers with fewer and fewer places to play. Too much power has been aggregated in the hands of too few and we now find ourselves feeling trapped and constrained in our options as growth marketers. The number of brands vying for impressions is exceeding the available attention span of Facebook and Instagram users, leading to declining ad engagement and soaring CPMs. Does an ad with little to no engagement influence users? News flash, it doesn’t, no matter how great the ad content.

Niche brands are at even more of a disadvantage on paid social. The more niche a brand is, the harder it is to scale spend on Facebook and Instagram. This is simply a matter of having less data for Facebook to work its machine learning magic with. As CPMs have risen, so too has the cost of traffic. At today’s elevated CPCs, these niche players lack the breadth of product to acquire enough customers to train Facebook’s machines adequately. With Facebook unable to learn where it can effectively expand the reach of these brand’s ads on its platform, scaling advertising spend efficiently is simply out of the question.

VCs initially overcapitalized DTC brands with the expressed purpose of acquiring as many customers as possible, economics be damned. But spending to go big (“Spending To Dominance”, as Bob Lefsetz puts it in his excellent piece on Netflix) hasn’t yet produced huge exits in the DTC space. The jury is still out, but the winner-take-all approach hasn’t worked yet. One can surmise that this is because network effects don’t apply to CPG brands (they have yet to behave as platforms…with one notable exception) and throwing dollars at advertising quickly reaches the threshold of diminishing returns as an investment. This overcapitalization, for however long it remains, is another factor leading to the increased customer acquisition costs seen in paid social today.

The lack of authority in brand content

When it comes to deciding content quality, it’s not the vote of a branding agency, nor the votes at Cannes that matter, but rather the vote of the customer. DTC brands today spend gobs of money on visual content only to have no real sense as to its effectiveness. Today’s consumers do not want to feel they are being sold to and regardless of its quality, so much of the content produced by brands today lacks the authenticity and authority the customer craves.

It’s not secret who has the authority these days. It’s the celebrity, the influencer and increasingly, the customer. They are the ones setting the trends and producing authentic content. Whether you agree with that or not, there is no question that the authority today lies with them. One need look no further than Glossier’s Instagram to see this dynamic in full effect. I would opine that Glossier’s visual content is not of the highest visual quality. However, one cannot deny that it is of exceptionally high authenticity and there’s no question of its effectiveness.

The dead cat bounce in physical retail

One could scarcely read anything in the DTC space last year without some mention about the re-emergence of physical retail. The problem with physical retail as a channel though remains foot traffic. There simply has not been a meaningful enough rebound in foot traffic for the recent buzz to be considered anything more that a brief counter to the long term downtrend. A glance at the US Retail REIT index shows the index at the very same level it was over 10 years ago, right before the great recession. More importantly, the index has fallen more than a third over the last 18 months. DTC brands may be bullish on physical retail, but it’s clear investors are not.

The problem lies in the current day physical retail experience. There hasn’t been enough innovation yet to drive incremental foot traffic. Certainly, there is nothing wrong with taking advantage of very selective and strategic retail opportunities. Getting direct tactile feedback from consumers is invaluable, as is offering a high density slice of a brand’s core demographic the opportunity to touch and feel. Physical retail should only be a small part of the overall channel mix for most DTC brands though. Brands that are banking on physical retail as the gateway to profitable growth are relying on an old playbook.

Well, all of that probably sounds quite foreboding. You might mistake me for being bearish on future of DTC brands, but I’m actually quite bullish. The brands that will be successful going forward will have adapted and, in the process, will have disrupted the disruptors.

Here’s how I see brands evolving in the DTC space:

A shift from acquiring customers to acquiring attention

With the cost of customer acquisition continuing to increase, the focus will shift from acquiring customers at unfavorable economics to acquiring more of a brand’s existing customers’ attention. The more attention a brand has from its customers, the better it can understand their wants, needs and desires. These additional data and insights will allow brands to develop product extensions to their increasingly niche core offerings. Selling these new products to an existing customer is significantly more profitable than the economics involved in acquiring a brand new one. The metric that captures this profitable symbiotic relationship with customers is lifetime value, which will quickly become the new vanity metric for DTCs going forward. This sentiment is perfectly articulated in David Perrel and Nik Sharma’s excellent article, The Customer Acquisition Pricing Parade.

Brands are already feeling the need to expand their presence in the lives of customers. If they don’t, they risk being forgotten and replaced by more engaging brands or simply cannibalized by Amazon, the bottom-of-the-funnel brand crushing black hole of online retail. If the presence of a brand in your customer’s digital life is simply to capture the occasional transaction, consider that brand at risk. If a brand’s email program functions as a way to refresh its customers recollection of its very existence, the next decade is not going to be very kind. The digital presence of every brand needs to shift from transaction to attention.

So how does a brand acquire more attention from its customers? By widening the aperture of its storytelling lens. Brands need to reciprocate the trust they’ve earned from customers and entrust them to help tell the story. The days of push storytelling are numbered and pull storytelling is taking its place. Brands need to pull customers into their storytelling and explore their journey with these customers on board as equal partners. With product quality becoming less of a differentiator in the future, word of mouth effects will begin to shift towards the brands whose stories are increasingly intertwined with those of its customers. This audience will seek to increase the utility they receive from sharing in these brands’ stories by bringing their friends along for the ride. Just like a ….. platform. A perfect example of this phenomenon today is Glossier, which will continue to shine in the next decade as it becomes a huge beauty platform with network effects. The growth of all brands going forward will be more a function of the role played in the lives of its consumers than of the product produced.

The rise of influencers-in-residence

Brands today lack the authority to set trends. As this realization becomes more and more readily apparent, I believe we will begin to see brands seek to gain back authority through association with influencers. That in and of itself isn’t newsworthy. But in this case, these won’t be with just any influencers; but instead a brand’s very own homegrown talent. In 2019, we will begin to see the rise of influencers-in-residence.

If you’re looking to launch your influencer career today, it’s going to be very difficult to break through. Just as there has been an explosion of brands in the DTC space, so too has the number of influencers expanded exponentially. The reason why is essentially the same in both cases: low barriers to entry. Nascent influencers lack trust and credibility, but existing brands have that in spades. These brands in turn lack compelling content, an issue that influencers can certainly alleviate. Brands routinely need to boost their posts through paid advertising (if ever there was an indication that advertising is the cost of being boring, this would be it). Influencers never have to pay to ensure their posts are seen.

Once brands realize the benefits of nurturing their own nascent influencer talent, they will gladly foot the bill to gain this increased organic engagement with their owned media. As soon as the influencer has proven s/he can support a presence of their own, they will move on to posting in their own channel and the next influencer-in-residence will assume the mantle for the brand’s social properties. A virtuous cycle thus forms where the brand’s audience will continue to associate the influencer’s rise with the brand, which in turn, lends the brand on-going authority. Rinse and repeat.

Of course, such an arrangement will require brands to give up a degree of control over the content posted in their social channels, including and not limited to, content about another brand’s products. GASP!

Which leads to the next trend..

Lifestyle ecosystems built by like-minded brands

Brands of the future will have no delusion of owning the entire customer and will focus obsessively on a single product category to improve their customers’ lives. These brands will cater to a particular lifestyle and ethos shared by other brands focusing obsessively on complementary product categories. Together, these brands will form self-sustaining ecosystems built around specific lifestyles.

Brands today put up artificial walls, but the days of brands as dead ends are over. The need for brands to be authentic stalwarts of a lifestyle requires discovery of and reciprocity to other complementary brands. The brands that share freely will form galaxies in a universe of otherwise disparate planets. The solo path will feel increasingly lonely. Larger DTC brands who came to fruition during the current decade will likely eschew this trend during the coming decade. Their prior VC-funded growth will offer connective brands the opportunity to chip away at the these larger brand’s market share . For a present day example of this ecosystem trend, look no further than the collaboration between Rowing Blazers and Tracksmith. When I saw this collaboration between these two like-minded brands, I had to stand up and cheer. Bravo!

From the aforementioned Perrel and Sharma article:

There’s the current state of customer acquisition — a parade of brands looking to acquire every single customer individually.

I predict we’ll see a lot of innovation in these lifestyle ecosystems very shortly. Sharing, open borders and collaborations are the future for the vast majority of brands.

Fixing Shopify product data in Google Analytics

UPDATE: To make your Shopify event tagging in Google Analytics even more robust and seamless, I highly recommend the Elevar service. They have a free plan to get you started on your Shopify eventing journey. Learn more >

If your Shopify store happens to sell products with variants, you have likely felt the futility of attempting to use the Product Performance report in Google Analytics. 

With data available only at the variant level, doing what should be very simple analysis, like understanding what key products were bought from an email, becomes tedious. None of us want to export this data to excel, parse it and then use a pivot table to get a report that we can actually use. Instead of seeing data at the variant level, what we really need is a way to view it at the master product level. 

 Wouldn’t it be better to have a report like the following? 

Layering on GA segments like the existing customers segment we created in the last post or a new customers segment makes this report even more useful. Just think how powerful it would be to know which products convert best for new customers vs. existing customers. I bet that would change the way you think about merchandising and selecting products for acquisition ads. Applying a segment of email traffic to such a report would let us know if those visitors actually bought what we featured in our email creative. Those are real insights that can drive your business forward.

The good news is if you’d like to put this fix in Google Analytics in place for your Shopify store, just read on!


To put this solution in place, we’ll be utilizing Google Tag Manager, customizing Google Analytics and inserting a bit of code into our Shopify implementation.

In GTM, we’ll be creating three new GA tags: one for product page impressions, one for add to cart events and a final one for products ordered.

Moving over to GA, we’ll create new custom dimensions and custom metrics to capture the data from our GA tags. Then we’ll create a few calculated metrics from these custom metrics. Finally, we’ll create the custom report to replace the existing GA product report. We’ll be moving a bit faster in this post, so if any of the GTM concepts are a bit hard to follow, please see my first post for a more detailed walkthrough.

Ready to put this in place? Let’s get going!


We will want to fire our product impression GA tag every time that a product page is viewed. To start, let’s edit our Shopify code so that we can capture our product name in a GTM variable. In our code, find the html element that wraps your product title on your product page. For example:

<h2>{{ product.title }}</h2>

Let’s go ahead and add an id to this h2 tag like follows:

<h2 id="product-title">{{ product.title }}</h2>

In GTM, we can now create a variable to capture the product name. Let’s call the variable Product Name and use DOM Element for the Variable Type. Use ID for the Selection Method and enter our id above for the Element ID 

Before we create our GA tag, we’ll create a trigger that will fire on every product page impression. The trigger condition will use the Product Name GTM variable created above and will be set to fire when it is present on the page (i.e. not null).

Let’s jump over to GA now. Before we can create the GA tag for the product impression, we need to create a custom dimension to record the name of the product viewed. We’ll call it Product Name as well.

Note the index position for this new custom dimension after you save it. You’ll be using it when creating your GA tag in GTM.

Now, we’ll create a custom metric in GA to record the impression. Let’s call it Product Page View. In addition to serving as a counter for the number of page views a product receives, this custom metric will also serve as the denominator in a few calculated metrics coming later (Add To Cart Rate and Product Conversion Rate). When creating this custom metric, leave the Scope as Hit and the Formatting Type as Integer. Again, note the index position for this new custom metric after you save it, as you’ll need it when creating the GA tag.

Let’s head back to GTM. Now on to creating the GA Tag. Let’s call it GA – Product Page – Impression. For Track Type, select Event. For Category, enter Product. For Action, select the {{ Product Name }} GTM variable you created above by clicking the + button and selecting it. This will populate the actual product name in GA for the event. For the Label, you can enter Impression. These values for the Category, Action and Label define the taxonomy for this event in GA. Be sure to check the Enable override settings in the tag box. For the Tracking ID, either create a new GTM variable using the Constant variable type and include your GA Tracking ID as the value or just copy and paste your GA Tracking ID directly into the input. In my example below, I’ve chosen to create a new variable called {{GA-ID}}. This will prevent me from having to continually copy and paste in my GA Tracking ID for future GA tags.

Expand the More Settings section. Under Custom Dimensions, enter your index position from above and select your {{Product Name }} GTM variable. Under Custom Metrics, enter your index position from above with a value of 1.

Here’s the competed GA tag: 

Just assign it to the Product Page – Impression trigger you created and we’re all set.


Our objective here is to fire a GA tag every time a product is added to the cart. To begin, let’s find the code in your theme which handles the add to cart action. Most themes will use an ajax event that looks very similar to the following: 

	      type: 'POST',
	      url: '/cart/add.js',
	      data: data,
	      contentType: 'application/x-www-form-urlencoded',
	      dataType: 'text',
	      success: function() {
	        {% increment cart.item_count %}
	      error: function() {

This is the code allows us to add to cart without requiring a page refresh. What we need to do is notify the data layer that an add to cart event has occurred. We will place this data layer code within the <script> tag that houses the add to cart action above. The code we will inject needs to go before the POST action above. Here’s the code:

    		event: 'GTM-ADD-TO-CART',
    		AddToCartHit: 1

For simplicity, we are assuming that the quantity added to cart will be a unit of 1 each time. To handle the case where a variable number of units can be added to cart, we would capture this selection on the page by the customer with an additional variable in the data layer. It would be included in the data layer array as a separate entry after the AddToCartHit variable in the code above. We would then create a new GTM variable to house the value. 

Now we create the GTM variable to record the AddToCartHit variable that has been injected into the data layer.

And here’s the trigger we’ll need to create the fire the GA tag. Note that the Event name is the same as the one we used in the data layer push above (GTM-ADD-TO-CART):

Jumping back into GA, we don’t need to create a new custom dimension, as we already have one for the product name. We do however need a new custom metric to record the add the cart event.

All good. Now we just need to create the GA tag. The tag is very similar to the product impression tag we created earlier with just a few changes.

Note the change in the index we are using in the Custom Metrics section. For the Metric Value, we have input a value of 1, but if you have created a GTM variable to capture the add to cart quantity, you’ll use that variable here instead.


To record the purchase event in GA, we will again need to populate the data layer. This time we will be informing GA which products have been purchased via a GA tag in GTM. Since we don’t have access to the source code on the Shopify thank you page, we’ll utilize the Additional Scripts area of the checkout settings in Shopify (Settings > Checkout).

In my first post, we inserted the following code into this area:

<!-- GTM Tagging -->
{% if first_time_accessed %}
<p id="GTM-PURCHASE-TRIGGER" style="color:white">GTM</p>

{% endif %} 

We’ll use this code as our base to insert new code to populate the data layer. Put the following code right after the closing </p> above:

	{% for item in line_items %}
        	<script type="text/javascript">
                	'event' : 'GTM-PRODUCT-PURCHASED',                	
                	'PRODUCT_PURCHASED' : '{{item.product.title}}'
	{% endfor %}

This code will loop through all of the items purchased and inject a variable for each product purchased into the data layer. If you would like to account for a variable number of units purchased per product, simply inject an additional variable into the data layer after the PRODUCT_PURCHASED variable above and assign it the appropriate quantity via {{line_item.quantity}}. In GTM, you can then record this quantity in a Data Layer Variable and then replace the Metric value with this new GTM variable when populating the GA tag.

Once again, we’ll create a GTM variable to record the variable injected into the data layer (PRODUCT_PURCHASED in this case). 

If you happen to use apostrophes in your product titles, you’ll want to take this next step. We need to replace the encoded apostrophe values that are fed into the data layer in order for our product names to appear correctly in our GA reporting. Note that if you use other special characters, you can use the following technique as well. You’ll just need to edit the encoded html character reference to match the special character you want to replace (in our case, an apostrophe is represented as ).

We’ll replace encoded apostrophe values by creating a new GTM variable called Product Name Purchased. We’ll use the Custom Javascript Variable Type and the following code:

function() {
	var name = {{Data Layer - Product Purchased}};
	var decodeName = name.replace(/'/g, "'");
	return decodeName;

Now we create a Custom Event trigger type for our GA tag. This time we’ll use GTM-PRODUCT_PURCHASED as the Event name and set the trigger to fire when Data Layer – Product Purchased is not null. 

Just two more steps and we are done with our GTM setup. Pop over to GA and create a new custom metric for the product purchase event.

And back to GTM one more time to create the GA – Thank You Page – Product Purchased tag. Note that we are using the {{Product Name Purchased}} GTM variable that we created above instead of the {{Product Name}} GTM variable used in the product impression and add to cart tags.

For our custom metric, we’ll assume 1 unit ordered per item, but if you created an additional GTM variable to house the quantity ordered per product, you’ll use it here instead.

Before submitting the changes to your GTM container, preview it and test that all three GA tags fire correctly (GA – Product Page – Impression, GA – Product Page – Add To Cart and GA – Thank You Page – Product Purchase). If all three tags fire, you are ready to submit!


The rest of our work will take place in GA. We just need to set up two calculated metrics first before we can create our custom reports. In the Admin section of GA, under View, you will see Calculated Metrics. The first calculated metric to create will be one for Add To Cart Rate. For the Formatting Type, select Percent. For the Formula, use two of the custom metrics we created before: {{Add To Cart Event}} / {{Product Page View}}

We also need to create a calculated metric for Product Conversion Rate. For this Formula, we’ll use {{Product Purchase Event}} / {{Product Page View}}.

And now on to the custom report. This is where all our previous work comes together. For the Metric Groups, we’ll be selecting the custom metrics and calculated metrics that were previously created in GA:

  • Product Page View (custom metric)
  • Add To Cart Event (custom metric)
  • Add To Cart Rate (calculated metric)
  • Product Purchase Event (custom metric)
  • Product Conversion Rate (calculated metric)

For the Dimension Drilldowns, we will use the Product Name custom dimension we previously created.

Save it and you are all set! Apply your favorite segments to this report and you’ll be analyzing your product activity in new and truly insightful ways.


I found this post on Digital Darts to be extremely helpful when setting up GA for my Shopify sites. If you want an A+ setup, read Joshua’s guide and implement it with my product reporting hack above.

Tracking repeat customer performance in Google Analytics

UPDATE: To make your Shopify event tagging in Google Analytics even more robust and seamless, I highly recommend the Elevar service. They have a free plan to get you started on your Shopify eventing journey. Learn more >

You can’t unlock your super powers in Google Analytics until you are able to segment your site traffic in ways that will provide meaningful insights for your business. Having spent the past seven years in the startup scene for DTC brands, one of the most insightful segments I’ve applied to my GA reporting is a segment for existing customers. If you’ve been using the returning visitors segment in GA as a proxy for your existing customer behavior, I would implore you to use a better proxy! This guide should fit the bill nicely.

What follows is a step-by-step guide to how I’ve implemented this segment in GA. The intention here is not to capture and report on every existing customer that visits your site. The goal is to track a solid majority of them so that you are able to look at existing customer behavior in aggregate on your site. This is a fairly involved tutorial as we’ll be covering in depth how to use the tools that we need to make this tracking possible. In particular, if you are new to the world of Google Tag Manager, I hope this tutorial will serve as a great first introduction that will have you well on your way to leveraging its full power.

Our Tools:

  • Shopify (will also work with any ecom platform with source code access)
  • Google Tag Manager (GTM)
  • Google Analytics (GA)
  • js-cookie


First things first, let’s be sure we have a solid GA and GTM set up for Shopify. In GA, navigate to Admin > Property > Tracking Info > Tracking Code and copy the Global Site Tag (gtag.js). Now jump into Shopify and paste the code into the Google Analytics section under Preferences in the Shopify admin (Online Store > Preferences). After saving the code, you will see a link in this section to add custom javascript. Click the link and paste the following into the Additional Google Analytics JavaScript input:

new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],

Be sure to replace ‘GTM-XXXXXXX’ with your Google Tag Manager Container ID.


Now, let’s install the cookie library we’ll be using, js-cookie. You can download the library here. Click on the Raw button and then save the page from the browser as cookie.js. Upload this file to the Assets folder in Shopify and include the following code towards the bottom of the theme.liquid file (before the closing </body> tag).

{{ 'cookie.js' | asset_url | script_tag }}

That will insure our cookie library is available for us to call on every page except checkout and the thank you page after ordering. We’ll now go ahead and make sure this library is available for us to use on the thank you page. Since we do not have access to the source code for the thank you page in Shopify, we’ll need to use GTM to inject our cookie library code into the thank you page when it loads.

At a minimum, there are two components required to fire a tag in GTM: The tag itself and a trigger that fires the tag. In this case, those are the only two components needed to get our cookie library to load on the thank you page. To start with, we’ll create the tag. Under the Tag section, click New and name your tag (let’s call it cookie.js). Click into the Tag Configuration area and select the Custom HTML tag type. 

You are going to copy and paste the contents of your local version of cookie.js into the HTML field, but first you need to put an opening and closing tag into the HTML field and then paste your code. Here’s what your screen will look like with the tags added:

Now go ahead and paste the contents of your cookies.js file in between the tags. Your screen should now look like the following:

All that’s missing now is a trigger to fire this tag. Click the area on the tag called Triggering and click the + sign to create a new trigger. Let’s name the trigger Thank You Page Trigger. Select the Page View trigger type, click on Some Page Views and select Page URL for the event type and enter /checkouts/ and then thank_you in an additional Page URL event type field. We need two event types to describe the thank you page because the structure of the URL looks like:


Your configuration should like the following:

Now save your changes and you’re done. If this is your first GTM tag, congrats! You now have a tag that will fire on the thank you page after checkout.


There will be three cookies to set for our tracking purposes:

RETURNING_CUSTOMER : This cookie will be set when an existing customer returns to the site.

COMPLETED_CHECKOUT : This cookie will be set after a customer places a first order.

FIRST_TRACKED_ORDER : This is a temporary cookie that will also be set after a customer places a first order. It will help us avoid including first time customers as existing customers in our analytics. More on this later.

Now, we’re ready to begin cookie-ing our customers. the first place we’ll do so is right after they place a first order. Let’s create a new tag called Thank You Page – Set Cookies in GTM. We will use the Custom HTML tag type again and include the following code:

   (function() {
       // check if user is first time thru checkout
       if (!Cookies.get('RETURNING_CUSTOMER')) {
          Cookies.set('FIRST_TRACKED_ORDER', '1', {expires: 1});
          Cookies.set('COMPLETED_CHECKOUT', '1');

Our trigger is the same as before, when a customer lands on the thank you page, so assign this tag the Thank You Page Trigger. This code first looks to see if there is already a cookie that has been set for an existing customer. If not, then the code sets two cookies: FIRST_TRACKED_ORDER, which is set to expire in 1 day, and COMPLETED_CHECKOUT. The reason why we include the first cookie and have it expire in a day will become apparent in the next step.

We will now create a snippet that we can include in our theme.liquid file in Shopify. This snippet will contain the logic for identifying returning customers. This snippet should be included towards the bottom of your file inside the closing body tag:

   // not 'FIRST_TRACKED_ORDER'   

   if (!Cookies.get('RETURNING_CUSTOMER')) {    	
      if (!Cookies.get('FIRST_TRACKED_ORDER') &&
      Cookies.get('COMPLETED_CHECKOUT')) {
         Cookies.set('RETURNING_CUSTOMER', '1');     	

Here we can see that we will not set the RETURNING_CUSTOMER cookie if the FIRST_TRACKED_ORDER cookie is present. This prevents us from including these first time customers as existing customers if they continue to browse the site right after they place their first order. Depending on the type of good you sell and the typical delivery time, you may want to adjust the 1 day value to the number of days the customer waits before receiving a first purchase.


Our next step is to create the code that will inform GA that an existing customer is visiting the site. We will do this by pushing a variable into the GTM data layer that can be read by a GTM trigger that we’ll create. This trigger will then fire a GA Tag that we’ll set in GTM. Understanding the data layer can be a bit tricky but it is essentially just a javascript array initiated with code on your site. We then populate this container with variables to be read by GTM when certain events happen on your site. These variables in GTM can then be used to create triggers to fire tags for various services (in this case, we’ll be creating a GA tag to fire). If this isn’t entirely clear, following along with the example should help clarify the concepts involved. I have also posted some articles at the end of this post that have helped me better understand GTM.

We will begin populating the data layer by amending the snippet we just added to the theme.liquid file. Add the following code into the snippet just before the closing tag.

window.dataLayer = window.dataLayer || [];

// if RETURNING_CUSTOMER cookie present, update data layer
if (Cookies.get('RETURNING_CUSTOMER')) {
window.dataLayer.push({'DL_RETURNING_CUSTOMER': 1});

This code first initializes the data layer and then checks to see whether there is a cookie called RETURNING_CUSTOMER. If there is, we push a variable into the data layer called DL_RETURNING_CUSTOMER and give it a value of 1. This code takes care of every page except for the thank you page. Let’s tackle that next!

Once again we’ll use our GTM implementation to create a tag that contains the code we want to execute on the thank you Page. The process starts off the same way as before with us creating a Custom HTML tag. Let’s name this new tag Thank You Page – Data Layer. The code is exactly the same as the code we used above to populate the data layer. We don’t need to worry about setting a cookie on the thank you page, so the whole script will just be:

<script type="text/javascript">
  (function() {
	  window.dataLayer = window.dataLayer || [];

      // if RETURNING_CUSTOMER cookie present, update data layer
      if (Cookies.get('RETURNING_CUSTOMER')) {    
         window.dataLayer.push({'DL_RETURNING_CUSTOMER': 1});  

The tag just needs a trigger now. If your inclination is to use the existing Thank You Page Trigger we created before, you are on the right track! We just need to make two adjustments. 

First, the thank you page on Shopify after submitting an order can be accessed by the customer at any time. Our code needs to fire once and once only to mark a conversion from an existing customer. If this customer reloads/revisits this page in a future session, we would accidentally count that page load as a new conversion, thereby inflating our existing customer conversion rate. We need a mechanism to ensure that our tag to populate the data layer on the thank you page fires once only. Fortunately, Shopify has our backs here.

If you’ve ever included conversion tags in the Additional Scripts area of the checkout settings in Shopify (Settings > Checkout), you might have noticed the following liquid code:

{% if first_time_accessed %} 


{% endif %}

This code ensures that whatever is executed inside will only be executed once. Here’s the code we will insert into the Additional Scripts area:

{% if first_time_accessed %} 

<p id="GTM-PURCHASE-TRIGGER" style="color:white">GTM</p>

{% endif %}

This code will insert an invisible paragraph block on the thank you page with an id=”GTM-PURCHASE-TRIGGER”. It’s this id that our Page View – DOM Ready trigger will use as a condition to fire. All that is left is to create a GTM variable to detect the presence of this id on the page and we’ll be ready to create the trigger for our new tag.

Navigate to the Variables section in GTM and click New under the User-Defined Variables area. Let’s name the variable GTM-PURCHASE-TRIGGER. In the menu, under the Page Elements section, select DOM Element. Choose ID as the Selection Method and paste in our ID (GTM-PURCHASE-TRIGGER) in the Element ID input. Your variable should look as follows:

Second, when we fire our code to populate the data layer, we need to be sure that the thank you page loads first before the new tag is loaded. We need to do this to ensure that our new tag can detect the presence of the ID found on the thank you page. We’ll do this by using a different trigger type with a slight delay. Let’s use the Page View – DOM Ready trigger type, which will fire once the DOM loads (which occurs after the initial page view).

Let’s go ahead and add the trigger. Select Page View – DOM Ready and name the trigger DOM Ready – Thank You Page. The conditions are the same as our previous thank you page trigger except we are adding the condition that the GTM-PURCHASE-TRIGGER variable cannot be null. You will see the variable listed as a choice in the dropdown when you add a new event condition. Then type null after selecting does not equal.


So now that we are populating the data layer with a variable to signify an existing customer visiting the site, what’s left? We have to let GA know about it! Here’s what we need to create to make that happen:

  • A GTM variable that will look for presence of the DL_RETURNING_CUSTOMER variable in the data layer
  • A custom dimension in GA to represent an existing customer 
  • A Google Analytics tag in GTM which we’ll use to assign data to our new custom dimension in GA
  • A trigger in GTM to fire the tag

When creating the new GTM variable, select Data Layer Variable as the Variable Type. For the section under Data Layer Variable Name, input DL_RETURNING_CUSTOMER. Your GTM Variable should look as follows:

Now we’ll take a quick jump over to GA and create the custom dimension. In the admin section of GA, look under the Properties section for Custom Definitions. Click to expand it and then you’ll see Custom Dimensions. Create a new custom dimension using the User Scope.

After you save your new custom dimension, be sure to note its Index position. Here you can see that the index position is 6 for the User Has Previously Ordered custom dimension.

Now back to GTM where we will create the GA tag using the Google Analytics – Universal Analytics tag type. For Track Type, select Event. The Category, Action and Label fields define the event taxonomy that you’ll see in GA for this event. The taxonomy I have chosen here is User / Activity / Has Previously Ordered, but you can classify the taxonomy however you wish. Two important steps to take are to make sure the Non-Interaction Hit value is set to True and to make sure the Enable overriding settings in the tag checkbox is checked. After checking that box, you will input your Google Analytics Tracking ID. You can either store this in a GTM Variable as I have below {{GA-ID}} or input the actual tracking ID. Finally, under More Settings, expand Custom Dimensions and input the index position for your GA custom dimension (in my example, the value is 6) and enter a value of 1 for the Dimension Value. We will be able to isolate this value when creating a segment in GA for existing customers.

All that’s left here is to create the trigger to fire this GA tag. For the trigger type, select Page View – Window Loaded and have the trigger fire on Some Window Loaded Events. For the trigger event condition, select the Data Layer – Returning Customer GTM Variable you created above and have it equal a value of 1.


Alright! The hard stuff is all done. You’ve made it this far, so I think you’ll want to take this one extra step. Currently, our tracking is configured to cookie customers when they checkout so that when they return, we’ll be able to read the cookie and identify them as existing customers. Cookies don’t stick around forever though and we haven’t done anything to solve for the multiple device problem. What we need is a way to identify additional returning customers when they visit the site. We’ll do this by reading the UTM params from referring URLs and see if any are set to signify that a returning customer is visiting. If any are, we’ll go ahead and set a new RETURNING_CUSTOMER cookie if one is not already set on the user’s browser.

The code that follows can be amended to check for additional marketing channels, but the one that we will focus on here is our email marketing channel. For this code to work, you will need to tag the links in your emails to existing customers with a specific UTM_CAMPAIGN. By way of example, we will assume that the UTM_CAMPAIGN param assigned to the links in your existing customer emails is Email-Customers. Go ahead and insert the following code at the very beginning of the snippet that was inserted into your theme.liquid file (right after the opening <script> tag):

    if (isNewSession()) {

      window.UTM_SOURCE = 'UTM_SOURCE';
      window.UTM_MEDIUM = 'UTM_MEDIUM';
      window.UTM_CONTENT = 'UTM_CONTENT';
      window.UTM_TERM = 'UTM_TERM';

      // Set UTM Keys


    // Determine if this page load is the first of this session.
    function isNewSession() {
      var tuckerUrlRegex = /^https?:\/\/(w{3}.)?tuckernyc.com/;
      return !(document.referrer.match(tuckerUrlRegex));

    // Store a url parameter to sessionStorage.
    function setFromUrlParam(key) {

      var value = window.getParameterByName(key);

      if (key == "utm_source") {
        Cookies.set(UTM_SOURCE, value);

      if (key == "utm_medium") {
        Cookies.set(UTM_MEDIUM, value);

      if (key == "utm_campaign") {
        Cookies.set(UTM_CAMPAIGN, value);

      if (key == "utm_content") {
        Cookies.set(UTM_CONTENT, value);

      if (key == "utm_term") {
        Cookies.set(UTM_TERM, value);


    if (Cookies.get('UTM_CAMPAIGN')) {

    	var str_medium = Cookies.get('UTM_CAMPAIGN');
      	var CustomerEmail = str_medium.includes("Email-Customers");

      	if (CustomerEmail) {
           if (!Cookies.get('RETURNING_CUSTOMER')) {
      	      Cookies.set('RETURNING_CUSTOMER', '1');

And there you have it. Your existing customers that are visiting from email are now also being added to the existing customer cookie pool if they are not already in it. You can easily amend this code to add in additional marketing channels like retargeting to make the cookie pool even larger. The more data, the better!


YOU MADE IT! Congrats on getting your tracking installed. I know that this was a lengthy guide, but we now have a great tracking code base that we’ll continue to build upon in (shorter) future posts. Ahem….

The only thing left to do is test our installation and create a segment in GA to use in our reporting. If you want to live dangerously, I won’t stop you. Just publish your GTM container and you will be live, but I would encourage you to use the Preview feature in GTM before publishing to test your tags. The Preview feature is very powerful and will certainly come in handy for testing your future GTM container additions.

There will be two specific use cases you want to test: 1) ensuring that we are correctly cookie-ing first time customers on the thank you page and 2) ensuring that we are recognizing our existing customers when they visit from our email channel and correctly cookie-ing them. You can use a dummy landing page url with the correct UTM_CAMPAIGN included to test this. Just be sure that you delete the RETURNING_CUSTOMERS cookie first if it’s present in your browser before testing this step.

For case 1, you will need to place a test order (after clicking the Preview button in GTM of course). On the thank you page, you should see three tags that are fired and one that is not:

Now, check to make sure that the COMPLETED_CHECKOUT and FIRST_TRACKED_ORDER cookies were installed correctly on the browser. In Chrome Developer Tools, navigate to the Application tab and scroll down and expand the Cookies section under Storage. You should see:

Now visit your home page and go ahead and delete the FIRST_TRACKED_ORDER cookie. This is the temporary cookie that expires after 1 day and prevents our GA – Returning Customer tag from firing. Reload the page and voila, there it is.

Assuming that all goes well, you can publish your container to go live!

To remove the preview feature on your browser, just click the Leave Preview Mode link

In Google Analytics, creating the segment for existing customers is a breeze:

You can now apply this segment to your traffic, conversion and product reports in GA for some super-charged analysis!


Simo Ahava’s blog was essential reading for me when learning about GTM. These two articles have additional information on what we reviewed here:

Thank you Simo!

I also highly recommend the book Google Analytics Breakthrough for anyone looking to learn to become a power user of the tool.