Send Google Analytics Client ID with Contact Form 7

This guide describes how to integrate the Google Analytics Client ID with the Contact Form 7 plugin for WordPress. No additional plugins are needed, though you will need to have Google Tag Manager available on the form page. While this post focuses on Contact Form 7 and the GA client ID, more generally this is a useful technique for integrating Google Analytics with a CRM and leveraging JavaScript to retrieve and send additional values alongside form submissions.


  1. add a hidden field to your form
  2. set that hidden field to be mailed to you upon form submission
  3. extract the GA client ID and store it into a Google Tag Manager variable
  4. populate the hidden field with the GA client ID
  5. set the tag to fire on your form page


In your WordPress dashboard, edit an existing form or navigate to Contact > Add New to launch the Contact Form 7 new form template.

At the top, add a new hidden text field as follows. To make it easier to follow along, use the same code and naming conventions that you see in this post.

[hidden textarea-123 id:hidId]



Still in the Contact Form 7 settings, click the Mail tab. Add the new hidden field to the Message Body section by including this text:


This is so the contents of the hidden field automatically get emailed to you when the form is submitted.


Switching over to Google Tag Manager, navigate to Variables > User-Defined Variables > New and choose Custom JavaScript variable. Paste in the following code and Save it.  This code will extract the GA Client ID and store it in a variable so we can use it later.

  return ga.getAll()[0].get('clientId');



Navigate to Tags > New > Custom HTML Tag and paste in the following script. This will identify the hidden form field from step 1, and populate it with the client ID variable.

<script type="application/javascript">
    var hidId = document.querySelector("#hidId");
    hidId.value={{JS - GA Client ID}};



Create a trigger that fires on your contact form page, e.g. Page Path contains /contact. Window Loaded, as opposed to Page View, fires only after the entire page and all its  linked images, libraries, etc. have loaded, while the Page View trigger fires as soon as the GTM container loads. The script to grab the GA client ID needs a few moments to run, so in this case it's important to use Window Loaded trigger type.



I received some feedback that sometimes even Window Loaded isn't enough time for the client ID to be ready, so we're also going to bootstrap a delayed trigger. To do this, navigate in GTM to Tags > New > Custom HTML and paste in the following:

window.setTimeout(function() {
    event: 'delayedPageview'
}, 1500);

Set the trigger for this tag to the Window Loaded trigger from step 5, so the whole thing looks like this:


Now every time GTM's Page View - Window Loaded event fires, it will also fire off a new event called delayedPageview 1500 milliseconds (1.5. seconds) later. Add this new event into a Custom Event trigger, like this:



Return to the tag you created in step 4 and add both of the above triggers to it. This means the client ID will first be pushed into the field upon window load, and then again 1.5 seconds later. It's redundant but more reliable this way.



Following the above steps will allow you to push the GA client ID into your form. This means that you will see the user's GA client ID in the email you receive after a successful form submission, like this:


This technique can also be expanded to integrate Google Analytics with a CRM and send other JavaScript-accessible values (e.g. page title, device type, etc.) within your contact form.

45 thoughts on “Send Google Analytics Client ID with Contact Form 7”

  1. It is nice article and helping me. But can i have both GA & GTM code in same website. How to avoid the duplicate views. I not yet used GTM still now. If i use the above method, is messed up in Ga? Let me know thanks

    • GTM is a container for other tags. So if you implement GA via GTM, you would need to remove your on-page GA code to avoid double-counting.

  2. Thank you, it works nicely.... mostly!, however, Sometimes i get the email from some clients not including the Client ID, sometimes I get it having the "Undefined" and sometimes the value is blank... not sure why that happened... i tested that in Chrome, Edge and Firefox while making the hidden field visible and found the field get populated with the client ID, however, if I tested it on Firefox Private model the field don't get populated!

    • Glad it's working out for you! (mostly)
      Firefox Private mode blocks GA tracking. That means that there is no GA client ID for that user, and they won't show up in the form field or in your GA reports. Other add-ons / extensions also block tracking, so in some cases the GA client ID also won't be available. I'm not sure why you'd get an 'undefined' though, let me know if you have any more details on when that happens and I'll try to dig in a bit.

      • Thanks Ana for your reply, Didn't expect that 🙂
        I have 4 Contact 7 forms and I'm using a plugin to send the form details to a google spreadsheet after submission and to Mailchimp (If the visitor ticked that newsletter checkbox), I made the id text field visible for you under the submit button to make it easier for you to debug. Unfortunately, i couldn't get the client id of over 30% of the total submissions. I tested it and sometimes on Chrome on android phone i get "Undefined" on the text field same as many of my visitors submissions and also some my visitor get the text ID blank (not sure which browser those with blank textbox are using).

        I tried to use the same textbox ID name with all 4 forms and also tried to use different text ID for each form (ex. hidId1, hidId2 ...) and added your snippet to the tag 4 times with the different IDs but i got the same result, "blanks and undefined". and sometimes some of the forms get "undefined" and other forms work properly!
        My ultimate goal for me to collect that client ID is as the following
        After submission, the page will redirect to a page with call to action button "create a review" that has a GA event set for it, My goal is to identify the ones who didn't click on that create review button and maybe identify them in the MailChimp list or on the google sheet list so I can target them with a followup email after they receive there gift. Since Google doesn't allow to send a personal info to GA so I thought your idea could be the solution which is to collect the client ID for each email and match it with the GA data to identify which ones who didn't click on that button.

        In case if there were no solutions to make your idea more reliable do you suggest anyway to achieve my goal in a better way, maybe by updating a mailchimp mergetag for each subscriber with the result of the GA goal completation result or something like that.

        below you can find the all 4 forms

      • I checked your 4 forms and all populated correctly 100% of the time in my tests, so it's a little hard for me to troubleshoot. My best guess is that on slow connections/devices, the client ID isn't always ready by the time the form field logic runs.
        To address this, I'd test delaying when the form field gets populated. The instructions above populate the form using the trigger Page View - Window Loaded. I'd create a second, delayed trigger that pushes in the client ID a second time, in case it wasn't ready on the first attempt. You can do this as follows:
        1) create a new custom HTML tag with the following script:
        window.setTimeout(function() {
        event: 'delayedPageview'
        }, 1500);
        2) fire this new tag using the same Page View - Window Loaded trigger from step 5
        3) create a new trigger with trigger type = custom event, event name = delayedPageview
        4) add this new trigger to your original "push the client ID" tag from step 4.

        It looks a bit convoluted, but essentially it's just creating a delayed trigger 1.5 seconds after the first, and then populating the field via both the original trigger and the delayed one 1500 milliseconds (1.5 seconds) later.

        I'm not really sure about alternate methods, but please try the above and let me know how it goes.

  3. Thanks so much again for your reply and help, I have a feeling that delayed page view would solve that issue, I tried it on Android/Chrome and saw the textbox value turn after 1.5 seconds from from "undefined" to the client ID so I think that could solve the issue however i won't be certain before maybe 1-3 days to collect some real visitors submissions. I will let you know if it completely solved the issue in case you wanna update the post with that delayed page load trick.

    btw there was a small typo on your snippet... it's the apostrophe on ‘delayedPageview’ ... it should be 'delayedPageview' otherwise GTM will give an error.

    • Great, thanks for your update and for catching the delayedPageview thing, it will be useful if anyone else reads this later. I think it's an issue with how WordPress encodes characters. Please let me know how it goes, I'll update the post if it works out.

  4. Hi Ana,
    This is such a helpful article, I have used it on three websites and it has worked on two, but keeps returning undefined on another. Our website has worked perfectly, and while is built in the same way it won't work! I'm banging my head against the wall with this one, do you have ideas about why it's not working?

    • Hey Jacob, I'm glad it was useful! I checked your sites and found the difference is that the working site uses a current version of the GA tracking code, while the non-working site is running an old version of GA that was phased out 6-7 years ago. Unfortunately this method doesn't work with the legacy GA code. Is it possible for you to update your GA code to a more recent version?

    • Hi Max, the technique described here is just using standard web tech so it can work on any form. However you need to be able to edit your form fields and add GTM to your site. If Wix allows you to do that (I'm not familiar enough with Wix to know if they do or not), then you can follow the same approach shown here.

  5. Hi Ana, Thanks so much for the awesome sharing. I successfully implement it but there is one big problem I am having: Only the first form is filled and the others are not.

    Do you know how to overecome this? Thank you.

    • Hey Robert, are these forms all on the same page? In that case each form should have a different ID value, so the first can be id:hidId, the second can be id:hidId2, and so on. Then you can duplicate the 'Add GA Client ID to Form' tag for each one, editing it to match the id values above. For example, the inner part of tag #2 would read

      var hidId = document.querySelector("#hidId2");
      hidId.value={{JS - GA Client ID}};

      Everything else can stay the same. Let me know if that works for you!

  6. Hi Ana, I got generous help from FB group. Below script will work for all forms on the same page with hidden field. It is not perfect because it is better to apply to certain hidden fields not all. But I would to post here to share with you and all your readers. I love INTERNET!

    (function() {
    var cid = {{JS - GA Client ID}};
    var fields = document.querySelectorAll('input[type="hidden"]');
    fields.forEach(function(field) {
    field.value = cid;

      • Yikes, that's bad. I'm not sure how this code would stop all contact forms from working since it's a pretty simple script, but it may be creating some conflict on the page. I can't really give specific advice since it depends on your setup, but in general you can try implementing it in parts to identify which step is causing the problem, and then revise that piece (maybe with a developer's help, if you're not one yourself).

    • gclid is an ID limited to Google Ads only, used by Google to link Google Analytics with Google Ads. The client ID is much more useful as it identifies every individual user, and gets displayed by default in the User Explorer report.

      • It can be used when you want to connect data from your customer database (say your database of optins or sales) with data you've collected in GA. The client ID serves as the key that connects the two data sources.
        Or, you can check the ID of users who have contacted you through the form, and consult the User Explorer path to see their actions leading up to the form submission.

  7. Hi, I am trying to implement this with Gravity forms and I am not having any luck. I am trying to call out the hidID var in the gravity form and not having any luck. Also, when I look at the dev tools in chrome, the client ID isnt getting passed through as a value, this is what I see (I modified the selector field to be the field name of the hidden gravity form field):

    var hidId=document.querySelector("#field_2_9");hidId.value=google_tag_manager["GTM-WNNZV9Q"].macro(4);

    As you see the value populates as: google_tag_manager["GTM-WNNZV9Q"].macro(4);

    Any help would be greatly appreciated.

    • Hey Nate, sorry, I can't really tell if you're saying that the issue is you can't get the field to populate, or that the field is getting populated with the wrong value (or both). But in general, to troubleshoot cases like this, test each step and look for the point of failure. Checking GTM in preview mode, what do you see in your {{JS - GA Client ID}} variable? From what you wrote, it seems it may be populating with the wrong value, which indicates the issue may be with the script you're using to get the GA client ID. Can you please double-check that you're using the same script as above? If you can email me a link to your site and a screenshot of your tag setup, I can be a bit more specific.
      Btw, looks like the master Simo recently wrote about these macro() calls here:

      • Thank you. I have sent the email. I just saw the article Simo posted for what I am seeing, however, I am seeing the same data outside of preview mode in GTM.

  8. Hi Ana, thank you for the most useful article I've seen in a long time! I have successfully set it up to add GA clientId to cf7 WP reports. Now I am trying to add it to the event registration form on our site. We use Event Espresso. I used the same technique as before but added '[hidden textarea-123 id:hidId]' as an 'admin-only question'. The field is showing up in reports but with no value. Also I couldn't find a place to add 'ID: [textarea-123]' to the mail message, but thought that won't matter since I will export straight from WordPress.. Do you have any ideas what might be going wrong? Could it be a problem with using multiple window loaded page triggers (one for contact & one for register) but only one of everything else (all tags point to both triggers)?
    Thanks in advance for your help!

    • Hey Rob, thanks for the comment! I can't say for sure why it's not working on your page without seeing your setup, since there are many potential points of failure, but my immediate guess would be that you're using Contact Form 7 form tag syntax in a different type of form, so key elements aren't recognized. In Contact Form 7, '[hidden textarea-123 id:hidId]' creates a hidden form field with an ID of 'hidId', and then GTM looks for ID 'hidId' and populates it. How does Event Espresso handle adding IDs to form fields?

  9. *^Ignore my above responses - forgot to add my name/email^!

    Hey Ana, thanks for your quick response! I’m not sure – I feel like the problem is coming from the way I have to edit event espresso forms (there isn’t a versatile editor, just an option to add a new question with these predefined fields – Question Text, Question Label (admin-only), Admin-Only Question?, Question Type?, Min Allowed Response Size, Required Question?, Required Text) The only way I can get it to hide is to select admin only and I don’t know if this prevents it from working. I’ve trial and errored all sorts of code in all sorts of ways (variations of: document.querySelector(“#hidId”)= text; ), but I’m getting nowhere. I thought maybe I could set it as an Advanced Custom Field and somehow send it with each registration that way? I’m sorry I can’t be more specific, this is a bit over my head, but any suggestions are very much appreciated!
    Thanks again,

    • Hey Rob, the issue just seems to be that you need to add in an ID to the form field. The document.querySelector(“#hidId”) snippet won't do anything if the field itself doesn’t have an ID called hidId. This guide uses form syntax specific for Contact Form 7, so you should check the Event Espresso documentation for how to add IDs to a form field. If it doesn’t allow you to add new IDs, then use dev tools inspector to inspect the form field and see what ID is already there, and you can replace ‘#hidId’ with that ID. Hope that helps!

  10. Hey there,

    Really great post, thank you so much!

    Firstly, I am not a developer but have a little bit of GTM knowledge and this has helped me get 90% of the way so it is great and I am learning lots.

    Unfortunately I am a little stuck. I followed the instructions above filling out the contact form on this page ->

    I can see the client id pulling through on the JS - GA Client ID Variable when I debug, however, when I look at the data layer of the successful form submission I can see it as "undefined"....
    name: 'textarea-123' , value : 'undefined'

    I have the tag firing on every page view + the delay event because I will be looking to roll this out to multiple forms on multiple pages.

    Any help would be great!
    Thanks , Angus

    • Hey Angus, when I look at your site I only see GA firing through the Yoast plugin, not through GTM. Can you please make sure you're running GA through Tag Manager? If GA isn't running through Tag Manager, the script to collect the client ID won't work.

  11. Hi Ana,

    Great post btw. I am new to GTM and I tried my best but I also get the "undefined" response. However in the GTM preview mode under datalayer JS - GA Client ID I can see my clientid. So not sure what is the issue. I tried to make the field visible, so not sure if you can identify anything from here.


  12. Hi Ana,

    Thanks for this! I have a question though, with regard to the clientId; I can't find it in the cookies that are being set by Google Analytics. GTM seems to agree, as no value is injected whenever the tags run. Could the Id have been replaced since you wrote the article? And if so, should I replace it with "_ga" or "_gid"? How do I do that? Simple replace "clientId" with "_ga"?

    Thank you!

    • Hey Stu, well, anything is possible :p However this is more involved, since unlike the GA client ID, those other IDs are only available on the first page of the session. So you'd need some code to parse the landing page URL, take the query string values, and store them so that they're available when you need them.
      I don't have the code for this myself, but I think this article covers what you're looking for:
      Hope that helps point you in the right direction!

Comments are closed.