How to create simple javascript/jquery client side captcha?
-
5What is the point of a client-side CAPTCHA?!? The whole purpose of CAPTCHA is to prevent the server from responding to requests that are made by non-humans. What are you trying to achieve? Spam-bots will not be executing your JavaScript. Humans will. Spam-bots will not get annoyed (even if they could). Humans can, and will. – Amadan Jul 07 '10 at 15:38
-
This practice is not recommended as executing the captcha only tin the frontend open the door to the robots to crawling your DOM and scripts and avoid your human detection script. – Danhdds Feb 04 '21 at 15:25
11 Answers
Why don't you use reCAPTCHA ? It's free, very efficient, and provides accessibility functionnalities.

- 3,115
- 7
- 31
- 44
-
29
-
I don't consider it due to the really ugly look these boxes have. But there is not reason not to implement ones own re captcha clone. Thanks for the hint :) – Nov 26 '11 at 23:23
-
7And reCAPTCHA is hosted in google it is not working here in China and other apps hosted at google. – spicykimchi Aug 05 '14 at 10:13
-
6
-
4
-
1I work in a corporate. And here google.accounts is blocked, so can't use google reCAPTCHA – Adarsh Singh Dec 18 '19 at 09:21
-
1
It can be done with HTML and a simple JavaScript code. Have a look at this:
function Captcha(){
var alpha = new Array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'0','1','2','3','4','5','6','7','8','9');
var i;
for (i=0;i<6;i++){
var a = alpha[Math.floor(Math.random() * alpha.length)];
var b = alpha[Math.floor(Math.random() * alpha.length)];
var c = alpha[Math.floor(Math.random() * alpha.length)];
var d = alpha[Math.floor(Math.random() * alpha.length)];
var e = alpha[Math.floor(Math.random() * alpha.length)];
var f = alpha[Math.floor(Math.random() * alpha.length)];
var g = alpha[Math.floor(Math.random() * alpha.length)];
}
var code = a + ' ' + b + ' ' + ' ' + c + ' ' + d + ' ' + e + ' '+ f + ' ' + g;
document.getElementById("mainCaptcha").innerHTML = code
document.getElementById("mainCaptcha").value = code
}
function ValidCaptcha(){
var string1 = removeSpaces(document.getElementById('mainCaptcha').value);
var string2 = removeSpaces(document.getElementById('txtInput').value);
if (string1 == string2){
return true;
}else{
return false;
}
}
function removeSpaces(string){
return string.split(' ').join('');
}
.capt{
background-color:grey;
width: 300px;
height:100px;
}
#mainCaptcha{
position: relative;
left : 60px;
top: 5px;
}
#refresh{
position:relative;
left:230px;
width:30px;
height:30px;
bottom:45px;
background-image: url(rpt.jpg);
}
#txtInput, #Button1{
position: relative;
left:40px;
bottom: 40px;
}
<link rel="stylesheet" type="text/css" href="estilo.css" />
<script type="text/javascript" src="script.js"></script>
<body onload="Captcha();">
<div class="capt">
<h2 type="text" id="mainCaptcha"></h2>
<p><input type="button" id="refresh" onclick="Captcha();"/></p> <input type="text" id="txtInput"/>
<input id="Button1" type="button" value="Check" onclick="alert(ValidCaptcha());"/>
</div>
</body>

- 33,559
- 24
- 104
- 119

- 127
- 1
- 2
-
3Given that the text appears _right there_, I don't think it's very secure against bots. – Nic Jun 15 '16 at 22:13
-
2
-
1Perfect code for a very simple, intentionally bad captcha for a project I'm working on. This has use cases. – dimitar.bogdanov May 01 '21 at 11:30
-
1For security, you can just draw it into a canvas and place a hash on value ctx.fillText(code , (canvas.width/2) - (textWidth / 2), 50); – Akshay K Nair Aug 02 '21 at 12:49
here you are ;)
var captchaText;
$(function() {
var pre = $('#captcha');
captchaText = pre.text();
pre.text('');
var lines = ['', '', '', '', '']
for (var ixLetter = 0; ixLetter < captchaText.length; ixLetter++) {
var letter = captchaText.substr(ixLetter, 1);
var letterLines = letters[letter];
for (var ix = 0; ix < 5; ix++) {
lines[ix] = lines[ix] + ' ' + letterLines[ix];
}
}
for (var ix = 0; ix < 5; ix++) {
pre.append(lines[ix] + '\n');
}
});
function check() {
if ($('#captchaCheck').val() == captchaText) {
alert('you are probably human');
} else {
alert('you probably made a mistake. Don\'t worry. To err is also human.');
}
}
var letters = {
h: [
'HH HH',
'HH HH',
'HHHHHH',
'HH HH',
'HH HH'
],
i: [
'II',
'II',
'II',
'II',
'II'
]
// etc
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<pre id="captcha">hi</pre> Please type what you see: <input id="captchaCheck" /> <input type="button" value="Check" onclick="check()" />

- 2,119
- 1
- 15
- 28

- 3,787
- 1
- 25
- 39
-
This is fun but if you use the real letters to represent the letters what is the point? :P Also consider that he is doing this to avoid bots so the submit button and href of the form should be written on a succesful captcha – Fabiano Soriani Jul 07 '10 at 18:54
-
1
-
-
You should take that text and then draw it to a canvas and try to un-normalize the letters by shifting them, rotating them, overlapping them slightly, things that make reading them hard. Do this all in a private function scope (you put it in the global scope) so that it's not accessible what the value of the text is except to the script, loop and check for the correct value or use events or whatever but don't expose the answer in the code to public scope javascript. Then your approach should work in theory, but probably won't be better than what ReCaptcha already offers (for anyone else) – OG Sean Aug 17 '20 at 20:38
I agree with all the comments that client side captcha is fundamentally flawed, and I don't know know tough the hurdles have to be to mitigate any amount of spam...
To get an impression of what you're up against, though, check xRumer and GSA in action: YouTube: xEvil vs GSA Captcha Breaker
The software is also able to gather and decipher artificial intelligence such as security questions (i.e. what is 2+2?) often used by forums upon registration. Since the latest version of XRumer, the software is capable of collecting such security questions from multiple sources and is much more effective in defeating them.
References:
- How do spambots work? - Webmasters Stack Exchange (2010!)
- BotDetect: Pure JavaScript CAPTCHA Validation Problems
So, caveats aside, here's a trivial alternative using HTML5 validation that's probably as ineffective as the other posts here! Presumably spambots would just add formnovalidate
before submission, and would identify a honeypot field.
<form class="input">
<label for="number" class="title">
What is three plus four?
</label>
<br>
<input
name="number"
required="required"
pattern="(7|seven)"
oninvalid="this.setCustomValidity('Sorry, please enter the correct answer')"
oninput="this.setCustomValidity('')"
>
<!-- Bonus honeypot field, hidden from the user. The server should discard this response if it contains any input -->
<input name="decoy" style="display: none;" />
<input type="submit">
</form>

- 14,902
- 10
- 83
- 103
Client-Side captchas do not provide the protection a server-generated captcha would because the server can not check if the solved captcha is solved correctly.

- 26,978
- 14
- 97
- 115
That is not possible.
You could create something that looks like a CAPTCHA, but it would only run when it's not needed, i.e. when the page is shown in a browser. When it's needed it won't run, as the program trying to break in won't run the client side script.

- 687,336
- 108
- 737
- 1,005
-
"That is not possible." - such a strong phrase, what proves itself wrong time after time – Fabiano Soriani Jul 07 '10 at 18:56
-
1@Fabiano: Such a strong phrases are waranted in cases like this. A client side CAPTCHA would actually be worse than nothing at all, as it gives a false sense of security, but offers no real security what so ever. – Guffa Jul 07 '10 at 21:37
-
I see your point and agree on your comment. But about *being not possible* likely, isn't right – Fabiano Soriani Jul 09 '10 at 18:15
-
1@Fabiano: If you want something that *looks* like a CAPTCHA, it's of course possible to do using client script, but to make one that actually works is not possible. – Guffa Jul 10 '10 at 13:52
function Captcha(){
var alpha = new Array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'0','1','2','3','4','5','6','7','8','9');
var i;
for (i=0;i<6;i++){
var a = alpha[Math.floor(Math.random() * alpha.length)];
var b = alpha[Math.floor(Math.random() * alpha.length)];
var c = alpha[Math.floor(Math.random() * alpha.length)];
var d = alpha[Math.floor(Math.random() * alpha.length)];
var e = alpha[Math.floor(Math.random() * alpha.length)];
var f = alpha[Math.floor(Math.random() * alpha.length)];
var g = alpha[Math.floor(Math.random() * alpha.length)];
}
var code = a + ' ' + b + ' ' + ' ' + c + ' ' + d + ' ' + e + ' '+ f + ' ' + g;
document.getElementById("mainCaptcha").innerHTML = code
document.getElementById("mainCaptcha").value = code
}
function ValidCaptcha(){
var string1 = removeSpaces(document.getElementById('mainCaptcha').value);
var string2 = removeSpaces(document.getElementById('txtInput').value);
if (string1 == string2){
return true;
}else{
return false;
}
}
function removeSpaces(string){
return string.split(' ').join('');
}
<h1 This works pretty well. </h1>

- 11
- 1
-
6Please do not only answer with code, but explain how it solves the problem. – Timisorean Mar 01 '19 at 15:43
if your purpose is to simply deflect most bots, you might be able to get away with a simple script that chooses 2 numbers at random and asks user to add them.

- 39,136
- 15
- 78
- 84
-
1Ок, but if spam bot use form.Submit() it's validation is not saffely, how i may check condition before form.Submit() If atribut on submit hadles only when member click on button submit – Vlad Omelyanchuk Jul 07 '10 at 15:52
-
4That's exactly what everyone keeps telling you - it is not possible. you can't catch `form.submit()`. And especially you can't catch someone who parses your web-page, constructs a POST request and contacts your server programmatically (without a browser, without JavaScript). – Amadan Jul 10 '10 at 15:23
Try this:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<script>
/* created dynamically by server when preparing the page */
// f function is on server and not known by bot and is random per result
// maybe bcrypt with a unique salt per request
var encodedResult = "f('X')";
var serverRenderedPositionSequence = [
[0,0],
[10,10],
[20,20],
[30,30],
[40,40],
[50,50],
[60,60],
[70,70],
[80,80],
[90,90],
[100,100],
[100,100],
[100,100],
[100,100],
[100,100],
[100,0],
[90,10],
[80,20],
[70,30],
[60,40],
[50,50],
[40,60],
[30,70],
[20,80],
[10,90],
[0,100]
];
window.index = 0;
window.move=function(but){
but.style.left = (serverRenderedPositionSequence[window.index][0]+"px");
but.style.top = (serverRenderedPositionSequence[window.index][1]+"px");
window.index++;
if(window.index<serverRenderedPositionSequence.length)
{
setTimeout(function(){
window.move(but);
},125);
}
}
window.onload=function(){
var but = document.getElementById("decoy-button");
window.index=0;
window.move(but);
};
function post()
{
// do something with
var xhrData= {
encodedResult:encodedResult,
result:document.getElementById('result').value
};
var postXhr=function(){ /* HTTP POST */}
// server checks if decoded "encoded result" is equal to the result (X here)
postXhr(xhrData);
}
</script>
</head>
<body>
<input id="result" type="text" value="Enter the message you see" />
<input id="test" onclick="post()" type="button" value="Post" />
<input id="decoy-button" type="button" value=" click me bot" style="width:0px;padding:0;position:absolute; left:0px; top:0px;" />
<input id="secret" type="button" onclick="window.index=0;move( document.getElementById('decoy-button'))" value="repeat sequence" />
</body>
</html>
Then the server would only use bcrypt to check if result is true.
Since the pattern matching requires dynamically observing the screen, it would cause some bots to fail. These would fail:
- bots that click to post button immediately
- bots that don't run javascript
- bots that mis-click the decoy buttons
- bots that can't understand the leap between coordinates in the sequence
-
- for example when drawing X, it leaps from bot-right to top-right effectively drawing a vertical line on imaginary plane which may trick some bots easily
- bots that use OCR with "fixed" screenshot timings
To further obfuscate any "canvas" hack, the server could add quick random bursts (with decreased latency between leaps) into the sequence such that resulting image would look unrecognizable but human will see what it writes between those random bursts.
To add one more depth, you can ask a math problem like
1+1
instead of just string.
But, when a bot memoizes the encoded result and re-sends it, the security is broken. So, have a "session" for client and not send any encoded result. Just the randomized sequence and check for result only by server-side. Of course the session also costs database time/space but at least website admin/editor does not see spam on the control panel of website.

- 11,469
- 4
- 45
- 97
please try this
<script type="text/javascript">
$('#submitcapt').click(function(){
var captval = "This will not do nothing";
$.ajax({
type : "POST",
url : "externals/reCaptcha/ajaxaction.php",
data : {loadval:captval},
success : function( msg ) {
if(msg=="1"){
}else{
}
}
})
});
</script>
In ajaxaction.php please put the following code
<?php
session_start();
$val=$_POST['loadval'];
$message= $_SESSION['random_number'];
if($val==$message) {
echo "1";
}else{
echo "2";
}
?>

- 7,219
- 3
- 35
- 65
$(document).ready(function() {
DrawCaptcha();
});
function refreshCap() {
DrawCaptcha();
}
function DrawCaptcha() {
var a = Math.ceil(Math.random() * 10) + '';
var b = Math.ceil(Math.random() * 10) + '';
var c = Math.ceil(Math.random() * 10) + '';
var d = Math.ceil(Math.random() * 10) + '';
var e = Math.ceil(Math.random() * 10) + '';
var f = Math.ceil(Math.random() * 10) + '';
var g = Math.ceil(Math.random() * 10) + '';
var code = a + ' ' + b + ' ' + ' ' + c + ' ' + d + ' ' + e + ' ' + f + ' ' + g;
var test = document.getElementById("ContentPlaceHolder1_txtCapcha").value = code;
alert(test);
}
function ValidCaptcha() {
var str1 = removeSpaces(document.getElementById('ContentPlaceHolder1_txtCapcha').value);
var str2 = removeSpaces(document.getElementById('ContentPlaceHolder1_txtinputCapcha').value);
if (str1 != str2) {
alert("Properly enter the Security code.");
document.getElementById('ContentPlaceHolder1_txtinputCapcha').focus() return false;
}
}
function removeSpaces(string) {
return string.split(' ').join('');
}

- 1,607
- 2
- 16
- 25