{"id":93590,"date":"2025-02-17T12:27:09","date_gmt":"2025-02-17T12:27:09","guid":{"rendered":"https:\/\/peraltafinancing.com\/analytics\/improve-google-analytics-bot-detection-with-recaptcha\/"},"modified":"2025-02-17T12:27:09","modified_gmt":"2025-02-17T12:27:09","slug":"improve-google-analytics-bot-detection-with-recaptcha","status":"publish","type":"post","link":"https:\/\/fivemor.com\/?p=93590","title":{"rendered":"Improve Google Analytics Bot Detection With reCAPTCHA"},"content":{"rendered":"<p> <br \/>\n<\/p>\n<div>\n<p>There are thousands upon thousands of bots, crawlers, spiders, and other creepy-crawlies out there doing nothing but crawling through websites and harvesting the content within for whatever purposes they have been fine-tuned to. While <a href=\"https:\/\/analytics.google.com\/\">Google Analytics<\/a> provides <a href=\"https:\/\/support.google.com\/analytics\/answer\/1010249?hl=en\">a bot filtering feature<\/a> to filter out \u201cspam\u201d and \u201cbot traffic\u201d from views, this is far from comprehensive enough to tackle all instances of bot traffic that might enter the site.<\/p>\n<div style=\"aspect-ratio: 1634 \/ 502;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2019\/09\/bot-traffic-in-ga.jpg\" title=\"Bot traffic in GA\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"502\" width=\"1634\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2019\/09\/bot-traffic-in-ga.jpg#ZgotmplZ\" alt=\"Bot traffic in GA\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>You might have noticed bot traffic in your data even if you have bot filtering toggled on. For instance, such traffic could be characterized as follows:<\/p>\n<ul>\n<li>Traffic without a discernible source\/medium<\/li>\n<li>Average Session Duration under\n<\/li>\n<li>Same \/ outdated user agent<\/li>\n<li>Non-converting traffic \/ high bounce rate<\/li>\n<li>Network location a known cloud host (e.g. AWS)<\/li>\n<\/ul>\n<p>Luckily, there are better ways to identify this traffic than looking at noisy Google Analytics data. Google has introduced <a href=\"https:\/\/developers.google.com\/recaptcha\/docs\/v3\">reCAPTCHA v3<\/a> which lets you verify traffic without any user interaction required. This is done with a simple JavaScript API combined with a server-side verification endpoint.<\/p>\n<div style=\"aspect-ratio: 980 \/ 752;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2019\/10\/recaptcha-bot-traffic.jpg\" title=\"reCAPTCHA bot traffic\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"752\" width=\"980\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2019\/10\/recaptcha-bot-traffic.jpg#ZgotmplZ\" alt=\"reCAPTCHA bot traffic\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>In this article, <strong>Sebastian Pospischil<\/strong> and <strong>Philipp Schneider<\/strong> from <a href=\"https:\/\/www.resolutionmedia.com\/\">Resolution Media<\/a> will share the solution with you. They\u2019ll show you how to build a simple PHP API on your Apache web server to handle the requests from reCAPTCHA.<\/p>\n<div style=\"aspect-ratio: 1249 \/ 629;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2019\/10\/phil-sebastian.jpg\" title=\"Philipp Schneider and Sebastian Pospischil\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"629\" width=\"1249\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2019\/10\/phil-sebastian.jpg#ZgotmplZ\" alt=\"Philipp Schneider and Sebastian Pospischil\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>I\u2019ll contribute by building the same thing with <strong>Node.js<\/strong>. Remember that you can have both (Apache and Node.js) running in <a href=\"https:\/\/cloud.google.com\/\">Google Cloud<\/a> using e.g. the <a href=\"https:\/\/cloud.google.com\/appengine\/docs\/standard\/runtimes\">App Engine<\/a> standard environment. This is helpful if you do not have the resources or capabilities to run something like this on your own web servers.<\/p>\n<p>Huge thanks to Philipp and Sebastian for sharing this nugget of wisdom with this blog!<\/p>\n<p>                <span class=\"simmer\"><br \/>\n  <span class=\"close\">X<\/span><\/p>\n<p>\n    <span class=\"fa fa-md fa-bell\"\/><br \/>\n    <strong>The Simmer Newsletter<\/strong>\n  <\/p>\n<p>\n    Subscribe to the <a href=\"https:\/\/www.simoahava.com\/newsletter\/\">Simmer newsletter<\/a> to get the latest news and content from Simo Ahava into your email inbox!\n  <\/p>\n<p>  <\/span><\/p>\n<h2 id=\"getting-started\">Getting started<\/h2>\n<p>To start with, you\u2019ll need to generate a (free) <strong>site key<\/strong> and a (free) <strong>secret key<\/strong> for your reCAPTCHA API use. Head on over to <a href=\"https:\/\/www.google.com\/recaptcha\/admin\/create\">https:\/\/www.google.com\/recaptcha\/admin\/create<\/a>, and register a new site to use with reCAPTCHA v3. Make sure you enter all the domains from which these verification requests will be sent.<\/p>\n<div style=\"aspect-ratio: 765 \/ 707;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2019\/09\/enable-recaptcha.jpg\" title=\"Enable reCAPTCHA\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"707\" width=\"765\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2019\/09\/enable-recaptcha.jpg#ZgotmplZ\" alt=\"Enable reCAPTCHA\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Once you\u2019ve added everything and checked all the necessary boxes, click <strong>SUBMIT<\/strong> to get your keys.<\/p>\n<div style=\"aspect-ratio: 791 \/ 535;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2019\/09\/register-keys.jpg\" title=\"register keys\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"535\" width=\"791\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2019\/09\/register-keys.jpg#ZgotmplZ\" alt=\"register keys\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Copy the keys, as you\u2019ll need them soon when configuring the Custom HTML tag in <a href=\"https:\/\/tagmanager.google.com\/\">Google Tag Manager<\/a> as well as the server-side endpoint.<\/p>\n<h2 id=\"php-endpoint\">PHP endpoint<\/h2>\n<p>In this chapter, Philipp and Sebastian will walk you through the steps of creating a PHP endpoint for verifying the reCAPTCHA requests. They\u2019ll also show you how to create the Custom HTML tag in Google Tag Manager for loading the reCAPTCHA JavaScript API and ascertaining the \u201cbot-ness\u201d of the user.<\/p>\n<h3 id=\"custom-html-tag\">Custom HTML tag<\/h3>\n<p>First things first &#8211; let\u2019s setup Google Tag Manager. In GTM, create a new <strong>Custom HTML Tag<\/strong>.<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-html\" data-lang=\"html\">style&gt;\n  <span style=\"color:#aaa;font-style:italic\">\/* hides the recaptcha badge *\/<\/span>\n  .<span style=\"color:#0a0;text-decoration:underline\">grecaptcha-badge<\/span> {\n    <span style=\"color:#00a\">visibility<\/span>: <span style=\"color:#00a\">hidden<\/span> <span style=\"color:#4c8317\">!important<\/span>;\n  }\n<span style=\"color:#1e90ff;font-weight:bold\">style<\/span>&gt;\nscript <span style=\"color:#1e90ff\">src<\/span>=<span style=\"color:#a50\">\"https:\/\/www.google.com\/recaptcha\/api.js?render=_reCAPTCHA_site_key_\"<\/span>&gt;<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;\nscript&gt;\n  grecaptcha.ready(<span style=\"color:#00a\">function<\/span>() {\n    grecaptcha.execute(<span style=\"color:#a50\">'_reCAPTCHA_site_key_'<\/span>, {\n      action: <span style=\"color:#a50\">'homepage'<\/span>\n    }).then(<span style=\"color:#00a\">function<\/span>(token) {\n      <span style=\"color:#00a\">var<\/span> xhr = <span style=\"color:#00a\">new<\/span> XMLHttpRequest();\n      xhr.onload = <span style=\"color:#00a\">function<\/span>() {\n        <span style=\"color:#00a\">if<\/span> (xhr.response !== <span style=\"color:#a50\">'noChange'<\/span>) {\n          <span style=\"color:#00a\">var<\/span> greResult = JSON.parse(xhr.response);\n          <span style=\"color:#0aa\">window<\/span>.dataLayer.push({\n            event: <span style=\"color:#a50\">'recaptcha'<\/span>, \n            recaptchaAnswer: greResult.success,\n            recaptchaScore: greResult.score\n          });\n        }\n      };\n      xhr.open(<span style=\"color:#a50\">'POST'<\/span>, <span style=\"color:#a50\">'\/gtm\/recaptcha.php'<\/span>, <span style=\"color:#00a\">true<\/span>); <span style=\"color:#aaa;font-style:italic\">\/\/replace this with URL to your PHP fil\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>      xhr.setRequestHeader(<span style=\"color:#a50\">'Content-type'<\/span>, <span style=\"color:#a50\">'application\/x-www-form-urlencoded'<\/span>);\n      xhr.send(<span style=\"color:#a50\">'token='<\/span> + token + <span style=\"color:#a50\">'&amp;action=homepage'<\/span>);\n    });\n  });\n<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;<\/code><\/pre>\n<\/div>\n<p>You can set this tag to fire on whatever trigger you wish, though a trigger that fires when the page loads (e.g. All Pages, DOM Ready, or Window Loaded) is recommended.<\/p>\n<p>Make sure you edit the following:<\/p>\n<ul>\n<li>The <code>_reCAPTCHA_site_key<\/code> string on lines 7 and 10 with the actual <strong>site key<\/strong> you copied from the reCAPTCHA admin console in the previous chapter.<\/li>\n<li>The URL of your PHP endpoint on line 24.<\/li>\n<\/ul>\n<p>This block of code runs the reCAPTCHA JavaScript API in the user\u2019s browser, and sends the tokenized result to the PHP endpoint you\u2019ll configure in the next chapter. When it gets a response, the score and success state are pushed into <code>dataLayer<\/code>.<\/p>\n<div style=\"aspect-ratio: 280 \/ 96;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2019\/09\/recaptcha-badge.jpg\" title=\"reCAPTCHA badge\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"96\" width=\"280\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2019\/09\/recaptcha-badge.jpg#ZgotmplZ\" alt=\"reCAPTCHA badge\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>The very first code block in the tag hides the reCAPTCHA badge from showing up on the site. <a href=\"https:\/\/developers.google.com\/recaptcha\/docs\/faq#id-like-to-hide-the-recaptcha-badge.-what-is-allowed\">Remember to read this part of the FAQ<\/a> to learn how to modify your site to allow the hiding of the badge.<\/p>\n<h3 id=\"php-file-for-your-server\">PHP file for your server<\/h3>\n<p>Create a file <code>recaptcha.php<\/code> with the following code, and upload it to all the domains you wish to validate reCAPTCHA requests on. Place it in a subdirectory named <code>\/gtm\/<\/code>.<\/p>\n<blockquote>\n<p><strong>NOTE!<\/strong> You can use whatever path and filename you want for the PHP file &#8211; just remember to update the Custom HTML tag\u2019s HTTP request endpoint URL accordingly.<\/p>\n<\/blockquote>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-php\" data-lang=\"php\"><span style=\"color:#4c8317\"><?php <\/span?>\n\t<span style=\"color:#aaa;font-style:italic\">\/\/ reCaptcha info\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#a00\">$url<\/span> = <span style=\"color:#a50\">'https:\/\/www.google.com\/recaptcha\/api\/siteverify'<\/span>;        \n    <span style=\"color:#a00\">$secret<\/span> = <span style=\"color:#a50\">\"_reCAPTCHA_secret_key_\"<\/span>;\n\t<span style=\"color:#a00\">$remoteip<\/span> = <span style=\"color:#a00\">$_SERVER<\/span>[<span style=\"color:#a50\">'REMOTE_ADDR'<\/span>];\n\t<span style=\"color:#aaa;font-style:italic\">\/\/ Form info\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>\t<span style=\"color:#a00\">$action<\/span> = <span style=\"color:#a00\">$_POST<\/span>[<span style=\"color:#a50\">'action'<\/span>];\n\t<span style=\"color:#a00\">$response<\/span> = <span style=\"color:#a00\">$_POST<\/span>[<span style=\"color:#a50\">'token'<\/span>];\n\t<span style=\"color:#aaa;font-style:italic\">\/\/ Botscore\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>\t<span style=\"color:#a00\">$botscore<\/span> = <span style=\"color:#a00\">$_COOKIE<\/span>[<span style=\"color:#a50\">'_rbs'<\/span>];\n\n\t<span style=\"color:#aaa;font-style:italic\">\/\/ Curl Request\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>\t<span style=\"color:#a00\">$curl<\/span> = curl_init();\n\tcurl_setopt(<span style=\"color:#a00\">$curl<\/span>, CURLOPT_URL, <span style=\"color:#a00\">$url<\/span>);\n\tcurl_setopt(<span style=\"color:#a00\">$curl<\/span>, CURLOPT_POST, <span style=\"color:#00a\">true<\/span>);\n\tcurl_setopt(<span style=\"color:#a00\">$curl<\/span>, CURLOPT_RETURNTRANSFER, <span style=\"color:#099\">1<\/span>);\n\tcurl_setopt(<span style=\"color:#a00\">$curl<\/span>, CURLOPT_POSTFIELDS, <span style=\"color:#00a\">array<\/span>(\n\t\t<span style=\"color:#a50\">'secret'<\/span> =&gt; <span style=\"color:#a00\">$secret<\/span>,\n\t\t<span style=\"color:#a50\">'remoteip'<\/span> =&gt; <span style=\"color:#a00\">$remoteip<\/span>,\n\t\t<span style=\"color:#a50\">'action'<\/span> =&gt; <span style=\"color:#a00\">$action<\/span>,\t\t\n\t\t<span style=\"color:#a50\">'response'<\/span> =&gt; <span style=\"color:#a00\">$response<\/span>\n\t));\n\t<span style=\"color:#a00\">$curlData<\/span> = curl_exec(<span style=\"color:#a00\">$curl<\/span>);\n\tcurl_close(<span style=\"color:#a00\">$curl<\/span>);\n\t<span style=\"color:#a00\">$curlJson<\/span> = json_decode(<span style=\"color:#a00\">$curlData<\/span>, <span style=\"color:#00a\">true<\/span>);\n\t\n\t<span style=\"color:#aaa;font-style:italic\">\/\/defining the answer\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>\t<span style=\"color:#a00\">$answer<\/span> = <span style=\"color:#a00\">$curlData<\/span>;\n\t\n\t<span style=\"color:#aaa;font-style:italic\">\/\/refresh the cookie\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>\tsetcookie(<span style=\"color:#a50\">'_rbs'<\/span>, <span style=\"color:#a00\">$curlJson<\/span>[<span style=\"color:#a50\">'score'<\/span>], time()+<span style=\"color:#099\">1800<\/span>, <span style=\"color:#a50\">'\/'<\/span>,<span style=\"color:#a50\">''<\/span>, <span style=\"color:#099\">0<\/span>); \n\t\n\t<span style=\"color:#aaa;font-style:italic\">\/\/ only fire $answer if botscore cookie is not set or different from acutal score\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>\t<span style=\"color:#00a\">if<\/span> (<span style=\"color:#a00\">$botscore<\/span> != <span style=\"color:#a00\">$curlJson<\/span>[<span style=\"color:#a50\">'score'<\/span>]) {\n\t\t<span style=\"color:#00a\">echo<\/span> <span style=\"color:#a00\">$answer<\/span>;\n\t} <span style=\"color:#00a\">else<\/span> {\n\t\t<span style=\"color:#00a\">echo<\/span> <span style=\"color:#a50\">\"noChange\"<\/span>;\n\t}\n<span style=\"color:#4c8317\">?&gt;<\/span>\n<\/span><\/code><\/pre>\n<\/div>\n<p>Again, make sure you replace the <code>_reCAPTCHA_secret_key<\/code> on line 4 with the <strong>secret key<\/strong> you got from the admin console.<\/p>\n<p>This PHP code takes the response sent by Google Tag Manager, validates it against the reCAPTCHA verification API, and then sends the result object in the response, which will, in turn, be pushed into <code>dataLayer<\/code> for your tags to use.<\/p>\n<p>The code also writes a cookie in the HTTP response. This cookie is named <code>_rbs<\/code> and contains the score of the reCAPTCHA action. The results are only returned if the reCAPTCHA score has changed in the last 30 minutes. If the results have not changed, the response will be <code>\"noChange\"<\/code>, which blocks the <code>dataLayer.push()<\/code> from taking place.<\/p>\n<h2 id=\"nodejs-endpoint\">Node.js endpoint<\/h2>\n<p>In this chapter, Simo will show you how to do the same as above by using a <a href=\"https:\/\/www.nodejs.org\/\">Node.js<\/a> application instead.<\/p>\n<h3 id=\"custom-html-tag-1\">Custom HTML tag<\/h3>\n<p>The main difference (apart from the tech stack) to the PHP solution is that we\u2019ll log errors as well. They are sent as the value of the <code>recaptchaScore<\/code> key in <code>dataLayer<\/code>, so in your report you\u2019ll end up with a mix of valid scores and error texts, but this should be easy to filter in your tables.<\/p>\n<p>This is what the Custom HTML tag looks like:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-html\" data-lang=\"html\">style&gt;\n  <span style=\"color:#aaa;font-style:italic\">\/* hides the recaptcha badge *\/<\/span>\n  .<span style=\"color:#0a0;text-decoration:underline\">grecaptcha-badge<\/span> {\n    <span style=\"color:#00a\">visibility<\/span>: <span style=\"color:#00a\">hidden<\/span> <span style=\"color:#4c8317\">!important<\/span>;\n  }\n<span style=\"color:#1e90ff;font-weight:bold\">style<\/span>&gt;\nscript <span style=\"color:#1e90ff\">src<\/span>=<span style=\"color:#a50\">\"https:\/\/www.google.com\/recaptcha\/api.js?render=_reCAPTCHA_site_key&amp;onload=__recaptchaCallback\"<\/span> <span style=\"color:#1e90ff\">async<\/span> <span style=\"color:#1e90ff\">defer<\/span>&gt;<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;\nscript&gt;\n  <span style=\"color:#0aa\">window<\/span>.__recaptchaCallback = <span style=\"color:#00a\">function<\/span>() {\n    <span style=\"color:#00a\">if<\/span> (<span style=\"color:#0aa\">window<\/span>.grecaptcha) {\n      <span style=\"color:#0aa\">window<\/span>.grecaptcha.execute(<span style=\"color:#a50\">'_reCAPTCHA_site_key'<\/span>, {action: <span style=\"color:#a50\">'homepage'<\/span>}).then(<span style=\"color:#00a\">function<\/span>(token) {\n        <span style=\"color:#00a\">var<\/span> url = <span style=\"color:#a50\">'https:\/\/mydomain.com:3000\/recaptcha\/'<\/span>;\n        <span style=\"color:#00a\">var<\/span> xhr = <span style=\"color:#00a\">new<\/span> XMLHttpRequest();\n        xhr.open(<span style=\"color:#a50\">'GET'<\/span>, url + <span style=\"color:#a50\">'?g-recaptcha-response='<\/span> + token, <span style=\"color:#00a\">true<\/span>);\n        xhr.onreadystatechange = <span style=\"color:#00a\">function<\/span>(data) {\n          <span style=\"color:#00a\">if<\/span> (<span style=\"color:#00a\">this<\/span>.readyState === XMLHttpRequest.DONE &amp;&amp; <span style=\"color:#00a\">this<\/span>.status === <span style=\"color:#099\">200<\/span>) {\n            <span style=\"color:#00a\">var<\/span> responseJson = JSON.parse(xhr.response);\n            <span style=\"color:#0aa\">window<\/span>.dataLayer.push({\n              event: <span style=\"color:#a50\">'recaptcha'<\/span>,\n              recaptchaAnswer: responseJson.status,\n              recaptchaScore: responseJson.recaptcha.score\n            });\n          }\n        }\n        xhr.send();\n      });\n    }\n  };\n<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;<\/code><\/pre>\n<\/div>\n<p>Remember to change the <code>_reCAPTCHA_site_key<\/code> on lines 7 and 11.<\/p>\n<p>The <code>url<\/code> variable on line 12 needs to point to your Node.js application.<\/p>\n<p>This setup is different from the PHP request. Here, we use a GET request, and we parse the response, pushing both the success and error into <code>dataLayer<\/code> using a success callback for the HTTP request.<\/p>\n<p>Also, since we load the JavaScript API asynchronously, we create a global callback method <code>__recaptchaCallback<\/code>, whose name we pass in the script loader as a parameter (<code>&amp;onload<\/code>).<\/p>\n<p>The end result is the same as with the PHP endpoint &#8211; a <code>dataLayer.push()<\/code> event with the reCAPTCHA status and score.<\/p>\n<h3 id=\"nodejs-application\">Node.js application<\/h3>\n<p>The <strong>Node.js<\/strong> application example here is the simplest possible thing you can build. For it to work, you need to have <a href=\"https:\/\/nodejs.org\/en\/download\/\">Node.js installed<\/a> on in the environment where you want to run the endpoint (for example, a web server running on your site or in the cloud).<\/p>\n<p>Create an empty directory, and initialize a new <code>npm<\/code> project with <code>npm init<\/code>. After following through the setup steps, run:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-sh\" data-lang=\"sh\">$ npm install express express-recaptcha cookie-parser --save<\/code><\/pre>\n<\/div>\n<p>This installs the required dependencies to run a simple <strong>express.js<\/strong> web server as well as the files required to run the reCAPTCHA middleware and some cookie parsing logic.<\/p>\n<p>Then, create a file named <strong>server.js<\/strong>, open it for editing, and add the following code within:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">const<\/span> express = require(<span style=\"color:#a50\">'express'<\/span>);\n<span style=\"color:#00a\">const<\/span> cookieParser = require(<span style=\"color:#a50\">'cookie-parser'<\/span>);\n<span style=\"color:#00a\">const<\/span> Recaptcha = require(<span style=\"color:#a50\">'express-recaptcha'<\/span>).RecaptchaV3;\n\n<span style=\"color:#00a\">const<\/span> app = express();\napp.use(cookieParser());\n\n<span style=\"color:#00a\">const<\/span> siteKey = <span style=\"color:#a50\">'_reCAPTCHA_site_key'<\/span>;\n<span style=\"color:#00a\">const<\/span> secretKey = <span style=\"color:#a50\">'_reCAPTCHA_secret_key'<\/span>;\n\n<span style=\"color:#00a\">const<\/span> recaptcha = <span style=\"color:#00a\">new<\/span> Recaptcha(siteKey, secretKey, {action: <span style=\"color:#a50\">'homepage'<\/span>});\n\napp.get(<span style=\"color:#a50\">'\/recaptcha\/'<\/span>, recaptcha.middleware.verify, (req, res) =&gt; {\n  <span style=\"color:#00a\">const<\/span> botCookie = req.cookies._rbs;\n  res.header(<span style=\"color:#a50\">'Access-Control-Allow-Origin'<\/span>, <span style=\"color:#a50\">'*'<\/span>); <span style=\"color:#aaa;font-style:italic\">\/\/ Set this to the actual domain that will be sending the requests\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">if<\/span> (!req.recaptcha.error) {\n    <span style=\"color:#00a\">const<\/span> recaptcha = req.recaptcha.data;\n    <span style=\"color:#00a\">const<\/span> score = recaptcha.score;\n    res.cookie(<span style=\"color:#a50\">'_rbs'<\/span>, score, {path: <span style=\"color:#a50\">'\/'<\/span>, maxAge: <span style=\"color:#099\">30<\/span> * <span style=\"color:#099\">60<\/span> * <span style=\"color:#099\">1000<\/span>});\n    <span style=\"color:#aaa;font-style:italic\">\/\/ Only send response if cookie does not exist or does not match the latest score\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#00a\">if<\/span> (botCookie !== score) {\n      res.send({status: <span style=\"color:#a50\">'1'<\/span>, recaptcha: req.recaptcha.data});\n    }\n  } <span style=\"color:#00a\">else<\/span> {\n    <span style=\"color:#00a\">const<\/span> score = req.recaptcha.error;\n    res.cookie(<span style=\"color:#a50\">'_rbs'<\/span>, score, {path: <span style=\"color:#a50\">'\/'<\/span>, maxAge: <span style=\"color:#099\">30<\/span> * <span style=\"color:#099\">60<\/span> * <span style=\"color:#099\">1000<\/span>});\n    res.send({status: <span style=\"color:#a50\">'0'<\/span>, recaptcha: {score: score}});\n  }\n});\n\napp.listen(<span style=\"color:#099\">3000<\/span>, () =&gt; console.log(<span style=\"color:#a50\">'App listening on port 3000!'<\/span>));\n<\/code><\/pre>\n<\/div>\n<p>Edit lines 8 and 9 with the actual <strong>site key<\/strong> and <strong>secret key<\/strong>, respectively.<\/p>\n<p>Edit line 15 to allow requests only from your site (so if your site is running on <code>https:\/\/mydomain.com<\/code>, that\u2019s what you would add as a valid origin instead of <code>*<\/code>).<\/p>\n<p>This application runs on port <code>3000<\/code> of whatever hostname is configured for your web server. It creates a simple GET request endpoint to <code>\/recaptcha\/<\/code>, where a piece of <strong>middleware<\/strong> will inspect the incoming request for a reCAPTCHA token.<\/p>\n<p>If the token is encountered, it is validated and the <code>recaptcha<\/code> results are written to <code>dataLayer<\/code> as well as a cookie named <code>_rbs<\/code>.<\/p>\n<p>If the validation fails, the \u201cscore\u201d will be the error message instead of the actual score.<\/p>\n<h2 id=\"rest-of-the-setup\">Rest of the setup<\/h2>\n<h3 id=\"google-analytics-custom-dimensions\">Google Analytics Custom Dimensions<\/h3>\n<p>In Google Analytics, create <strong>two<\/strong> new Custom Dimensions:<\/p>\n<ul>\n<li><strong>reCAPTCHA score<\/strong> (session scope)<\/li>\n<li><strong>reCAPTCHA answer<\/strong> (session scope)<\/li>\n<\/ul>\n<div style=\"aspect-ratio: 806 \/ 672;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2019\/09\/create-custom-dimension.jpg\" title=\"Create custom dimension\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"672\" width=\"806\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2019\/09\/create-custom-dimension.jpg#ZgotmplZ\" alt=\"Create custom dimension\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>These two Custom Dimensions allow us to permanently filter out bot traffic from our Google Analytics production views.<\/p>\n<div style=\"aspect-ratio: 1652 \/ 472;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2019\/09\/new-custom-dimensions.jpg\" title=\"New custom dimensions\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"472\" width=\"1652\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2019\/09\/new-custom-dimensions.jpg#ZgotmplZ\" alt=\"New custom dimensions\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Note that the Google Analytics tags are only fired if the score changes (or if the score was previously an error). That way you won\u2019t constantly send the same reCAPTCHA score to Google Analytics while the session is active.<\/p>\n<p>The Custom Dimensions are sent with an <strong>event tag<\/strong>.<\/p>\n<h3 id=\"google-tag-manager-setup\">Google Tag Manager setup<\/h3>\n<p>First, let\u2019s create two new Data Layer variables.<\/p>\n<h4 id=\"data-layer-variables\">Data Layer Variables<\/h4>\n<p>The first variable is named <strong>dl_recaptchaAnswer<\/strong>, and should have its Data Layer Variable Name field pointing to <code>recaptchaAnswer<\/code>.<\/p>\n<p>The second variable is named <strong>dl_recaptchaScore<\/strong>, and should have its Data Layer Variable Name field pointing to <code>recaptchaScore<\/code>.<\/p>\n<p>Here\u2019s what the latter would look like:<\/p>\n<div style=\"aspect-ratio: 537 \/ 582;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2019\/09\/data-layer-variable.jpg\" title=\"Data Layer variable\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"582\" width=\"537\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2019\/09\/data-layer-variable.jpg#ZgotmplZ\" alt=\"Data Layer variable\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<h4 id=\"trigger\">Trigger<\/h4>\n<p>The trigger is a simple Custom Event trigger that looks like this:<\/p>\n<div style=\"aspect-ratio: 730 \/ 468;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2019\/09\/custom-event-trigger.jpg\" title=\"Custom event trigger\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"468\" width=\"730\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2019\/09\/custom-event-trigger.jpg#ZgotmplZ\" alt=\"Custom event trigger\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<h4 id=\"event-tag\">Event tag<\/h4>\n<p>The main function of the event tag is to send the Custom Dimensions. You can arrange the other fields however you like. This is what a sample Universal Analytics event tag might look like:<\/p>\n<div style=\"aspect-ratio: 918 \/ 686;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2019\/09\/ga-event-tag-1.jpg\" title=\"GA Event tag 1\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"686\" width=\"918\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2019\/09\/ga-event-tag-1.jpg#ZgotmplZ\" alt=\"GA Event tag 1\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<div style=\"aspect-ratio: 897 \/ 538;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2019\/09\/ga-event-tag-2.jpg\" title=\"GA Event tag 2\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"538\" width=\"897\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2019\/09\/ga-event-tag-2.jpg#ZgotmplZ\" alt=\"GA Event tag 2\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Just make sure you have the Custom Dimension index and value settings correct per what you configured in Google Analytics admin earlier.<\/p>\n<blockquote>\n<p><strong>NOTE<\/strong>! One enhancement would be to set the Custom Dimensions <em>only<\/em> if <code>recaptchaAnswer<\/code> is <code>1<\/code> (success), so that you don\u2019t end up overwriting a valid score for the session with an errant error message.<\/p>\n<\/blockquote>\n<h2 id=\"analyze-the-results\">Analyze the results<\/h2>\n<p>When you set the whole thing up, all users on your page will be vetted in the background for their probability to be a bot. The script fires if the user hasn\u2019t been validated with a proper score within 30 minutes since the last validation. This ensures that you don\u2019t flood Google Analytics unnecessarily with events that just have the same score sent with each one.<\/p>\n<div style=\"aspect-ratio: 980 \/ 752;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2019\/10\/recaptcha-bot-traffic.jpg\" title=\"reCAPTCHA bot traffic\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"752\" width=\"980\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2019\/10\/recaptcha-bot-traffic.jpg#ZgotmplZ\" alt=\"reCAPTCHA bot traffic\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Here\u2019s what the custom dimensions will end up populated with:<\/p>\n<table>\n<thead>\n<tr>\n<th>Key<\/th>\n<th>Google Analytics fields<\/th>\n<th>Explanation<\/th>\n<th>Sample value<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>recaptchaAnswer<\/code><\/td>\n<td>Event Action, Custom Dimension<\/td>\n<td>Whether or not the validation worked. <code>1<\/code> for success, <code>0<\/code> for failure.<\/td>\n<td><code>1<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>recaptchaScore<\/code><\/td>\n<td>Event Label, Custom Dimension<\/td>\n<td>Score between <code>0.0<\/code> and <code>1.0<\/code> (where <code>1.0<\/code> is most likely to be human and <code>0.0<\/code> most likely to be bot). If the validation fails, the error message is sent instead.<\/td>\n<td><code>0.9<\/code>, or <code>invalid-input-response<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>You can drill down to the <code>0.1<\/code> score to identify idiosyncrasies in this low-score traffic.<\/p>\n<div style=\"aspect-ratio: 980 \/ 987;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2019\/10\/recaptcha-providers.jpg\" title=\"reCAPTCHA providers\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"987\" width=\"980\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2019\/10\/recaptcha-providers.jpg#ZgotmplZ\" alt=\"reCAPTCHA providers\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>To get a better understanding of the amount of bot traffic, create segments based on <strong>reCAPTCHA score<\/strong>. After a few weeks, you\u2019ll have enough data in order to:<\/p>\n<ul>\n<li>Determine the ratio of bot traffic on your site.<\/li>\n<li>Decide whether you should permanently filter out flagged bot traffic from you Google Analytics production views.<\/li>\n<\/ul>\n<h2 id=\"summary\">Summary<\/h2>\n<p>Thank you so much to Philipp and Sebastian for sharing their amazing idea here. Since reCAPTCHA v3 calculates the score based on user interactions on the site, it\u2019s a perfect candidate for measuring with Google Analytics, since we can surreptitiously collect the \u201cbot-ness\u201d of the visitor and leverage GA\u2019s custom dimensions to collect the data.<\/p>\n<p>It\u2019s not trivial to implement, as it requires a web service to poll for the reCAPTCHA score. Perhaps someone could do the world a service and create a free, public API for polling this information? Until then, you\u2019re stuck with an on-premise solution or, better yet, leveraging the cloud for setting up the API endpoint.<\/p>\n<p>This solution should serve well to uncover the complexity of bot traffic on any given website. Bots and crawlers come in different shapes and sizes &#8211; there are malicious agents as well as services that aim to do good. Regardless, bot traffic is most likely <em>not<\/em> your target traffic when building your website, so being able to segment it out in Google Analytics is a major win for data quality indeed.<\/p>\n<p>Let us know in the comments what you think of this solution, and whether you have ideas for improving it!<\/p>\n<\/p><\/div>\n\n","protected":false},"excerpt":{"rendered":"<p>There are thousands upon thousands of bots, crawlers, spiders, and other creepy-crawlies out there doing nothing but crawling through websites and harvesting the content within for whatever purposes they have been fine-tuned to. While Google Analytics provides a bot filtering feature to filter out \u201cspam\u201d and \u201cbot traffic\u201d from views, this is far from comprehensive [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":93591,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12033],"tags":[12765,3641,1428,1531,12638,36737],"dealstore":[],"offerexpiration":[],"class_list":["post-93590","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-analytics","tag-analytics","tag-bot","tag-detection","tag-google","tag-improve","tag-recaptcha"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Improve Google Analytics Bot Detection With reCAPTCHA - Som2ny Network<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fivemor.com\/?p=93590\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Improve Google Analytics Bot Detection With reCAPTCHA - Som2ny Network\" \/>\n<meta property=\"og:description\" content=\"There are thousands upon thousands of bots, crawlers, spiders, and other creepy-crawlies out there doing nothing but crawling through websites and harvesting the content within for whatever purposes they have been fine-tuned to. While Google Analytics provides a bot filtering feature to filter out \u201cspam\u201d and \u201cbot traffic\u201d from views, this is far from comprehensive [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fivemor.com\/?p=93590\" \/>\n<meta property=\"og:site_name\" content=\"Som2ny Network\" \/>\n<meta property=\"article:published_time\" content=\"2025-02-17T12:27:09+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/bot-traffic-in-ga.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1634\" \/>\n\t<meta property=\"og:image:height\" content=\"502\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"admin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fivemor.com\/?p=93590#article\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/?p=93590\"},\"author\":{\"name\":\"admin\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371\"},\"headline\":\"Improve Google Analytics Bot Detection With reCAPTCHA\",\"datePublished\":\"2025-02-17T12:27:09+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=93590\"},\"wordCount\":1885,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fivemor.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=93590#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/bot-traffic-in-ga.jpg\",\"keywords\":[\"Analytics\",\"Bot\",\"Detection\",\"Google\",\"improve\",\"reCAPTCHA\"],\"articleSection\":[\"Analytics\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fivemor.com\/?p=93590#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fivemor.com\/?p=93590\",\"url\":\"https:\/\/fivemor.com\/?p=93590\",\"name\":\"Improve Google Analytics Bot Detection With reCAPTCHA - Som2ny Network\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=93590#primaryimage\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=93590#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/bot-traffic-in-ga.jpg\",\"datePublished\":\"2025-02-17T12:27:09+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fivemor.com\/?p=93590#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fivemor.com\/?p=93590\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/?p=93590#primaryimage\",\"url\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/bot-traffic-in-ga.jpg\",\"contentUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/bot-traffic-in-ga.jpg\",\"width\":1634,\"height\":502},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fivemor.com\/?p=93590#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/fivemor.com\/?bp_activities=1\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Improve Google Analytics Bot Detection With reCAPTCHA\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/fivemor.com\/#website\",\"url\":\"https:\/\/fivemor.com\/\",\"name\":\"Som2ny Network\",\"description\":\"Daily Deals\",\"publisher\":{\"@id\":\"https:\/\/fivemor.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/fivemor.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/fivemor.com\/#organization\",\"name\":\"Som2ny Network\",\"url\":\"https:\/\/fivemor.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2026\/07\/4a0953c4-logo-300x86-1.png\",\"contentUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2026\/07\/4a0953c4-logo-300x86-1.png\",\"width\":300,\"height\":86,\"caption\":\"Som2ny Network\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371\",\"name\":\"admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/729ae85bf62b9917e93538db2f2688ca?s=96&r=g&default=https%3A%2F%2Ffivemor.com%2Fwp-content%2Fplugins%2Fbuddypress-first-letter-avatar%2Fimages%2Fdefault%2F96%2Flatin_a.png\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/729ae85bf62b9917e93538db2f2688ca?s=96&r=g&default=https%3A%2F%2Ffivemor.com%2Fwp-content%2Fplugins%2Fbuddypress-first-letter-avatar%2Fimages%2Fdefault%2F96%2Flatin_a.png\",\"caption\":\"admin\"},\"sameAs\":[\"https:\/\/fivemor.com\"],\"url\":\"https:\/\/fivemor.com\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Improve Google Analytics Bot Detection With reCAPTCHA - Som2ny Network","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fivemor.com\/?p=93590","og_locale":"en_US","og_type":"article","og_title":"Improve Google Analytics Bot Detection With reCAPTCHA - Som2ny Network","og_description":"There are thousands upon thousands of bots, crawlers, spiders, and other creepy-crawlies out there doing nothing but crawling through websites and harvesting the content within for whatever purposes they have been fine-tuned to. While Google Analytics provides a bot filtering feature to filter out \u201cspam\u201d and \u201cbot traffic\u201d from views, this is far from comprehensive [&hellip;]","og_url":"https:\/\/fivemor.com\/?p=93590","og_site_name":"Som2ny Network","article_published_time":"2025-02-17T12:27:09+00:00","og_image":[{"width":1634,"height":502,"url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/bot-traffic-in-ga.jpg","type":"image\/jpeg"}],"author":"admin","twitter_card":"summary_large_image","twitter_misc":{"Written by":"admin","Est. reading time":"12 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fivemor.com\/?p=93590#article","isPartOf":{"@id":"https:\/\/fivemor.com\/?p=93590"},"author":{"name":"admin","@id":"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371"},"headline":"Improve Google Analytics Bot Detection With reCAPTCHA","datePublished":"2025-02-17T12:27:09+00:00","mainEntityOfPage":{"@id":"https:\/\/fivemor.com\/?p=93590"},"wordCount":1885,"commentCount":0,"publisher":{"@id":"https:\/\/fivemor.com\/#organization"},"image":{"@id":"https:\/\/fivemor.com\/?p=93590#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/bot-traffic-in-ga.jpg","keywords":["Analytics","Bot","Detection","Google","improve","reCAPTCHA"],"articleSection":["Analytics"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fivemor.com\/?p=93590#respond"]}]},{"@type":"WebPage","@id":"https:\/\/fivemor.com\/?p=93590","url":"https:\/\/fivemor.com\/?p=93590","name":"Improve Google Analytics Bot Detection With reCAPTCHA - Som2ny Network","isPartOf":{"@id":"https:\/\/fivemor.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/fivemor.com\/?p=93590#primaryimage"},"image":{"@id":"https:\/\/fivemor.com\/?p=93590#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/bot-traffic-in-ga.jpg","datePublished":"2025-02-17T12:27:09+00:00","breadcrumb":{"@id":"https:\/\/fivemor.com\/?p=93590#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fivemor.com\/?p=93590"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/?p=93590#primaryimage","url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/bot-traffic-in-ga.jpg","contentUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/bot-traffic-in-ga.jpg","width":1634,"height":502},{"@type":"BreadcrumbList","@id":"https:\/\/fivemor.com\/?p=93590#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/fivemor.com\/?bp_activities=1"},{"@type":"ListItem","position":2,"name":"Improve Google Analytics Bot Detection With reCAPTCHA"}]},{"@type":"WebSite","@id":"https:\/\/fivemor.com\/#website","url":"https:\/\/fivemor.com\/","name":"Som2ny Network","description":"Daily Deals","publisher":{"@id":"https:\/\/fivemor.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fivemor.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/fivemor.com\/#organization","name":"Som2ny Network","url":"https:\/\/fivemor.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/#\/schema\/logo\/image\/","url":"https:\/\/fivemor.com\/wp-content\/uploads\/2026\/07\/4a0953c4-logo-300x86-1.png","contentUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2026\/07\/4a0953c4-logo-300x86-1.png","width":300,"height":86,"caption":"Som2ny Network"},"image":{"@id":"https:\/\/fivemor.com\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371","name":"admin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/729ae85bf62b9917e93538db2f2688ca?s=96&r=g&default=https%3A%2F%2Ffivemor.com%2Fwp-content%2Fplugins%2Fbuddypress-first-letter-avatar%2Fimages%2Fdefault%2F96%2Flatin_a.png","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/729ae85bf62b9917e93538db2f2688ca?s=96&r=g&default=https%3A%2F%2Ffivemor.com%2Fwp-content%2Fplugins%2Fbuddypress-first-letter-avatar%2Fimages%2Fdefault%2F96%2Flatin_a.png","caption":"admin"},"sameAs":["https:\/\/fivemor.com"],"url":"https:\/\/fivemor.com\/?author=1"}]}},"_links":{"self":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts\/93590","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=93590"}],"version-history":[{"count":0,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts\/93590\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/media\/93591"}],"wp:attachment":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=93590"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=93590"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=93590"},{"taxonomy":"dealstore","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fdealstore&post=93590"},{"taxonomy":"offerexpiration","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fofferexpiration&post=93590"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}