FixYoureYour, the short-lived Twitter bot

Josiah Keller // June 2016 // Code available on GitHub

On a Thursday afternoon, I was lazily scrolling through my Twitter timeline when I saw this Tweet:

A twitter bot that corrects people's use of "you", "your", and "you're" in longer Tweets—even when they got it right to begin with.

— Sampson ✏ (@jonathansampson) June 2, 2016

For a long time I had been wanting to write a Twitter bot, but I hadn't done it because I had no idea what kind of bot to write. Well, here was an idea, packaged up in 140 characters for me.

Two days later, I decided to go for it. I registered the Twitter account @FixYoureYour, and started writing some code.

I had already worked with the Twitter API before, but using PHP. This time, I decided to implement the bot as a Node script. I didn't really feel like writing PHP. Plus, Node scripts are very well suited to simply being run from the command line. I set up a directory for my project and installed twitter-node-client from npm.

In order to interact with the Twitter API, you need an API key and secret. In addition, in order to act on behalf of a Twitter account, you need an access token and secret associated with that account. To get the API key and secret is easy - you just go to the Application Management portal at apps.twitter.com, create an app, and then get it from the "Keys and Access Tokens" tab. The access token is a little different. Normally, you present a user with a Twitter login prompt, and then Twitter sends you back OAuth credentials that your app uses to act on the user's behalf. In this case, I didn't want to go to the trouble of implementing all that infrastructure since this app was only ever going to have to control its own account. As it happens, Twitter provides a feature for just that scenario. On that same "Keys and Access Tokens" tab, there's an option to create an access token for your own account. You can simply take the information it gives you and stick it in a configuration file along with your API key. (of course, that means the bot's account has to be the account that owns the app)

My config file was as simple as this:

        const config = {
            "consumerKey": "...",
            "consumerSecret": "...",
            "accessToken": "...",
            "accessTokenSecret": "...",
            "callbackUrl": "..."
        };
        module.exports = config;
    

This was in a file called twitter-config.js, which I included from the main index.js file — and, of course, put in my .gitignore.

(In hindsight, I'm not really sure why I called the main file index.js. I guess it's a habit I developed in the olden days, before all this fancy npm stuff, when starting a new project meant creating a new directory with an index.html file in it)

I spent the rest of Saturday, June 4, and afternoon of Sunday the 5th writing and then tweaking the basic functionality. It ran in half-hour cycles, where it would use the Twitter search API to grab some Tweets containing the words "your", "youre", or "you're". After retrieving Tweets, it would process each one as follows:

  1. Figure out which word we need to correct and its location in the string.
  2. If the Tweet starts with "RT", or meets some other conditions detailed below, skip it.
  3. Figure out what word we're going to use as the "correction"
    • It took a very basic look at the context of the Tweet. If it matched a few specific cases, then the bot actually knew the correct word and would usually use it.
    • Otherwise, it would randomly pick a correction. It would draw from these four words: "your", "you're", "yore", and "yer". There was a much higher probability of selecting one of the first two rather than those last two joke responses. Since there was such a limited pool, the correction was usually either wrong, or the same word as the original Tweet used.

At first, I simply had the bot log the correction to the console so that I could see it was working. Once I thought I had it working reasonably well, I added an API call to actually tweet the correction.

I also added the ability for the bot to check its mentions. That way, if someone responded to it, and the response happened to contain "you're" or "your", the bot could correct them a second time. However, I added a dictionary of usernames so that the bot would remember who it had interacted with and not continuously harass someone.

I encountered a couple of unexpected problems along the way. The first problem was that, unfortunately, Twitter is rife with spam bots that all tweet the same garbage simultaneously. Worse, a lot of them are porn accounts. During one cycle, I noticed FixYoureYour's logs showed a bunch of Tweets that looked the same. It had just happened that about half a dozen porn bots all Tweeted exactly the same crap all at once, and all of them got caught up in FixYoureYour's search. I added a blacklist of words for the bot to stay away from. It was a file called inappropriate.js, structured very similarly to the config file.

The other problem I ran into was that later in the evening, new Tweets apparently were not coming in fast enough, resulting in some duplicates turning up in FixYoureYour's searches. The Twitter search system isn't real-time, and I had also chosen to have FixYoureYour pull from the "Top" search results instead of "All." I was hoping that this way, the bot would be more likely to pick up Tweets from prominent accounts and get more exposure. Anyway, I added some code to remember the IDs of Tweets the bot had already engaged with so that it would ignore duplicates. Since there were now so many conditions where FixYoureYour might ignore a Tweet, sometimes a cycle would result in no acceptable Tweets being found. So I modified the search function to cast a wider net, but then set a limit of 5 replies per cycle so that I wouldn't get rate-limited by the API.

FixYoureYour's Fate

After I had it working pretty smoothly, I left it running in a PowerShell window while I went about my other business. Every half hour, however, I would take a look back at the browser window where I had the @FixYoureYour profile pulled up, so that I could see who it had trolled this cycle. Using FixYoureYour's account, I manually replied to Jonathan Sampson's original tweet so that he'd see it.

@jonathansampson *yore ;)

— Fix You're Your (@FixYoureYour) June 5, 2016

He must have thought it was funny, because he Tweeted about it later.

Haha! Somebody actually did it. @FixYoureYour is alive! I freaking love Twitter 😜 https://t.co/XvnxuxAGHK

— Sampson ✏ (@jonathansampson) June 6, 2016

Before long, I was ready to get some sleep. I wasn't yet confident that it was ready to leave unattended overnight, so I killed the script, manually pinned a Tweet explaining that the bot was down for the night, and planned to start it back up in the morning.

The next morning, I started the script up again, but when it tried to send out its Tweets, it received error responses back from the API. It turned out that the FixYoureYour application had had its write privileges revoked. I had expected worse. About halfway through the development process, I had abruptly remembered that Twitter has a set of rules about automated accounts. I went and found the document explaining the rules, and it turned out that one of the rules specifically prohibits automatically sending replies based on a keyword search, which is exactly how FixYoureYour works. I decided to keep working on the bot anyway, because I had already spent a fair amount of time on it, and I figured the worst Twitter would probably do is suspend the account. They didn't even do that, they just shut off its API write access.

So that's the story of FixYoureYour: a Twitter bot that only lived one day. But it was a fun weekend project, and I learned a few things about ES6, which I hadn't messed around with before.

For anyone who might happen to be interested, the code (except for the config and blacklist files) is up on GitHub.