Google Analytics 4 Setup for Online Marketplace

Documenting some setup steps I went through and decisions I made when setting up GA4 for an online marketplace I'm running.

About the app

8+ domains

It's a marketplace for English-speaking home & office cleaning services, available in 7 countries, launched in September 2016. Each country has its local domain (, etc). There is also a "global" page listing all available countries (, and some "coming soon" websites on local domains in locations we're planning to launch in.

CMS and a web app

We use separate, per-country installations of Statamic CMS for marketing/sales pages, and have a single Laravel-based app for our booking form, transactional pages, admin panel, cleaner (service provider) dashboard, and customer dashboard. Simpler "coming soon" and "global" pages are static pages generated with Tighten Jigsaw.

Where we are coming from: Our Universal Analytics (GA3) setup.

Before co-founding our marketplace, I worked as a Business Intelligence analyst and had some exposure to how things could be set up on the marketing end. Since there are no universal rules for setting your tracking systems, I replicated what I knew. I decided to go for separate Google Analytics accounts, one for each country. Each country has 1 property, and 2 views (filtered and unfiltered). We also have a separate account for the "global" page. Traffic to "coming soon" pages has not been tracked at all. Having things separate sounded like a good idea initially, because it was consistent with what we had in Google Search Console and Google Ads. I also thought we could franchise one of the countries, and it would make the "handover" of Analytics easier (I don't know why it seemed important to me at that time).

The above setup turned out to be much more of a hassle than it was worth it. Some of its downsides:

  • Hard to analyze data, where you need to constantly switch between 8 different accounts

  • Lots of "referral exclusion" rules to set up and "copy-paste" between accounts

  • Making any change to the account sounds like a "big deal", since it needs to be replicated in all places

  • Hard to make comparisons between countries, where everything is isolated and treated individually.

Migration to GA4?

Before digging into GA4, I assumed that we would need to "migrate" the previous setup, and that we would end up replicating GA3 setup for GA4. I thought that migrating the historical data was something important. This was quite a misconception. After doing some research into GA4, I realized that while you can migrate some of the account/property settings from GA3 to GA4, you can't migrate the data. The data is going to stay in GA3 anyway. I thought it was a good opportunity for a "fresh start".

Decision #1: One account/property per country or "all in one place"

Instead of creating separate accounts for each country, I decided to use one property for all of them. It was pretty easy and only required copy-pasting one "Google tag" across all CMS installations, and on our backend app.

One thing that tripped me up here was not realizing that I still had to set the referral exclusions for our different domains (e.g., In GA4 it is called "Listing unwanted referrals".

Decision #2: Do we keep traffic from cleaners and customers together?

Initially, I just set up a single tag for our app. It was included in all views, except for the admin panel. With a couple of days of traffic, I realized that it doesn't really make sense to keep the data from customers and cleaners together. When it comes to customers, we're interested in how they reach us, and what leads them to book the cleaning. Reports on customer traffic need to be checked very frequently, daily or more often. With cleaners, we want to see how they interact with their dashboards, and the source is not important. Analyzing existing cleaner traffic is something that can be done on a weekly or monthly basis, where we make decisions on how to change/improve their dashboard.

I could split that data using filtered reports, but I don't think we'll ever need to combine that data, and conversion and any custom dimensions/properties for these 2 groups will remain different. It makes more sense to keep things separate. They still live within one "" account, but have separate properties: "GA4 - Customers" and "GA4 - Providers". Within our Laravel app, on views for cleaners, I replaced the "GA4 - Customers" tag with "GA4 - Providers" one.

Decision #3: What to do with Developer traffic

In our GA3 setup, we filtered out development traffic at the view level using filters defined for specific hostnames I used at my local dev setup and the staging domain.

In GA4, since we have one property for all markets, I decided to create a separate property for developer traffic. Instead of using filters to catch it, I dynamically set the "measurement id" in the Google Tag based on the app environment, as in:

    <!-- Google tag (gtag.js) -->
    <script async src="{{ config('app.ga4.customers_measurement_id') }}"></script>
        window.dataLayer = window.dataLayer || [];
        function gtag(){dataLayer.push(arguments);}
        gtag('js', new Date());

        gtag('config', "{{ config('app.ga4.customers_measurement_id') }}");

There's also a "Developer traffic" filter from Google Analytics, but for the time being, I decided not to use it. Having a "sandbox" GA4 property to play around with and test things out is pretty helpful regardless. I also think it's more practical to see the data as they would appear in "production" GA4, without relying only on "debug" view.

Decision #4: How do we filter out internal traffic

IP-based internal traffic exclusion doesn't work in our case, as pretty much all team members work from different locations (home, coworking space, office, cafes, airports, etc.). We filter our internal traffic by setting up a cookie that is placed on team-members machines when they log-in to the admin dashboard.

In GA3, we used the cookie to set a custom dimension via Google Tag Manager, and then used a View Filter to exclude these visits.

In GA4, we use the Internal Traffic filter. Google doesn't give us much flexibility here: if we don't want to rely on IP-based exclusion, we need to send traffic_type=internal with every event. To do this, we add that parameter to config command in gtag() function as described here.

<!-- Google tag (gtag.js) -->
<script async src=""></script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());

gtag('config', 'G-XXXXXXXXXX', {
  'traffic_type': "{{ config('app.ga4.traffic_type') }}"

The ga4.traffic_type config value is set in the middleware of our app based on the cookie value.


There's no one "best" Google Analytics 4 setup for a more complex business, like an online marketplace available in a few countries. The technical side of the setup was much easier than I expected. What was difficult, was making the decisions outlined above. It's still an experiment, and time will tell if they are good for the business. Luckily, traffic data is not something that you need to store for years. It's something that remains relevant for a year or so and is useful for making short-term decisions. If I messed something up, we can always adjust along the way and get the data in the shape the business needs.