{"id":24952,"date":"2026-08-06T06:52:08","date_gmt":"2026-08-06T06:52:08","guid":{"rendered":"https:\/\/capskip.com\/?p=24952"},"modified":"2026-08-06T06:52:08","modified_gmt":"2026-08-06T06:52:08","slug":"improve-recaptcha-v3-score","status":"publish","type":"post","link":"https:\/\/capskip.com\/zh\/improve-recaptcha-v3-score\/","title":{"rendered":"\u5982\u4f55\u63d0\u5347 reCAPTCHA v3 \u5206\u6570\uff1a\u516d\u4e2a\u5207\u5b9e\u6709\u6548\u7684\u65b9\u6cd5"},"content":{"rendered":"<p>You can&#8217;t set a reCAPTCHA v3 score. Google assigns it per request, and nothing in your code changes it directly. What you can change is what feeds it: how you name actions, when you request the token, how much of your site runs reCAPTCHA at all, and what your backend does with the result. Fix those and the distribution moves.<\/p>\n<p>Six changes, ordered by how much they typically help. Measure first, because half the sites that think they have a scoring problem have a threshold problem.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">What the score actually means<\/h2>\n<p>v3 returns a number between 0.0 and 1.0 with every verification. Google&#8217;s wording: 1.0 is very likely a good interaction, 0.0 is very likely a bot. There&#8217;s no checkbox and no puzzle, so the number is the entire signal.<\/p>\n<p>Two things follow from that, and both matter:<\/p>\n<ul>\n<li>The score is <strong>per request and per action<\/strong>, not per user. The same visitor can score 0.9 on your homepage and 0.3 on checkout.<\/li>\n<li>Google&#8217;s suggested starting threshold is <strong>0.5<\/strong>. That&#8217;s a default to tune away from, not a target to hit.<\/li>\n<\/ul>\n<p>If you&#8217;re new to how v3 differs from the checkbox version, our explainer on <a href=\"https:\/\/capskip.com\/what-is-recaptcha\/\">how reCAPTCHA works<\/a> covers the mechanics.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Measure before you change anything<\/h2>\n<p>The reCAPTCHA admin console shows a score distribution for your site and a breakdown for your top ten actions. Look at it before touching code. You&#8217;re looking for one of three shapes:<\/p>\n<ul>\n<li><strong>Everything at 0.9<\/strong>, and you&#8217;re still blocking people. Your threshold or your backend logic is the problem, not the score.<\/li>\n<li><strong>A wide spread<\/strong> with a bump at the low end. Normal. Tune the threshold per action.<\/li>\n<li><strong>Everything at 0.1 to 0.3.<\/strong> Something structural is wrong. Usually the token, not the traffic.<\/li>\n<\/ul>\n<p>Google also warns that scores in staging or right after you install v3 differ from production, because the model has no history for the site yet. Give it a week of real traffic before drawing conclusions. To sanity-check a single request in isolation, our <a href=\"https:\/\/capskip.com\/captcha-demo\/recaptcha-v3\/\">live reCAPTCHA v3 test page<\/a> returns the raw score for one solve.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Fix 1: name your actions, and name them correctly<\/h2>\n<p>This is the biggest single win, and it&#8217;s routinely skipped. Google scores each action separately and uses the action&#8217;s own history as context. One generic action across the whole site means one blended history, and every page inherits the worst of it.<\/p>\n<pre data-enlighter-language=\"js\" class=\"EnlighterJSRAW\">\/\/ One action per meaningful event. Not one for the whole site.\ngrecaptcha.ready(function () {\n  grecaptcha.execute(&quot;YOUR_SITEKEY&quot;, { action: &quot;login&quot; })\n    .then(function (token) {\n      document.getElementById(&quot;recaptcha-token&quot;).value = token;\n    });\n});<\/pre>\n<p>Rules Google enforces: actions may contain only alphanumeric characters, slashes and underscores, and they must not be user-specific. So <code>checkout\/payment<\/code> is fine, <code>checkout_user_8842<\/code> is not. A user-specific action fragments the history into thousands of buckets with no data in any of them, which is worse than not naming actions at all.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Fix 2: run reCAPTCHA on more than the form<\/h2>\n<p>v3 scores behaviour, and behaviour needs more than one data point. If the script only loads on your login page, Google sees a visitor who materialises at a form and submits, which is exactly what a bot looks like.<\/p>\n<p>Google&#8217;s own recommendation is to load v3 across the site, including pages with no form on them. You don&#8217;t have to verify on those pages. Just executing the script gives the model something to work with by the time the visitor reaches the action you care about.<\/p>\n<p>This is also the fix people accidentally undo. Moving the script into a conditional that only fires on the checkout route will drop your scores within days.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Fix 3: get the token when you submit, not on page load<\/h2>\n<p>reCAPTCHA v3 tokens expire two minutes after they&#8217;re issued. Generate one in <code>ready()<\/code> at page load, and any visitor who reads your form for longer than that submits a dead token. Depending on how your backend handles the failure, that reads as a bad score or a hard rejection.<\/p>\n<pre data-enlighter-language=\"js\" class=\"EnlighterJSRAW\">\/\/ Solve on submit so the token is always fresh.\nform.addEventListener(&quot;submit&quot;, function (e) {\n  e.preventDefault();\n  grecaptcha.execute(&quot;YOUR_SITEKEY&quot;, { action: &quot;login&quot; })\n    .then(function (token) {\n      tokenField.value = token;\n      form.submit();\n    });\n});<\/pre>\n<p>Long forms, multi-step checkouts and anything with a file upload are where this bites hardest.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Fix 4: verify server side, and check the action too<\/h2>\n<p>The token is worthless until your backend exchanges it. That exchange returns the score, the action, and a hostname, and you should be checking all three.<\/p>\n<pre data-enlighter-language=\"bash\" class=\"EnlighterJSRAW\"># Exchange the token for the score. Server side only.\ncurl -X POST https:\/\/www.google.com\/recaptcha\/api\/siteverify \\\n  -d secret=YOUR_SECRET_KEY \\\n  -d response=THE_TOKEN_FROM_THE_PAGE\n\n# {&quot;success&quot;:true,&quot;score&quot;:0.9,&quot;action&quot;:&quot;login&quot;,&quot;hostname&quot;:&quot;example.com&quot;}<\/pre>\n<p>If you only check <code>success<\/code>, you&#8217;re not using v3 at all. <code>success<\/code> means the token parsed, not that the visitor looked human. And if you don&#8217;t compare <code>action<\/code> against what that endpoint expected, a token minted on your low-value newsletter form works fine on your login endpoint.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Fix 5: set a threshold per action, not one for the site<\/h2>\n<p>A checkout and a newsletter signup shouldn&#8217;t share a cutoff. Once you have a week of data per action, set each one where your traffic actually sits.<\/p>\n<table>\n<thead>\n<tr>\n<th>Action type<\/th>\n<th>Reasonable starting point<\/th>\n<th>What to do below it<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Newsletter, search, page view<\/td>\n<td>0.3<\/td>\n<td>Allow, log the score<\/td>\n<\/tr>\n<tr>\n<td>Login, comment<\/td>\n<td>0.5<\/td>\n<td>Add a second factor or a v2 checkbox<\/td>\n<\/tr>\n<tr>\n<td>Checkout, password reset<\/td>\n<td>0.7<\/td>\n<td>Step up to a manual challenge<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Notice that none of those rows say &#8220;block&#8221;. Hard-blocking on a low score is how v3 deployments lock out real customers on corporate VPNs and privacy browsers. Step up the challenge instead.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Fix 6: rule out the usual score killers<\/h2>\n<p>If the structural fixes are all in place and scores are still low, work through these:<\/p>\n<table>\n<thead>\n<tr>\n<th>Cause<\/th>\n<th>Why it scores low<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Two reCAPTCHA scripts on one page<\/td>\n<td>The second load clobbers the first and the token binds to the wrong context<\/td>\n<\/tr>\n<tr>\n<td>Shared or datacenter IPs<\/td>\n<td>Office NAT, VPNs and cloud egress all carry other people&#8217;s history<\/td>\n<\/tr>\n<tr>\n<td>Aggressive privacy extensions<\/td>\n<td>Blocked cookies and storage leave the model with nothing to read<\/td>\n<\/tr>\n<tr>\n<td>Iframed or embedded forms<\/td>\n<td>Cross-origin context weakens the signal<\/td>\n<\/tr>\n<tr>\n<td>Sitekey and domain mismatch<\/td>\n<td>Check the <code>hostname<\/code> field in the verify response<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>One thing that is <em>not<\/em> on this list: hiding the badge. That&#8217;s a CSS and attribution question, and it has no effect on scoring. We covered the compliant way to do it in <a href=\"https:\/\/capskip.com\/hide-recaptcha-badge\/\">hiding the reCAPTCHA v3 badge<\/a>.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">The problem tuning won&#8217;t solve<\/h2>\n<p>If the traffic is automated, it scores low because it is what v3 was built to detect. No amount of action naming fixes a headless browser. For testing your own site, or for automation you&#8217;re authorised to run, you get a token from a solver instead of from the page:<\/p>\n<pre data-enlighter-language=\"python\" class=\"EnlighterJSRAW\"># pip install capskip\nfrom capskip import CapSkip\n\nsolver = CapSkip(host=&quot;127.0.0.1&quot;, port=8080)\n\nresult = solver.recaptcha(\n    sitekey=&quot;YOUR_SITEKEY&quot;,\n    url=&quot;https:\/\/example.com\/page-with-recaptcha&quot;,\n    version=&quot;v3&quot;,\n    action=&quot;login&quot;,     # must match the page\n)\n\nprint(result[&quot;code&quot;])   # token, inject it and submit<\/pre>\n<p>Note the <code>action<\/code> again. It matters as much on this side as it does on yours, for exactly the same reason: the backend compares it.<\/p>\n<p>What you can&#8217;t do is name a score. There&#8217;s no minimum-score parameter on the solve request. The number is Google&#8217;s call, made when your token is verified, so a solver hands you a token and nothing more.<\/p>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Frequently asked questions<\/h2>\n<details style=\"border:1px solid #e2e5ee;border-radius:10px;padding:14px 18px;margin:0 0 12px;\">\n<summary style=\"cursor:pointer;\">\n<h3 style=\"font-size:1.15rem;line-height:1.4;display:inline;margin:0;\">Why is my reCAPTCHA v3 score always 0.1?<\/h3>\n<\/summary>\n<p style=\"margin:12px 0 0;\">A flat 0.1 across all traffic is almost never a behaviour problem. Check for a duplicate script tag, a stale token issued more than two minutes before submission, or a sitekey registered to a different domain. The <code>hostname<\/code> field in the verify response settles the last one immediately.<\/p>\n<\/details>\n<details style=\"border:1px solid #e2e5ee;border-radius:10px;padding:14px 18px;margin:0 0 12px;\">\n<summary style=\"cursor:pointer;\">\n<h3 style=\"font-size:1.15rem;line-height:1.4;display:inline;margin:0;\">How long does it take for score changes to show up?<\/h3>\n<\/summary>\n<p style=\"margin:12px 0 0;\">Several days. The model uses history per site and per action, so a new action starts with no context and settles as traffic accumulates. Don&#8217;t judge a change on one afternoon of data.<\/p>\n<\/details>\n<details style=\"border:1px solid #e2e5ee;border-radius:10px;padding:14px 18px;margin:0 0 12px;\">\n<summary style=\"cursor:pointer;\">\n<h3 style=\"font-size:1.15rem;line-height:1.4;display:inline;margin:0;\">Does a higher score threshold make my site safer?<\/h3>\n<\/summary>\n<p style=\"margin:12px 0 0;\">Only up to a point, and it costs you real users. Raising every endpoint to 0.9 blocks people on shared IPs and privacy browsers long before it stops a determined attacker. Set the threshold per action and step up the challenge instead of rejecting outright.<\/p>\n<\/details>\n<details style=\"border:1px solid #e2e5ee;border-radius:10px;padding:14px 18px;margin:0 0 12px;\">\n<summary style=\"cursor:pointer;\">\n<h3 style=\"font-size:1.15rem;line-height:1.4;display:inline;margin:0;\">Can I see the score without writing backend code?<\/h3>\n<\/summary>\n<p style=\"margin:12px 0 0;\">Yes. The admin console shows the distribution for your own site, and our v3 demo page returns the raw score for a single solve so you can compare one request against what your own endpoint reports.<\/p>\n<\/details>\n<h2 style=\"font-size:1.6rem;line-height:1.35;\">Summary<\/h2>\n<p>Name one action per event, load v3 across the site, mint the token at submit time, verify server side and compare the action, then set a threshold per endpoint instead of one global cutoff. Check the admin console a week later, not the same day.<\/p>\n<p>For the mechanics of v3 scoring and the options that go with it, see <a href=\"https:\/\/capskip.com\/recaptcha-v3-solver\/\">reCAPTCHA v3 solving<\/a>, and Google&#8217;s own <a href=\"https:\/\/developers.google.com\/recaptcha\/docs\/v3\" rel=\"nofollow noopener\" target=\"_blank\">v3 documentation<\/a> is the authority on thresholds and action naming. If you&#8217;re testing your own forms against a low score, CapSkip is a <a href=\"https:\/\/capskip.com\/\">captcha solver<\/a> that runs locally, so you can generate tokens all day without a per-solve bill.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u4f60\u65e0\u6cd5\u8bbe\u5b9a reCAPTCHA v3 \u7684\u5206\u6570\uff0c\u4f46\u53ef\u4ee5\u6539\u53d8\u5f71\u54cd\u5b83\u7684\u56e0\u7d20\u3002\u516d\u4e2a\u80fd\u64ac\u52a8\u8fd9\u4e2a\u6570\u5b57\u7684\u4fee\u590d\uff0c\u4ee5\u53ca\u4e00\u4e2a\u518d\u600e\u4e48\u8c03\u4f18\u4e5f\u89e3\u51b3\u4e0d\u4e86\u7684\u95ee\u9898\u3002<\/p>","protected":false},"author":1,"featured_media":24957,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"rank_math_title":"Improve reCAPTCHA v3 Score: Six Fixes | CapSkip","rank_math_description":"Six changes that improve reCAPTCHA v3 score results, from action names to token timing. Measure your current distribution first, then fix the biggest one.","rank_math_focus_keyword":"improve recaptcha v3 score","footnotes":""},"categories":[71],"tags":[],"class_list":["post-24952","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-google-recaptcha"],"_links":{"self":[{"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/posts\/24952","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/comments?post=24952"}],"version-history":[{"count":2,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/posts\/24952\/revisions"}],"predecessor-version":[{"id":24958,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/posts\/24952\/revisions\/24958"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/media\/24957"}],"wp:attachment":[{"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/media?parent=24952"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/categories?post=24952"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/capskip.com\/zh\/wp-json\/wp\/v2\/tags?post=24952"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}