âTWITTER BOTS ARE RUINING TWITTERâ is a very accurate, very true statement. Iâve had countless people instinctively flinch when I tell them I make Twitter bots. Bots are often responsible for spreading disinformation, hurting artistsâ merch sales, and basically ruining the human experience of the bird site.
So why are we making one? To make a nice bot, of course!
YOUR bot isnât going to sow discord, or do anything malicious, right?
Answer me.
Ok, youâre good. So, letâs talk about how to do this and why. Twitter bots are a great way to practice using an API and developing some coding skills along the way. You can usually get the bot going for under 100 lines of code, so itâs especially good for beginners. In this tutorial, Iâll show you how to use Node.js and a few npms to have your bot tweeting positivity and fun to counteract all those other nasty bots.
Weâll be using:
Node.js
Twit
node-schedule
DotEnv
Twitter
Twitter Developer portal
Heroku
GitLab
Gitpod through GitLab
Setting up a Twitter Account
This is where you decide what you want your account to be named and what it will do automatically. This bot I'm showing you code for will tweet a link to a video game soundtrack once a week (pulled randomly from an array of links) and will respond to a user who asks for a link with a random link from the same array. Weâll call our bot @SNESSoundtracks. Go to Twitter and follow the instructions for making a brand new account for your bot.
Twitter Developer Portal
The developer portal is where you register your new account to be able to use the Twitter API. This is an important step because it unlocks the account's ability to tweet by using the API with code instead of manually tweeting. You know, the whole point of a bot?
So hereâs the process: get logged in to your botâs twitter and youâll head to the developer page. Once there, youâll see a link near the profile picture on the top right that says âapply.â
Click that, and itâll take you to a page where you apply to have your Twitter profile become an active developer profile. Follow the instructions on screen until you have an authenticated developer account. Once thatâs done, create the app and fill out the descriptions for your app. Really, all you have to say is that youâre doing it as a hobby and itâs just for learning to code or practicing a bot. Youâre not giving info to the government or really consuming streaming data for analytical purposes. When youâve finished, the developer portal should look like this.
The next thing to do, once the app is created, is to go into the settings and make sure that the app can read and write. This is a little more complicated these days, but here's the new process. Go into the settings for the app and scroll down till you see "User Authentication Settings." Head into that and turn on the toggle for Oauth 1.0a. Check the Read and Write box underneath that, and fill in only Calback URI
and Website URL
withâŠ
literally whatever.
It actually doesn't matter what you put there because all we need is read and write access for our keys, there is no callback URL, but they require one. I know someone who just puts example.com
in that space so they can change the Auth setting and get their bot to write. Save these settings at the bottom.
The Keys and the Code and the Node Package Manager
Ok, so youâve created the app, verified your email, and now youâre reaching for the keys. Iâm gonna stop you right there.
Itâs easier to get the keys after you have somewhere to put them. Weâre gonna be keeping them in a dotenv file for safekeeping from people who would try to get access to your keys. We'll come back to the keys later. For now, let's set up GitLab
Getting Started with GitLab
For today, we're using GitLab, the DevOps platform. This article has a quick little getting started guide to get your repo up and running, but there's more details in this video I made going over some introductory stuff. The sequel to it is here. These videos go through the same lessons GitLab provides for you when you sign up. Now, since this is for beginners, the important thing here is your repository, a place to store your code online. This uses git, a type of source control that is an important part of every developer's knowledge.
Sign up for a new account and follow the instructions until you get to the main page. Use the blue button to create a new project, then select "blank project." Fill in the information on this next page and make sure that "Initialize with a readme" is selected. This is an important step so you can immediately clone
your repo.
Once you've created the project, you'll be on the main repository page where only a readme exists. I recommend writing a description of your bot in the readme: what you used to make it, what it does, and any other information that will help people learn about you or the bot. You can do this by clicking the readme and clicking the edit
button on that page. The readme is written in markdown, a specialized markup language that allows for changing aspects of the visual presentation of the text. For more on markdown, go here.
Itâs almost code timeâŠ
Doing the work RIGHT IN YOUR BROWSER
This is the part of the article where we talk about Gitpod. Gitpod is a full instance of VSCode right in your browser (Chrome, Edge, Bravo, Safari, Firefox). This means you donât need to move anything local, because GitLab and Gitpod already work together to give you a great development environment right in your browser. To use Gitpod, follow these instructions to make sure the Gitpod option is turned on. Right in your repositoryâs main page, there is a dropdown menu that may say Web IDE
or Gitpod
.
Ensure it says Gitpod then click it. After a few seconds, Gitpod will open in your browser and youâll see the readme in the left column. Now you can start creating files!
Major Key (Twitter keys)
Remember the Twitter keys from earlier? Weâre gonna create some variables for them. Youâll have four keys you need in order to connect your app to the code youâve written. Create a file in your project called .env
(sometimes written as dotenv). Inside, add four variables: access_token
, access_token_secret
, consumer_secret
, consumer_key
.
The consumer keys will pair with the API keys from the Developer Twitter site. NOTE: You will need to regenerate all four of your keys before using them. This is because you changed the permissions earlier. So when you go to the keys page on the twitter developer page (click the key icon in your settings) there will be a button to regenerate them. Do so when youâre ready to put them in the .env file.
Something important about a dotenv file, you wonât need quotes around the values of your variables, as long as there arenât spaces. Make sure to write it like this: consumer_key=whateveryourkeyis
. Your dotenv file is going to be your one source of truth for the keys. The config file will point to the .env values, and because you created a gitignore, you wonât upload your keys to GitLab.
Up next, weâre going to install all the npm packages we need, so you'l need to enter some commands into your terminal in Gitpod. Note: to get the terminal open, there should be a tab on the window called "Terminal". Just in case, here's the docs on the terminal from VSCode and gitpod
Input the following commands one by one into your terminal. In the future, you may learn quicker ways to do this, but for now I recommend doing it one by one so you can see what the process looks like.
"Npm init -y"
"Npm install node"
"Npm install node-schedule"
"Npm install twit"
"Npm install dotenv"
This installs all the dependencies weâll need to be able to have a functional Twitter bot that can read the API, post on a schedule, use the .env file, and use node.js. We have one more thing to adjust, and thatâs to create some scripts inside the package.json file code block. Open it and ensure the scripts section looks like this.
scripts:{
"start": "node index.js",
"develop": "NODE_ENV=develop node index.js"
}
That index.js file doesnât exist yet, so you'll need to create it and name it whatever you like. Thereâs an icon that looks like a rectangle with a plus sign on it. Thatâs the add file icon. Click it and name your file. You can call this file whatever you want instead of index.js as long as you remember what you called it (I called mine snes.js).
Go ahead and make a config.js at the same time and input the following into it.
module.exports = {
consumer_key: process.env.consumer_key,
consumer_secret: process.env.consumer_secret,
access_token: process.env.access_token,
access_token_secret: process.env.access_token_secret,
};
Letâs write some code.
Code It Up.
console.log("SNES Soundtracks booting up");
//making sure npm run develop works
if (process.env.NODE_ENV === "develop") {
require("dotenv").config();
};
//rules for node-schedule
var schedule = require("node-schedule");
var rule = new schedule.RecurrenceRule();
rule.dayOfWeek = 1,
rule.hour = 10;
rule.tz = "Etc/GMT+4";
//array to pull soundtracks from
var soundtrackArray = [ "an array of youtube video URLs"];
var soundtrackArrayLength = soundtrackArray.length;
var soundtrackArrayElement = Math.floor(Math.random() * soundtrackArrayLength);
At the beginning, I log a start up message to the console just so I know itâs running. Next is an if statement to use the dotenv when the node environment is âdevelopâ, which is handled in the scripts of the json file from earlier. We set up a few variables for the node-schedule so the bot can tweet on a set day and time. I pulled this directly from the docs for node-schedule. Basically, it will tweet every Monday at 10 am Eastern Daylight Savings Time. Finally, I set up an array for the bot to pull from at random with the last three lines of this section. I removed the URLs in the interest of length.
EDIT: I DISCOVERED A BUG HERE, and I'm leaving it in to show that bugs happen all the time and that what's important is watching your code.
By running the random number at this point in the code, I create a problem whereby the random number is selected at runtime rather than every time the function runs. This meant the bot was tweeting the same soundtrack every time it tweeted. To fix this, I moved var soundtrackArrayElement = Math.floor(Math.random() * soundtrackArrayLength);
inside each the two functions, pressStart
and pressSelect
. This allows the number to be chosen randomly upon the function running, rather than when the bot is first run. Now, back to the code!
// Create a Twitter object to connect to Twitter API
var Twit = require('twit');
// Pulling keys from another file
var config = require('./config.js');
// Making a Twit object for connection to the API
var T = new Twit(config);
// Setting up a user stream
var stream = T.stream('statuses/filter', { track: '@SnesSoundtracks' });
// Now looking for tweet events
// See: https://dev.Twitter.com/streaming/userstreams
stream.on('tweet', pressStart);
This is where we start using Twit. We create an object called Twit that requires the twit code, and then pass a configure that requires the configuration file into the object. We then use new to create âTâ, an instance of the object from before. From now on, when we want to use something from Twit, we simply use T.whatever in order to call up the property, field, or method we need from their library. We set up a stream so that we are monitoring specifically @SnesSoundtracks while the code is running. Finally, we create an event listener with stream.on, and use a string parameter to name it, and input a function weâve called, âpressStartâ. pressStart is defined in the next set of code.
function pressStart(tweet) {
var id = tweet.id_str;
var text = tweet.text;
var name = tweet.user.screen_name;
let regex = /(please)/gi;
let playerOne = text.match(regex) || [];
let playerTwo = playerOne.length > 0;
//this helps with errors, but isn't really best practice. It's ok, we're new. This let lets you see if the regex matched and if playerTwo is true or false
console.log(playerOne);
console.log(playerTwo);
// checks text of tweet for mention of SNESSoundtracks
if (text.includes('@SnesSoundtracks') && playerTwo === true) {
// Start a reply back to the sender
var replyText = ("@" + name + " Here's your soundtrack!" + soundtrackArray[soundtrackArrayElement]);
// Post that tweet
T.post('statuses/update', { status: replyText, in_reply_to_status_id: id }, gameOver);
} else {
console.log("uh-uh-uh, they didn't say the magic word.");
};
function gameOver(err, reply) {
if (err) {
console.log(err.message);
console.log("Game Over");
} else {
console.log('Tweeted: ' + reply.text);
}
};
}
pressStart contains a few local variables, a bit of logic, and a final function that must be included in the T.post method. You can use an unnamed function there and it will do the same thing, but I went ahead and wrote on separately for readability. Essentially, the function gameOver gives us a chance to log an error if it occurs or to log the tweet that was sent out.
pressStart takes âtweetâ as a parameter. This is the tweet that another user writes that tags SnesSoundtracks. That tweet has tons of data attached to it, data that Twit helps us parse through. The first three variables are the id of the tweet, the text of the tweet, and the username of the person who wrote the tweet. We will need those three in order to respond accurately as a comment to the original tweet by the other user.
Up next is a regex for whatever word you want to activate the bot to reply. I chose âplease,â so that as long as the user is polite, theyâll get a random soundtrack.
The regex has âiâ and âgâ at the end so it ignores capitalization and checks globally for the word please. playerOne is a variable that can either be an empty array or will use .match to create an array with one element, the word âpleaseâ. playerTwo is a boolean that verifies whether the array playerOne has an element or not.
The logic dictates that the tweet text contains the botâs name and an array of at least one element was passed into playerTwo. If both of these come back as true, then we proceed to an area where the variable replyText is created, which includes a random element of the array, as well as the username of the person being replied to and a short message. replyText is passed into an object that contains two properties: status and in_reply_to_status_id. Status is the actual text to be posted to the tweet, in our case the variable replyText is our status. In_reply_to_status_id is defined as id, which is a variable from the beginning of the pressStart function. Id is a unique identifier of a tweet from Twitterâs API. This allows Twit to identify which tweet the bot will reply to as a comment. Finally, the else statement at the end will log a quote from Jurassic Park to the console if the user doesnât say please. I thought about having the bot tweet this to the user but decided against it. Instead, itâs a little fun just for me.
function pressSelect() {
var weeklyReplyText = soundtrackArray[soundtrackArrayElement] + " Here's your soundtrack for the week!";
T.post('statuses/update', { status: weeklyReplyText }, gameOver2);
function gameOver2(err, reply) {
if (err) {
console.log(err.message);
console.log("Game Over");
} else {
console.log('Tweeted: ' + reply.text);
}
}
}
const job1 = schedule.scheduleJob(rule, pressSelect);
job1.on("Every Day Tweet", pressSelect);
Here is the function used to tweet on a schedule, which Iâve named pressSelect. pressSelect has the replyText variable, slightly changed to be a tweet rather than a comment, but uses the same array to pull from. The gameOver function is also present, though renamed just to be safe. Since gameOver and gameOver2 are local variables within their respective functions, there shouldnât be any issues. However, they both do the same thing.
The final part of this code is creating a variable called job1. job1 is the scheduleJob method from the node-schedule object at the top of the code. I pass in the rule created and pressSelect as parameters. We then use an event listener with pressSelect passed in again.
Running the Code
To test your code and ensure it works, type ânpm run developâ into the terminal. If you get a Twit error about consumer keys, ensure there are no spaces between the variable, equals sign, and key itself in your .env file. If the error persists, you may have copied your keys wrong. You can always generate them again and copy them directly into the .env file. If youâd like to test pressSelect on its own and make sure it works, you can just comment out the last two lines of the code and call pressSelect directly. This way, you donât have to wait for whatever day and hour you scheduled node-schedule for.
Once itâs running, to test the way it responds to other users, log in to another Twitter account and tweet at your bot. You should be able to see some action in the terminal that tells you itâs working, followed by the response on Twitter.
You did it!
Your bot runs from your code! but what if you want it to run all the time? and not on your own machine? Well, to do that, we have to deploy it. Check out this article for more on how to deploy using Heroku!
Finished!
I hope this article has been helpful! I'm always trying to improve, and this article was certainly a challenge. I tried to include every step and think of possible pitfalls you might experience, but if you're stuck, you can always reach out to me on Twitter and I'd be happy to chat about your bot! Hereâs a copy of my snes repo so you can check and see whatâs working for me!
Top comments (1)
If you have a business or personal brand, a large Twitter following can significantly contribute buy twitter followers to increasing brand awareness. Your content will be exposed to a wider audience, potentially leading to more recognition, referrals, and conversions.