Increase Your Google Analytics Page Speed Hit Limit



It’s not much of a secret that slow-loading pages on your site decrease the chances of a visit converting. Walmart, Google, and others have released data that point to real-world impacts from sluggish page load times. Enter the Page Timings report in Google Analytics – chock-a-bloc full of actionable metrics. You can see exactly which pages on your site are loading slowly, and you can apply Segments to focus on just the traffic you’re interested in.

There’s just one catch – the data is pretty heavily sampled. By default, Google Analytics collects timing data on just 1% of users who visit your site, or 10,000 hits per day, whichever comes first. You can increase the percentage of users that are sampled, but once you hit 10,000 hits, you’ll get no more data. My colleague Samantha Barnes has written an excellent guide that fleshes out this feature toe-to-tip.

What I’m here to tell you today is that you actually can exceed the 10,000 hit limit for your page timing data. How’s that, you’re asking? By using Events, of course.

How It Works

The page timing data you see in Google Analytics isn’t being gathered by any kind of JavaScript witchcraft on the browser: they come from the Navigation Timing interface, an API exposed by modern browsers that holds data on a slew of different and important steps the browser takes on the way to rendering a page. The Mozilla Developer Network has a a great guide to this API here.

Since this interface is available to any Joe Schmoe, we, too, can use it to get data about how long our pages take to load.

Capturing The Data

You can implement this through JavaScript on your page or through Google Tag Manager. We’ve even created a Page Load Timing GTM Recipe to make your life easier!

I’ve also provided instructions below:

  1. Create a new Google Analytics Event. Fill in all the normal information, your Google Analytics Tracking ID, etc.
  2. Give it whatever Category name pleases you best, I used “Site Speed”
  3. For the Action, fill in the Variable {{Page URL}}. Either type this, or choose it from the lego dropdown box.
  4. For the label, click the Variables drop down and choose Create a new Variable.
  5. Select the Variable type Custom JavaScript and paste the below into the field:

  1. Finally, select ‘True’ for the Non-Interaction Hit field. We’ll be firing this automatically and we don’t want this to artificially affect our bounce rate.

In the end, your Event should look something like this:

Once you’ve got that configured, you’ll need to create two Triggers – one to fire the tag, and another to block it when the API isn’t available. The firing Trigger is super simple – we’ll just use the built-in Window Load Pageview Type:

Next, we’ll need to create our blocking trigger; it should look like this:

Why Not Custom Metrics?

Custom Metrics are a great choice! If you’d like to gather the same metric in a Custom Metric, or pull out additional Timing API data and plug it into Events there, be my guest. The reason I’m recommending an Event here is that we need to fire the Event on window.load, which can come well after we’d like to send a Pageview, and thus we have to fire a second hit – so why not just use that hit for our data. If you’ve already got an Event firing on every pageview, you can just use a Custom Metric instead.

Keep in mind that adding this Event will effectively double the hits you’re generating; if you’re running close to that 10 million hit limit on a monthly basis, you should sample this hit, either through the sampleRate Field To Set or another Blocking Exception like the Blocking Trigger #7 Jon Meck outlines here.

So What Does This Do For Me?

Using your page speed timing data, you can learn which pages of your site are taking an abnormally long time to load. By sorting first by the Label, you can drill into just the pages that are going over a certain threshold, e.g. 2.0 seconds or higher, and begin to investigate why they’re not up to snuff. If you want to be really fancy, try the new Histogram Buckets feature in version four of the Core Reporting API. Some additional tools that will help you along your way:

  •, which allows you to run up to 9 simultaneous loads of a page and returns a handy waterfall of the results
  • PageSpeed Tools, which provide concrete recommendations on how to improve the performance of your pages
  • Chrome’s Timeline Tool, found in the developers console

Armed with your data and these tools, you can drastically improve the performance of your site (and hopefully your conversion rate, too).

Any questions? Sound off in the comments below.

Dan Wilkerson is a former LunaMetrician and contributor to our blog.

  • When i set this up in analytics i just get “-1470064037.4” in the event label column

    • make sure you have set your trigger to fire on ‘window loaded’, should be golden!

  • Dmitri Ilin

    Hi, Dan,

    thanks for the article. Probably, using the following variable to determine page load time with NT API could be a better option:

    var result = ‘not available’, event = {{Event}};
    var performance=window.performance||window.webkitPerformance||window.msPerformance||window.mozPerformance;
    if (event === ‘gtm.load’ && !!performance) {
    var timing = performance.timing;
    result = Math.round((timing.loadEventStart – timing.navigationStart) / 100) / 10;
    return result;

    Thus, there’s no need to create the second “blocking” trigger. Instead, we can use a single trigger like this:

    Custom Event
    Event name equals gtm.load AND Page Load time does not equal not available

    And why can’t we use user timings instead of events?

    • Dan Wilkerson

      Hi Dmitri,

      That’s a totally valid way to do it. I generally prefer using separate variables for separate tasks because it makes things more obvious to the outside observer and I have often had to decompose variables like that later on when another tag needs the same functionality. It all comes down to preference and needs!

      Per your second question, User Timings are capped at 10k hits per day (a bit of an oversimplification, but accurate), just like our Page Speed Timings. Events have no such cap and provide pretty much the same functionality.


  • Thanks guys, I’ve installed this one and comparing it against developer tools, it’s consistently just a bit below the load time being reported in developer tools… would be good to understand what exactly this is measuring.

  • bhudga

    How do you associate the “Events” Events numbers to the page load time? Events tied to users (cookies)?

  • John Samaris

    Hi Dan!,

    Maybe you can help with following two doubts regarding this implementation:

    a) I am having a hard time reconciling the number of total events of this type (to track page load times) vs number of page views reported by Google Analytics over the same period (i.e. per day).
    It seems that I have way more page views than number of events recorded for page load times.

    Any thoughts on why? I can maybe discount some off from people running anti-spam filters on their browsers but still.

    b) Using the javascript you provided above I do get some events with negative label values and high values. Could this be related to the navigation timing formula?

    Would this not work better? (taken from other sites)

    var startTime = performance.timing.redirectStart ||
    performance.timing.fetchStart ||
    var endTime = performance.timing.domContentLoadedEventEnd ||
    performance.timing.domInteractive ||
    performance.timing.domComplete ||

    if (startTime && endTime && (startTime < endTime)) {
    return (endTime – startTime);

    Thanks for your help!

    • Dan Wilkerson

      Hi John,

      a) How big is the discrepancy? Older browsers don’t support the performance APIs. If the difference is small, it might be those. If resources are hanging and never loading, the window.load event wouldn’t fire and the hit is never sent. Could be either of those.

      b) Make sure your hit is firing on window.load and add the blocking trigger to prevent accidental negative values. Per the script you provided, those are all timings for different events; DOMContentLoaded will end a lot sooner than window.load will fire, in some circumstances. I wouldn’t switch to that.

      • John Samaris

        Hi Dan,

        a) If I query GA for number of pageviews today I get: 135,608
        If I query GA for total number of events (ga: totalEvents) filtered by ga:eventCategory==Site Speed (the event I created to track page load times) I get: 63,623

        It’s more than half difference!

        I find it strange that we have this difference due just to cases of users blocking TAG manager / using older browsers.
        Even if I could the total number of events for labels with unusual numbers (i.e. negative numbers of higher than 1520000000 I only get like 152)

        BTW, what I am doing to determine the number cases per label (i.e. number of times a page loaded with a specific timing such as 2.3 seconds), is querying Google Analytics for:

        – Metric: ga:totalEvents
        – Dimension: ga:eventLabel
        – Filter ga:eventCategory==Site Speed

        This is correct, right?

        b) OK, thanks
        My trigger is configured as trigger type: “Page View – Window Loaded”

        • Dan Wilkerson

          Check to ensure that you’re not sending page views via another tag or on-page code. If users were blocking GTM or GA, you shouldn’t be getting page views, either. It sounds like you’ve got a duplicate page view tag somewhere; that’s almost exactly double.

          That query looks fine to me.

          • John Samaris

            Not sure I understood.

            You think the value reported by ga:pageviews metric is wrong?
            Or your saying that maybe there is code that is causing some pages to be counted twice for the ga:pageview metric?

            Tag manager for this site has many tags configured with triggers of type “page view” but only one tag has a trigger of type “Page View – Window Loaded” (the Site Speed one).

            However it is true (maybe this is what you are asking) that there is one tag configured like this:

            Tag Type: Universal Analytics
            Track Type: Pageview
            Trigger. All pages

            I don’t know the history of this tag but could the intention of this tag be to accurately track the total number of pages instead of delegating this to the normal Google Analytics page view tracking mechanism.

            Even if it were, why would it be so off from the page load time events which is also being tracked from Tag Manager.

          • Dan Wilkerson

            That tag you mentioned is your page view tag; it fires on every page right when GTM loads and records a page view in Google Analytics. The timing tag fires an event when the window.load event occurs.

            Ideally, these should be nearly identical, since each should only fire once every time a user loads the page; however, if there exists a second tag similar to or exactly like the page view tag you found, either in Google Tag Manager or embedded on the page in the source code, Google Analytics will be sent two page view when the user loads the page. This is a common implementation problem, and usually occurs because someone left an old-fashioned hard-coded hit in the somewhere or because the page view tag is duplicated in the container.

            I’d check that the other tags with the Page View trigger don’t send hits to the same UA number. Another sign that this is the issue is the bounce rate will be very, very low.

          • Dan Wilkerson

            This could also happen if you have other page view tags that are valid but fire on events other than ‘Page View’, e.g. SPA.

          • John Samaris

            We might be getting somewhere 🙂

            The bounce rate as stated in Google Analytics->Audience->Bounce Rate was 0,30% yesterday and today it is around 0,90% so very low.

            Some strange things which might match with your helpful hints:

            1. Source code of the page under the has:

            (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),

            ga(‘create’, ‘UA-XXXXXXXX-1’, ‘auto’);

            //If _gaManaged is true, the page should manage Google Analytics manually.
            if((typeof _gaManaged) == “undefined” || !_gaManaged)
            ga(‘send’, ‘pageview’);

            I have no idea what this last bit is but as you mentioned it might be an old piece of implementation left behind that was not cleared.

            I have no idea what the gaManaged variable is but with chrome F12 debugger I can see it is sending this pageview!

            2. In total with have (in tag manager) around 30 or so tags but most are tracking page views towards Facebook (with type custom HTML) and others are running special code for other marketing toolkits, adwords and conversion linker and one is tracking clicks on a button and registering a event,

            I don’t see anything suspicious there so I am thinking it might be script in the Head doing the damage.

            3. I don’t know if this is normal but the Tag Manager tag that is registering page views, under advanced settings there is a box called “Tag firing options” and it is set to “Once per event”. Shoud it not be set to “Once per page” or this is fine?

            Thanks for your invaluable help so far by the way!

          • Dan Wilkerson

            Yeah, thats almost certainly the culprit – get that out of there and your numbers should line up again. No need to adjust the Tag setting in GTM!

          • John Samaris

            Excellent! Thanks for you amazing help!

  • Katie

    Thanks for the post. I built this following all the steps properly and everything was pulling in great, but it was double counting my sessions. Can you explain why this is happening? I understand that it’s sending another hit, but that hit shouldn’t result in another session counted.

  • Alriksson

    If I want to change the sample of 1% does this event solves that? If now what do I need to change? or do i need to do that manually but the: _gaq.push([‘_setSiteSpeedSampleRate’,X]); ?

  • John Samaris

    Hi Dan,

    I again ask for your help interpreting what is occuring with my Tag Manager setup.
    My setup in tag manager was done following your guide on this page but I am having the following problems:

    1. I am getting way too many hits registered as “(not set)”.
    i.e. yesterday (start-date ->end-date=yesterday) the total events registered was 142,452 and (not set) ones was 135,891!

    My interpretation of “(not set)” is that it was not possible to collect data for that page view.

    I can understand that some browsers do not support the navigation timing API and that many users have content filters/ad-blockers installed that many don’t allow TM data to be collected, however I was not expecting the (not set) value to be so high.

    Is there any change to the javascript function that can be done to correct this?

    2. The blocking trigger I have does not seem to filter out all the negative values.
    The setup, in the triggers section of Tag manager, that I have is:

    Name: Blocking – Page Load Time less than 0
    EventType: Custom Event
    Filter: Page Load Time less than 0
    Tags: 0

    Inside the trigger, I have:
    Event Name: .
    Use regex matching: Checked

    What could be wrong?

    Many Thanks

    • John Samaris

      One additional note regarding point 1)

      I was looking back on the data provided by Tag Manager and it seems that the quantity of “(not sets)” was very low (in the order of the hundreds) and suddenly it increased massively!

Contact Us.

Follow Us



We'll get back to you
in ONE business day.
Our Locations
THE FOUNDRY [map] LunaMetrics

24 S. 18th Street
Suite 100

Pittsburgh, PA 15203


4115 N. Ravenswood
Suite 101
Chicago, IL 60613


2100 Manchester Rd.
Building C, Suite 1750
Wheaton, IL 60187