On the wave of the Bitcoin and alt-coins hype, I think it’s worth to ask yourself a question: Can something be done to get Bitcoin for free? Well the answer is simple: Yes you can! With the support of modern programming language, you can generate some coins in no time using the Bitcoin bot. It’s a great way to start your adventure with Bitcoin without putting your budget at risk. Don’t expect golden mountains though – it’s more a programming challenge/fun project than new way of getting rich but with proper scale. Here’s the complete guide how to setup your Bitcoin bot, but before we got down to business let’s talk about problems and theory.

Bitcoin Faucets

So how does it work? Everybody keeps on saying that you have to throw some cash into this insecure, unknown and hazardous machine, some sorcery happens and ta-daaa – you own virtual money. You wouldn’t risk your hard earned cash with something like this, right? Well, there’s a way to avoid uncertainty. Bitcoins and alt-coins (such as DOGE, Litecoin, DarkCoin) are mined by people with serious graphics card (and I mean serious – like plane hangars full of GPUs).

Fortunately some guys found a way to share satoshi (1/100000000 of Bitcoin) with people visiting their sites. Mechanism is simple, you create a webpage packed with ads and pay users for visiting (and earn revenue from ads providers). Such pages are called Faucets. There are separate faucets for each of coin. I believe you already know what is going to happen next. It’s time to write bitcoin bot which will perform all needed actions to earn bitcoins. Sounds simple? It ain’t that easy. Faucet owners are no stupid and protect their sites from bots. Usually with captchas. The more sophisticated captcha, the harder it gets to earn satoshi with bot (and to get profit).

Captcha problem

It’s easy to solve solveMedia type captcha when siting in front of monitor. Those are usually distorted sentences and human should fairly easy recognize them.But how bot will read this text? It won’t. There are multiple services that solves catpchas for you for a small fee. I’ve chosen 9kw.eu as it can be free – you can solve captchas to earn credits which can be later spent on you requests. More advanced captchas like famous Google’s recaptcha2 can be solved with 2captcha.com but this service is slow and it’s not worth it.

Payout problem

Some faucets function as a separate entity in the Internet. In most cases those sites are scams and promise payout after reaching certain satoshi threshold. In practice your account will be banned before you reach that level. To solve that problem and to gather more people, faucet owners started to organize themselves. One of the biggest and best grouping site is faucethub.io. It provides lot of faucets for major coins. You can play games and manually visit faucets to earn more coins apart of bot. Be aware though – they can ban you due to suspicious activity (like playing whole day without rest using bitcoin bot).

Creating The Bitcoin Bot

Now, after some theory, it’s time to actually build something. Here’s what you will need:

  1. new email (there are a lot of scams ahead)
  2. bitcoin wallet
  3. FaucetHub Account
  4. 9kw account
  5. node.js installed
  6. phantom and casperjs installed
  7. Bitcoin Bot code

I will skip email creation part as it’s pretty simple 🙂 I assume that you know how to create a separate email if you are trying to write a Bitcoin bot.

Bitcoin Wallet

This is the most important thing in this whole Bitcoin Bot process. In general, there are 2 kinds of Bitcoin wallets: hardware and software. Hardware wallets come in different way – as a USB key or printed QR code. They are considered the most secure and therefore I would suggest using one. The most basic is the paper wallet. You can print you own at Wallet Generator Site. If you have at least minimal trust in people you can use software wallet but you want to stick with the ones giving you access to your private key. It’s simple: having your private key or seed you can replicate your wallet on any other device. If you don’t own keys (like for example in Bitcoin exchange portals) then provider can simply close the site and your coin is gone. And there’s no way to get it back. Literally. For my personal use I chosen Copay Android app as it stores keys on the device. Whichever approach you chose, you should have 33 or 34 chars long address like this:

1AVNfQQjEJCmst83oQH6RJUpbqkHZWe1W7

This is the public address and it’s safe to share it. Never share private address as it can be used for hacking your wallet.

FauceHub Account

Go to Faucethub and create account using the Signup button on top

Fill in all required details including newly created Bitcoin wallet.

9kw account

Go to 9kw and create new account there. After you’re done, go ahead and click Captcha tab at the top and solve couple of captchas:

Just enter correct answer in the field below and you should see your balance on the right increase. For single bot run you will need ~30 credits.

node.js

Now let’s talk about programming environment. I an Javascript guy so naturally I’ve chosen the JS-like language to work with. Node.js is not really needed here as Casperjs is a standalone product, but npm installations is easier with node.js on board.

Go to https://nodejs.org/en/download/ , download package for your OS and them install it. Make sure you know where it installs – you will need that directory. To make sure that your system recognizes node.js and npm commands, PATH needs to be updated.

To update PATH Variables in Windows 7 click Start> Right click on Computer > Properties > Advanced System Setting > Advanced Tab > Environment Variables. For the PATH variable scroll down to Path and edit it by adding path to just installed node.js. In my case it’s c:\software\nodejs. Be sure to precede and follow this entry with semicolon.

phantomjs and casperjs

PhantomJS and CaperJS are framework based on node.js which allows to emulate behavior of the user in the browser. Those are so called headless browsers which means that they don’t display any GUI while operating. As you might imagine this will be the foundation for Bitcoin bot.

Let’s start with phantom. Go to http://phantomjs.org/download.html and download proper package for your operating system. Install it and add phantom.exe location to path variable. in my case it was C:\PhantomJS\bin\phantomjs.

Now let’s proceed with Casperjs. On http://casperjs.org/ you can find different ways to install casperjs but thanks to just installed node.js we can use npm installer. Fire up command line and run

npm install casperjs

By default this should install casperjs in node.js modules directory. As in the previous cases, you need to add that directory to PATH variables. In my case it was C:\Software\nodejs;C:\Software\nodejs\node_modules\casperjs\bin\

By now you should have everything setup. Let’s check if casper is visible in your system. Bring up command prompt and enter

casperjs --version

This should output in casperjs version.

Bitcoin Bot Code

Here comes the real stuff. For this tutorial I’ve chosen BitLucky.io faucet as it covers actions common in other faucets.

When you go to the site, you easily notice that there’s a set of actions that needs to be done to get satoshi.

  1. enter bitcoin wallet
  2. click login
  3. solve captcha
  4. click claim
  5. withdraw

Here’s my sample code which covers all of those steps. Please note variables section at the top and follow commented lines for more instructions. Click to expand the whole code:

var fs = require('fs');
var page = require('webpage').create();     
var current_timestamp;
var current_balance;
var new_balance;
var type;
var msg;
var claimed;
var next_run_time;
var md5;

var bitwallet = 'your_wallet_id'; //enter your wallet id
var apikey = 'your_captcha_id'; // enter your 9kw api key id
var application = 'bitlucky'; //site name - usable when running multiple scripts in batch
var cooldown=5; //cooldown in minutes until script can be run for the next time
var captcha_timeout = 200000;

var captcha_wait=0;
var captcha_fetched;

document.writeln("<script src='https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.js'></script>");
document.writeln("<script src='https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/md5.js'></script>");


/***********************************************************************/
    /* 9kw / captcha api part.. probably don't need to change that */
/***********************************************************************/
function kwsolver(fileName,apikey){

        var casper2 = require('casper').create({
            waitTimeout: 40000+captcha_timeout,
            headers: {
                    'Accept-Language': 'en'
                },
            onPageInitialized: function (page) {
                    page.evaluate(function () {
                        window.screen = {
                            width: 1440,
                            height: 900
                        };
                    });
                },
                viewportSize: {
                    width: 1440,
                    height: 900
                }

            });

      casper2.on('error', function(msg,backtrace) {
        console.log("I am in error handler!" +msg)
        casper1.exit();
        casper2.exit();
      });

      casper2.on('Timeout', function(msg,backtrace) {
        console.log("I am in timeout handler!" +msg)
        casper1.exit();
        casper2.exit();
      });

    casper2.start("https://www.9kw.eu/index.cgi?action=usercaptchaguthaben&apikey="+apikey).then(function(){

            balance = this.evaluate(function(){
                return document.querySelector('body').textContent;
            })

            if (balance<120){
            this.echo("Warning! low captcha credits: "+balance,'COMMENT');
            } else {
            console.log("current 9kw credits: "+balance);    
            }
            
            if (md5=="1B2M2Y8AsgTpgAmY7PhCfg==")
            {
              console.log("possible Januvia");

                answer = "JANUVIA";
                url ="manual Januvia";

                fs.write(application+'answer.txt',answer, 'w');
                fs.write(application+'captchaid.txt',url, 'w');
                answer_template=1;


            } else {

              console.log("doesn't look like januvia");
              answer_template=0;
            }
            

        }).thenOpen("https://www.9kw.eu/grafik/form.html")

        .then(function(){

            if (answer_template==0){

                    var captchaid;                  
              
                    this.fillSelectors('form[action="/index.cgi"]', {
                            'input[name="apikey"]':apikey,
                            'input[name="file-upload-01"]': fileName
                        }, true);
              }

        }).then(function(){

            if (answer_template==0){
                this.evaluate(function(){
                    document.getElementById("newsubmit").click();
                });

                this.capture(application+" captchaformfilled "+generateTimestamp()+".png");

                console.log("Captcha Pushed "+application + " [" + generateTimestamp("short") +"]" );

                this.then(function(){

                    captchaid = this.evaluate(function(){

                     return document.querySelector('body').textContent;

                    });
                    url = 'https://www.9kw.eu/index.cgi?action=usercaptchacorrectdata&prio=10&apikey='+apikey+'&id='+captchaid;

                    fs.write(application+'captchaid.txt',url, 'w');
                });
              }

        }).then(function(){
              
             if (answer_template==0){

               this.open(url);

             }

        }).then(function(){

            if (answer_template==0){

              console.log("Check start "+application + " [" + generateTimestamp("short") +"]" );

            }
        }).then(function(){
            
            if (answer_template==0){                                     

                  function issuccess(){
                    casper2.then(function(){
                   
                        this.reload(function(){


                            answer = this.evaluate(function(){

                                        return document.querySelector('body').textContent;

                                    });
                            
                                 if(answer=="" && captcha_wait < captcha_timeout/1000 ) {
                                        this.wait(5000,function(){
                                            captcha_wait = captcha_wait + 5; //cumulative captcha wait in seconds
                                            issuccess();
                                        })
                                 } else {

                                    if(captcha_wait >= captcha_timeout/1000) {captcha_fetched=0;} else {captcha_fetched=1;}

                                        console.log("Check Finish "+application + " [" + generateTimestamp("short") +"]" );
                                        fs.write(application+'answer.txt',answer, 'w');                                                                                                                                                           
                                }

                        });

                    });
                }
                issuccess();

            }                   

        }).run(function(){
     
            console.log("Leaving Solver "+application + " [" + generateTimestamp("short") +"]" );
            casper2done = true;
        });


}

function cleaner(mode){
            var path = ""; 
            var list = fs.list(path);

            for(var x = 0; x < list.length; x++){
                    var file = path + list[x];
                    if(
                        fs.isFile(file) 
                        && file.match("^"+application)
                        && !file.match(".js$")
                    )
                {
                    fs.remove(file);
                  
                    if (mode!="silen"){
                    console.log("Deleted " + file);
                    }
                }
            }
}

function generateTimestamp(version){

  var currentdate = new Date(); 


  year = currentdate.getFullYear();

  if(currentdate.getMonth()+1<10){month = "0"+(currentdate.getMonth()+1);}else{month = currentdate.getMonth()+1;};
  if(currentdate.getDate()<10){day= "0"+currentdate.getDate();}else{ day=currentdate.getDate();};
  if(currentdate.getHours()<10){hour= "0"+currentdate.getHours();}else{ hour= currentdate.getHours();};
  if(currentdate.getMinutes()<10){ minute= "0"+currentdate.getMinutes();}else{ minute= currentdate.getMinutes();} ;
  if(currentdate.getSeconds()<10){second = "0"+currentdate.getSeconds();}else{ second= currentdate.getSeconds();};


  var datetime = day +"_" + month +"_" + year + " | " + hour +"_" +minute +"_" +second;
  var datetimesafe = year +"" + month +"" + day + "" + hour +"" +minute +"" +second;

  var shifteddate = new Date();
  shifteddate.setTime(currentdate.getTime()+(cooldown*60*1000));

  if(shifteddate.getMonth()+1<10){ monthsafe = "0"+(shifteddate.getMonth()+1);}else{ monthsafe = shifteddate.getMonth()+1;};
  if(shifteddate.getDate()<10){ daysafe= "0"+shifteddate.getDate();}else{ daysafe = shifteddate.getDate();};
  if(shifteddate.getHours()<10){ hoursafe= "0"+shifteddate.getHours();}else{ hoursafe= shifteddate.getHours();};
  if(shifteddate.getMinutes()<10){ minutesafe= "0"+shifteddate.getMinutes();}else{ minutesafe= shifteddate.getMinutes();} ;
  if(shifteddate.getSeconds()<10) {secondsafe = "0"+shifteddate.getSeconds();}else{ secondsafe= shifteddate.getSeconds();};


  var datetimeshift = daysafe +"_" + monthsafe +"_" + year + " | " + hoursafe +"_" +minutesafe +"_" +secondsafe;

          if (version =="short")
          {

              return datetime;

          }else if(version=="shift") {

              return datetimeshift 

          }else {

              return datetimesafe

          }

} 

/* end of functions */

var casper1 = require('casper').create({
waitTimeout: 80000+captcha_timeout, 
headers: {
        'Accept-Language': 'en'
    },
 
onPageInitialized: function (page) {
        page.evaluate(function () {
            window.screen = {
                width: 1440,
                height: 900
            };
        });
    },
    viewportSize: {
        width: 1440,
        height: 900
    }

    });

casper1.on('error', function(msg,backtrace) {
  console.log("I am in timeout handler!" +msg)
  casper1.exit();
});

casper1.on('Timeout', function(msg,backtrace) {
  console.log("I am in timeout handler!" +msg)
  casper1.exit();
});


var casper2done = false;
var varum="ref/1AVNfQQjEJCmst83oQH6RJUpbqkHZWe1W7";

/***********************************************************************/
            /* faucet specific navigation starts here */
/***********************************************************************/

casper1.start("https://www.google.com/finance?q=BTCPLN").then(function(){
this.echo("** starting " + application +" **",'GREEN_BAR');

        this.wait(100,function(){
           cleaner("quiet");
         });


          this.wait(2000,function(){

            plnratio=this.evaluate(function(){
              return document.querySelector('span.bld').textContent.replace(',','').match(/\d+/)[0];
            });

            plnratio = plnratio/100000000;

          });

//cleanup previously generated screenshots

}).thenOpen("https://bitlucky.io"+varum,function(){
/***********************************************************************/
                              /* login */
/***********************************************************************/
   
    this.wait(1000,function(){
        
        console.log("Login "+application + " [" + generateTimestamp("short")  +"]");
        this.capture(application+" initial "+generateTimestamp()+".png");

        this.evaluate(function(bitwallet) {
            document.querySelector('input[name=address]').value = bitwallet;
            document.querySelector('a.btn-lg').click(); 
        },bitwallet);


    });

    //change captcha to solvemedia
    this.wait(2000,function(){

            var selected_captcha = this.evaluate(function(){
                return document.querySelector('a[href="/captcha/SolveMedia"]').textContent;
            });

            if (selected_captcha =="SolveMedia"){

                    this.wait(100, function(){
                        this.evaluate(function(){
                            document.getElementById("dropdownList").click();
                            document.querySelector('a[href="/captcha/SolveMedia"]').click();    
                            });
                    });

                    this.wait(2000, function(){
                        this.evaluate(function(bitwallet) {
                            document.querySelector('input[name=address]').value = bitwallet;
                            document.querySelector('a.btn-lg').click(); 
                        },bitwallet);
                    });

            } 

    });


    this.wait(4000, function(){
            this.capture(application+" captchaScreen "+generateTimestamp()+".png");
            console.log("Saving Captcha "+application + " [" + generateTimestamp("short")  +"]");
            this.captureSelector(application+'file22.png', '#adcopy-puzzle-image');

    });

    this.wait(2000, function(){

      captcha_object = this.evaluate(function(){

        return document.querySelector("#adcopy-puzzle-image-image").src;
      })

      md5= CryptoJS.MD5(captcha_object).toString(CryptoJS.enc.Base64);
      
    });



    this.wait(100,function(){ //wait to start second page

        kwsolver(application+'file22.png',apikey);

    });


}).waitFor(function check(){ //wait for kswolver to finish
    return casper2done;


}).then(function(){ //answer checking module

        answer = fs.read(application+'answer.txt');

        if (answer==""){
               console.log(application + " failed to captcha - timeout");
               casper1.exit();
                };

        }

}).then(function(){
   //back to the first page
    
        this.wait(100,function(){


            console.log("Login Answer fill-in "+application + " [" + generateTimestamp("short")  +"]");            
          
            this.capture(application+" loging "+generateTimestamp()+".png");
            
            answer = fs.read(application+ 'answer.txt');

            this.evaluate(function(answer){
                        document.getElementById('adcopy_response').value=answer;
                        document.getElementById('button').click();
            },answer);
         
        });


        this.wait(500,function(){

            this.capture(application + " loging "+generateTimestamp()+".png");
            casper2done = false;

        });

}).then(function(){

/***********************************************************************/
                              /* claiming */
/***********************************************************************/

    this.wait(100,function(){


        current_balance = this.evaluate(function() {
            
                return document.querySelector('span[style="font-size:18px;"]').textContent.match(/\d+/)[0];
            });


     //   console.log("current balance: "+current_balance);


            logged_in = this.evaluate(function(){
                    return document.getElementById('button').textContent.replace(/[^\w\s]/g,'');

            })


       //     console.log("logged in: '"+logged_in+"'");          
 
    });

}).then(function(){ //answer correctness checking module

      if (logged_in=="Login" || logged_in.match(/([A-Z])\w+/g)=="Login"){
    
              console.log(application + " failed to login");
               //console.log("failed to login. Check captcha id if correct: "+fs.read(application+'captchaid.txt'));
               casper1.exit();
            };

        }

}).then(function(){


    this.wait(100, function(){
        fs.remove(application+'captchaid.txt');
        fs.remove(application+'answer.txt');

        this.evaluate(function() {
            document.getElementById('button').click(); 
        });


    });
}).then(function(){

    this.waitForSelector('.btn.btn-lg.btn-default.btn-block',function(){
            this.capture(application+" logged "+generateTimestamp()+".png");

            this.evaluate(function() {
                 document.querySelector('.btn.btn-lg.btn-default.btn-block').click();

            });


    });




    this.wait(2000, function(){

          

            this.capture(application+" claiming "+generateTimestamp()+".png");
            
            console.log("Saving Captcha "+application + " [" + generateTimestamp("short")  +"]");
            
            this.captureSelector(application+'file22.png', '#adcopy-puzzle-image');
      
      

        });

  this.wait(2000, function(){

    md5= CryptoJS.MD5(document.getElementById("#adcopy-puzzle-image")).toString(CryptoJS.enc.Base64);
    console.log("md5 "+md5);


  });

   casper1.wait(100,function(){ //wait to start second page

            kwsolver(application+'file22.png',apikey);

        });


}).waitFor(function check(){ //wait for kswolver to finish
    return casper2done;

}).then(function(){ //answer checking module

    answer = fs.read(application+'answer.txt');

    if (answer==""){
       
             console.log(application + " failed to captcha - timeout");
               casper1.exit();
            };

    }
   
}).then(function(){

     this.wait(1000,function(){
    
            this.capture(application+" claiming "+generateTimestamp()+".png");

            console.log("Answer fill-in "+application + " [" + generateTimestamp("short")  +"]");            

            
            answer = fs.read(application+'answer.txt');



            this.evaluate(function(answer){
                          document.getElementById('adcopy_response').value=answer;
                          document.getElementById('button').click();
            },answer);

        })
         
 }).then(function(){   

        this.wait(2000,function(){
                    this.capture(application+" claimed0 "+generateTimestamp()+".png");

                    new_balance = this.evaluate(function() {
                    
                        return document.querySelector('span[style="font-size:18px;"]').textContent.match(/\d+/)[0];
                    });
                
                    console.log("current balance: "+new_balance);

                    claimed = new_balance-current_balance;

                    //console.log("debug claimed: " + claimed);

                        if (claimed>0)
                        {
                            this.echo("woo hoo! claimed "+ claimed +" satoshi / approx: "+claimed*plnratio+" PLN",'TRACE');
                        
                        } else {
                            console.log("something went wrong. no satoshi for you!");

                        }

            });

}).then(function(){

        fs.remove(application+'captchaid.txt');
        fs.remove(application+'answer.txt');
        casper2done = false;



}).then(function(){

    console.log("Operation Done "+application + " [" + generateTimestamp("short") +"]");
  
    if (type=="claimed"){
        console.log("** Next Run "+application + " [" + generateTimestamp("shift") +"] **");
        
      } else {
        console.log("** Next Run "+application + " [" + generateTimestamp("short") +"] **");
        

      }

}).run(function(){
  
  
    cleaner("silent");
    this.exit();

});

 

What’s going on here? Here’s the quick overview of functions used in Bitcoin bot:

  • kwsolver – accepts saved captcha image, pushes it to the 9kw service, waits certain moment of time for answer and returns answer in text file
  • cleaner – cleans all files (mostly images) generated by the script
  • generateTimestamp – outputs time in various format. Usable in debugging and showing next run time

When you inspect the code, it’s pretty straightforward what does it do. There are steps within .then() statements that are run one by one. One aspect that might be new is site object reference like this:

document.getElementById('button').click();

It’s just a handler reference. It can be found by Inspecting the webpage in browser:

 

What you might find strange is this JANUVIA. This is kind of a hack for common captcha that appeared for my Bitcoin bot. It looks like this:

Unfortunately 9kw service couldn’t handle that correctly so I was wasting credits on this. To solve this problem, I’ve added md5 hash checker which checks if image hash is the same as this one and bypasses 9kw service by providing correct security code which in this case is always Januvia. This workaround can be expanded for other common captchas. You just need to catch the generated md5hash and add it to kwsolver function.

Running the Bitcoin bot

So we know the theory, we have the code, let’s run it. Simply copy the code above, save it to a .js (for example to bitlucky_io.js) file and using the command prompt run (remember to be in folder where file is located)

casperjs bitlucky_io.js

You will see a lot of status updates – those are controlled by console.log() function. There are also image files generated in the same folder. Those will help you debug the script as it saves exactly the same webpage as seen by your browser.

I allowed the script to run and it looks like I was lucky. I managed to get satoshi from the faucet and thankt to Januvia hack I didn’t even spent 9kw credits on that.

Withdrawal

As you might noticed, there’s a balance indicator in the script. Bitlucky keeps your claimed satoshi on the internal balance account. It looks like the case I’ve described in the Payout problem part above. Fortunately you can withdraw coins at any time. And yes, you can write a separate script which will do it for you automatically. Funds withdrawn that way are transferred to your FaucetHub account and then can be withdrawn to Bitcoin wallet.