Free AJAX Event Listener for Google Tag Manager


AJAX Event Listener in GTM Debug Panel

Our blog posts are frequently borne out of the experiences we have working with clients or on our own website. Often we’ll create a tool and think to ourselves, could others benefit from this? We created this AJAX listener for Google Tag Manager to help monitor completed requests and then fire tags appropriately, and we definitely think others will have a need for it. Give it a shot and let us know how you’re using it!

jQuery, one of the most ubiquitous JavaScript libraries in the world, offers several easy to use methods for performing AJAX requests. It also enhances these requests by emitting globally scoped events when the request starts and finishes. We’ve created a simple Custom HTML Tag that binds to these events, so we can push data about them into the Data Layer. This can be useful for triggering tags after asynchronous resources have been resolved, retrieving query parameters or headers from on-page requests, and more.

The tag will listen for $.ajax and all of its kin, including $.post, $.getJSON, $.getScript, et. al. When an AJAX request is completed, it will push details about that request into the Data Layer; here’s an example push:

The Code

This code is available freely under the MIT License. We make no guarantees of performance or reliability, and you use this at your own risk. If you do happen to see a bug or a place for improvement, please let us know in the comments.

Get It For Yourself

You can copy the above code and stick it into a script tag, or simply merge this container file with your Google Tag Manager container to import the tag and Data Layer Variables for all of the data it surfaces with each event. For instructions on how to do this, see Jim’s post detailing how to use container import.

Tell Us What You Do With It

If you use this listener, we’d love to hear about your use cases. We’ve identified a couple in this post, but please don’t hesitate to share if you’ve found another way to put this to work. As always, if you spot a bug, please let us know in the comments and we’ll fix it straight away.

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

  • Adrian Willings

    I’d love to use something like this to get blog article information out so I can use it in JSON style structured data. Is that possible using a method similar to this? I’m thinking about variables so I don’t have to get each page coded with the dataLayer but I’m out of my depth.

    • Dan Wilkerson

      Hi Adrian,

      It’s possible that you could write a Custom HTML script that scrapes out those values and pushes them into the Data Layer in a structured way. You might be able to accomplish the same thing using JavaScript Variable and DOM Element Variables, though; the bottom line is there’s a lot of flexibility in GTM!


      • Adrian Willings

        Sure is!

  • Ryan

    This is very cool! But how do you define for instance “hostname” as a user defined variable in GTM? We’ve tried all different sorts of name conventions and have not been able to get GTM to pick it up as a variable.

    • Dan Wilkerson

      Hi Ryan,

      Create a Data Layer Variable (v2) with this input:


      That should do the trick.


  • Mary French

    I am trying to utilize the AJAX listener I got from

    Goal/Tracking Purpose: :

    Track the email newsletter sign ups.

    Issue: Tag is not firing correctly – please see view here: – it seems the olny time it’s triggered is at Pageview


    If you can help – I would be much appreciative!

    Thank you very much.


  • Thanks for the share but why are you using different variables names when sending data to GTM? For example, in this example, you named the GTM variables like ‘type’ ‘url’ ‘queryParameters’ ‘pathname’ and more, but in Variables GTM you created variables with name atributes.type, attributes.url, etc. How does GTM knows that the data sent to type variable, will be assigned to atributes.type variable which you defined?


    • Dan Wilkerson

      Yes, you are correct; we updated the naming conventions in the script but I didn’t update them here. Thanks for the spot!

  • John Goodwin

    Dan – which Trigger element should be used to fire this event? My last attempt was ‘event-luna.ajaxComplete’ but that did not fire on my form. Please help. Thanks.

    • Dan Wilkerson

      Hi John,

      Your Trigger should be a Custom Event type, with the event name luna.ajaxComplete. See attached!


    • Dan Wilkerson

      Hi John,

      Your Trigger should be a Custom Event type, with the event name ajaxComplete. We revised the naming conventions and the docs are out of sync. See attached!


      • John G.

        Great. Thanks but still not getting a Tag to fire. Should my Tag be set up to UA Form Submission?

        • Dan Wilkerson

          Hi John,

          Can you verify that your form is being submitted with $.post() and not native browser functionality or non-jQuery code? A simple test is to CTRL+Click the submit button, which should open the result in a new tab, then inspect the dataLayer.


          • John G

            I am not as code savvy as many of your other respondents. This is what I am seeing pushed to Data Layer on the Submit button click. I’ve tried verifying tag by using ‘submit_button’ and other variations. Anything you see here that I should be targeting to fire Tags?

          • An Le

            Hi Mr Dan
            My page can not open a new tab when Ctrl Click. They write the code with “on click setLocation”. So, i can not colect the dataLayer b/c the page loaded. Could you help me with this case.
            Thank you in advance!
            An Le

  • llckll

    Hi Dan,

    Great script and it’s working for the most part. I have three checkboxes that use the same name. How can I modify the script so that the code captures all three values if all three checkboxes are selected?

    • Dan Wilkerson

      I would put that into a separate JS Variable and use that when the ajaxComplete event fires, instead of messing with the listener.


  • Brad Dunzer

    Dan do you think this could be used to track type-ahead/live search text? I want to track all that is typed into the box, but I don’t have a submit action and instead I have Ajax doing a live push and return of values.


    • Dan Wilkerson

      Sure, if you wanted- just be aware that you have 500 hit per session limit with Google Analytics, so a noisy query could burn through that pretty quick. You’ll want to add some throttling logic around that, I suspect.


  • I downloaded your container file and imported it into tag manger. I then created a custom event trigger and set it to gtm.formSubmit. I was able to find gtm.formSubmit by turning on the javascript console and typeing in datalayer after I submitted the form. I then created a tag for Google Analytics Universal that fired on the trigger i made.

    • Dan Wilkerson

      Hi David,

      Great! But so you know, you’re not actually using my listener at all, and you could remove it. You’re relying on the built-in form submit listener in GTM.


      • it did not start working until I instalked it and that woukd mean gtm suppors ajax now.

        • Dan Wilkerson

          Yes – GTM’s default listeners (gtm.formSubmit,, gtm.linkClick, etc) do not “work” until you’ve created at least one Trigger that uses that listener type. I’m guessing that when you imported the listener, you also then created a Trigger for Form Submits, which is causing the confusion here. You are right that the AJAX listener will allow you to hook into $.ajax calls, which may be useful, but it uses the event ajaxComplete not gtm.formSubmit.


  • Hi Dan, thank you very much for this Event Listener. It has helped me a lot on several website with Ajax forms! Thus, I’m not able to use it anymore. GTM made some UX change recently, but nothing about the tag management itself as I know? However, I used to activate the built-in “click” variables to rapidly check if GTM was working, but I saw that the gtm.Click doesn’t work if you click anywhere on a page in test mode (gtm.LinkClick still work). I was wondering if I was the only one having issues with the event listener now (It was working perfectly fine before I saw the minor change in GTM) Maybe it’s a website issues on my side but I was curious to know.
    Again, thank you for this Listener which is VERY helpful and saves me lot of time.

  • John


    I’ve got the code working, however it is sending 3 events to Google Analytics each time a form is submitted? Is there a way to ensure it only send one event per submission?

  • ECOM Catalogue

    Hi Dan,
    I have imported your container and my tag fires correctly but when ever an ajax function takes place on my website i donot see an ajaxComplete event in the debug console. How to fix that.

  • Kim

    Does this violate Googles Terms of Service for PII (geolocation)? Is collecting IPs ok? Or is it different rules with GTM?

  • Zach


    I need to save the zip code from our checkout form to the dataLayer so I can then set as a Custom Dimension for the transaction. Would utilizing this work or am I looking for something else?


  • Hi guys! I’ve been using LM Ajax Listener for GTM in order to track a Contact Form 7 form submission. Since its latest update dismissed jquery.form.js, I think that sniffing form submission using your ajax listener will be useless or even impossible. Isn’t it? Is there anyone that can help me?

  • Hi Dan —

    I have a scenario that uses a form within an iframe (the iframe includes the GTM container, and is not a cross-domain application). I’m trying to formulate a trigger that employs your listener to confirm the form’s submission. From this I hope to identify an attribute value that I can reliably use as an event trigger.

    Do you have any suggestions for applying your listener to the iframe form rather than the parent page?

    Thank you,

  • Anthony Collins

    For some reason this is no longer emitting the ajaxComplete event on two landing pages which were initially working. Has anyone else had this issue?

    I’m getting around it by manually emitting the ajaxComplete event on successful submission, but would rather the library did this for me.


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