How I Made a Twitterbot with Node.js

The other day, I decided to make a Twitterbot to help streamline my marketing efforts for my art brand. I wanted to make a bot that would retweet tweets from a different user, selected from a list of users. I wanted the bot to also run once a day.

For my project, I used the following:

  • Node.js
  • twit – Twitter API client for Node.js
  • Heroku – platform for deployed applications

Creating an Application with Twitter

To get started, I used the Twitter application form to register my application. The process is pretty straight forward, and once it was completed, I was able to grab the necessary consumer_key, consumer_secret, access_token, and access_token_secret.

Building the Bot

To get started with Node.js, I created a new project directory. Then I ran npm init.

I ran the following commands to ensure I had the right packages to build the application:

npm install --save dotenv http twit

Next, I created the environment variables. I created a .env file in the directory, where I added in my project keys:

CONSUMER_KEY="add_it_here"
CONSUMER_SECRET="add_it_here"
ACCESS_TOKEN="add_it_here"
ACCESS_TOKEN_SECRET="add_it_here"

In my index.js file, I connected the .env variables to the application:

require("dotenv").config();
const config = {
  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
};

Then I added logic so the bot would retweet tweets from a list of users or retweet tweets tied to specific hashtags. First I set variables to use twit and to control the number of retweets the bot would make when the code was executed:

const twit = require("twit");
const Twitter = new twit(config);
const MAX_RT_COUNT = 1;

I found the Twitter ids for several users that I wanted to the bot to retweet. I used their ids instead of their screen names, in case a user decided to change their screen name. In order to keep track of who was who, I stored details about each user in a comment:

const USERS = [
  "15057943", // moma
  "14803372", // saam
  "5225991", // tate
  "22009731", // design museum
  "81783051", // artsy
  "17896874", // itsnicethat
  "158865339", // fastcodesign
  "21661279", // creative review
  "16336998", // print magazine
  "17623957", // design observer
  "418597196", // creativebloq
  "15446126", // design milk
  "18201801", // interior design
  "19038849" // how design
];

I made a function that would filter through the list of users, so that each day of the week, a different user would get a retweet from the bot:

const getUserOfTheDay = () => {
  let date = new Date();
  let dayOfMonth = date.getDate();
  let pickUserIndex = dayOfMonth % USERS.length;
  return USERS[pickUserIndex];
};

Next, I created the logic for retweeting tweets tied to different hashtags. I ultimately decided not to deploy this functionality, but I wanted to keep it around in case it’s useful in the future:

let retweetTags = async function() {
  try {
    const { data } = await Twitter.get("search/tweets", {
      q: "#art, #painting",
      result_type: "mixed",
      lang: "en"
    });

    const statuses = data.statuses.slice(0, MAX_RT_COUNT);
    // loop through the first n returned tweets
    for (const status of statuses) {
      // the post action
      const response = await Twitter.post("statuses/retweet/:id", {
        id: status.id_str
      });
      if (response) {
        console.log("Successfully retweeted");
      }
    }
  } catch (err) {
    // catch all log if the search/retweet could not be executed
    console.error("Err:", err);
  }
};

// retweetTags();

Lastly, I added the code for retweeting tweets from my list of users:

let retweetUsers = async function() {
  try {
    const { data } = await Twitter.get("users/show", {
      user_id: getUserOfTheDay()
    });

    const status = data.status;
    // make sure tweet isn't in reply to another user
    if (status.in_reply_to_status_id == null) {
      const response = await Twitter.post("statuses/retweet/:id", {
        id: status.id_str
      });
      if (response) {
        console.log("Successfully retweeted");
      }
    }
  } catch (err) {
    // catch all log if the search/retweet could not be executed
    console.error("Err:", err);
  }
};

To run the bot locally, I added retweetUsers(); to the file, then ran node index.js in the terminal.

Deploying the App to Heroku

Once I had my app up and running locally, I wanted to deploy it somewhere so it could run automatically. I did this by deploying it to Heroku.

I added a Procfile to the project, and added the line worker: node index.js to the file. Then I created a new Heroku project by running heroku create twitterbot-retweet. Next, I had to define the environment variables in Heroku by running heroku set:config key_name="key_value" in the terminal.

By accessing the Heroku dashboard online, I had to toggle on the worker for the bot (it was located under the “Dyno formation” section).

After deploying the bot, I realized I wanted the bot to run once every day, so I looked into options for how I could wake the application up once a day in order to execute the code. I ended up going with the simple setInterval method.

If your curious about how all the code looks, or want to see an up-to-date version of the project, you can find it on GitHub.

Deploying a React App to GitHub Pages

Earlier today, I worked on putting together this Sticky Note App, in an effort to get more comfortable with React.js. The application uses React.js, React DOM, and React Draggable.

After completing my application, I was about to tackle deployment with Heroku, since I’ve become pretty familiar with deploying various applications that consist of different stacks on Heroku.

However, this application was a lot simpler, so it seemed like using Heroku would have been a little excessive, especially since there’s no backend component for this application.

So I decided to tackle deploying the application via GitHub pages – which is already one of my favorite ways to deploy simple applications since I host all my repos there as well.

The first step I did, was use the create-react-app command in my terminal, where I then moved the various components of my simple React application. Then I followed the following steps:

Step 1

Edit package.json by adding a homepage

"homepage": "https://[insert username].github.io/[insert project repo name]"

Step 2

Run npm install --save-dev gh-pages

Step 3

Edit package.json by adding a predeploy and deploy script:

"scripts": {
"predeploy": "npm run build",
"deploy": "gh-pages -d build"
}

Step 4

Run: npm run deploy

And there you have it, a simple enough solution for deploying those simple enough React applications.

WDI Day Fifty-Eight: Project 4 Presentations and the Last Day of WDI

I can’t believe that three months have already gone by, and that WDI is over. It was a wonderful experience and I’m glad I decided to go through it. Today we had a chance to work on our projects in the morning, and in the afternoon we presented our project 4. I was pleasantly surprised that a lot of people enjoyed my application. I thought it was a rough project that wasn’t fully complete, but it was great seeing that others thought it was good.

After our presentations, we did a few group activities to close off our experience at WDI. We did an exercise where we had a piece of paper taped to our back and everyone walked around writing things we liked about other people so they were receiving anonymous compliments. A couple of the students in the class created certificates for everyone that were pretty humorous. We also received GA backpacks and did a toast at the end of class.

Overall, the experience has been a really positive one. I doubted myself a lot at times towards the end of the course, but overall I did indeed learn a lot. I also met such a wonderful group of people who I hope I can stay in touch with for years.

WDI Day Fifty-Seven: Project Week 4, Part 5

Using Rails and JavaScript for my project has proved to be a good move. Instead of struggling with the technology and building out an application, I have been able to focus on building out my app.

Today was a pretty successful day – I created icons for all of the different sections of the site. I also found a fix for the weird offset issue I was running into. I also added the ability for users to change the difficulty level of the puzzles they created. Overall, things are slowly falling into place, and I’ve successfully launched all changes to the deployed app on Heroku.

puzzle-me-pictures-screenshot

WDI Day Fifty-Six: Project Week 4, Part 4

My project is gradually coming together, and I’m feeling much better about things now that I’ve changed gears. I’ll definitely need to revisit front-end frameworks next week so I can feel more confident with them.

After spending a few hours working on my app, we had a break in the afternoon where the Outcomes team had a former instructor review the technical interview process that developers often go through. Since I’m not at all familiar with that process, it was pretty insightful to get a taste of what happens.

Later I played around with adding animations to my app, and discovered how fun SVG animations are. I’ll need to look into those more in-depth since they seem to be pretty powerful. Overall, today had several wins. I managed to set up user logins, deploy my app, add image uploading with AWS, spiced up the homepage with an animation, and looked into a few other ways to fine-tune the app. For tomorrow, I hope to work on the following:

  • Adding icons to each landing page
  • Rethink the puzzle index page
  • Rework the styling
  • Try to resolve the offset issue that makes the JavaScript puzzle act weird in Chrome and Firefox
  • Add seed data
  • Fine-tune the user experience for user logins

WDI Day Fifty-Five: Project Week 4, Part 3

I woke up at around 5am today to get started on rebuilding my project since I only have until Friday to finish it. I want to make sure that I can create as complete of an application as possible. I like how when my instructor heard that I was rebuilding my project, he told me that the deadline is really just an arbitrary date since we aren’t getting graded for the final project. But I told him that I still wanted to create something complete and portfolio-worthy. And that I can always revisit these more complex applications next week, when I don’t have the pressure of a deadline – even if the deadline is considered arbitrary.

I redid my application in Rails and managed the get the JavaScript puzzle functionality working, for the most part, as I’d like it to. Tonight I’ll work more on styling the application and fine-tuning the JavaScript functionality. Tomorrow I think I’ll add user login and launch it for the first time to see how it does live. Then I’ll take a look at some smaller “like to haves” that I’ll work on tackling one-by-one.

Ever since our third project, the group one, I’ve found myself feeling a little down about my abilities as a developer. I’ve been doubting myself a lot lately, and I’m realizing the problem is that I’m dealing with too many complex frameworks and concepts. Every now and then, I think it will be a good idea if I revisit concepts and technologies that I’m more comfortable with so that I can reassure myself that I am perfectly capable of building things. Sometimes it’s easy to get lost in the noise of all the languages and techniques that are out there. It’s a good thing to reevaluate where you stand.

WDI Day Fifty-Four: Project Week 4, Part 2

Over the weekend I spent a good chunk of time working on my project. And then again all day today and tonight I alway hacked away at it. Unfortunately, I had to come to the conclusion that I need to start the whole project over tomorrow. Why, you may ask?

Well, I didn’t realize that working with HTML5 canvas and React would prove to be a bit complicated. I also realized that I don’t understand React as thoroughly as I’d like to in order to create a complete and polished product.

When it came down to it, it was more important to me that I build something new to add to my portfolio that I can be proud of. After project week, I can always explore React and the MEAN stack once more. And at that point in time, I can also take my time with my work without the pressure of a project deadline.

WDI Day Fifty: Completed Lab & React Router and React with Backend

This morning our MEAN Stack and Web socket lab was due. I decided to work on something simple in order to help me get a better understanding of the technologies used, so I worked on a game of tic tac toe. Web sockets are pretty fascinating, and I hope to incorporate them into a few future projects.

tictactoe-screenshot

So far, the game doesn’t do everything that I’d like it to do. I haven’t used the database to persist the game data, so that’s one thing to add to my ‘to do’ list. I’d also like to add the following:

  • Prompting the user for their name
  • When users chat, having their names appear beside any remark made
  • Scoring

The rest of the day we did a code review of a React to do list application. React definitely seems a little easier than Angular to pick up, but I find myself wanting to spend a good chunk of time to building and piecing apart applications in order to get a better understanding of Angular as well as React.

WDI Day Forty-Eight: Web Sockets and Lab Time

Web sockets are a way that users can interact in real time with each other on websites. During class we did a quick tutorial where we created a chatroom – it was some pretty cool stuff. After walking through the chatroom with socket.io, we tried to add Angular to the mix, and yet again it tripped me up a bit.

In the afternoon the instructors announced the web socket lab, where we will have to build a game with the MEAN stack and use web sockets. I can’t believe how many labs we’ve had – here I thought this weekend I would be able to get a head start on my final project. Looks like I’ll be refactoring the lab that was due this morning and have to complete yet another project.

I still feel pretty shaky with Angular JS, so I’m going to attempt to do several tutorials over the weekend. I did manage to put a basic MEAN stack framework in place for my lab project that I’ll work on customizing more tomorrow. I am also going to attempt to create Tic Tac Toe.

WDI Day Forty-Six: Building a MEAN App & Starting a MEAN Lab

We had an introduction to adding Angular to the mix when building apps with Mongo DB, Express JS, and Node JS. However, the intro was a little too brief for everyone’s liking. Essentially we walked through an exercise that incorporated Angular with the rest of the stack, but not many of us were feeling at all confident with this new component.

After attempting to complete the in-class assignment, we were introduced to our lab for the week – building a MEAN stack application. We could either work in groups or alone. Although I enjoy working with others, when I’m struggling to retain new information, I do much better being able to struggle and absorb things on my own a little bit before returning to the group. Thus I opted for working on my own project.

It was a bit of a struggle – I tried to walk through the in-class assignment several times, but was unable to build something that could function. Next I started Googling all sorts of tutorials, desperate to find a working example of a way to format and use all these different pieces together. Luckily, I finally stumbled upon something that worked and helped me add basic CRUD functionality to the app. Once I had the working pieces in place, I pretty much called it a day. I was pretty sleep deprived from the day before, but I did indeed successfully complete a large chunk for the lab.

I’m hoping that tomorrow goes well and that I can successfully refine this application. I have a sturdy foundation now–all I want to do now is add to it and read over a few documents to make sure I’m understanding everything involved with the basics for the MEAN stack.