How I Made My Tweets Ephemeral with Node and Webtask

A couple of weeks ago I stumbled upon this article by Vicky Lai called Why I’m automatically deleting my old tweets using AWS Lambda. It hit me at a time when I just started to rekindle my love for minimalism and digital detox and I was immediately intrigued with the thought of making my tweets ephemeral, i.e. deleting them after a certain number of days. Because, let’s face it, a tweet from way back then should not have the power to let other people make assumptions on who you are today.

We change our opinions, our desires, our habits. We are not stagnant beings, and we should not let ourselves be represented as such, however unintentionally.

—Vicky Lai

After looking at Vicky’s Go code I got excited to try this in Node and use Webtask to host my ephemeral-tweets microservice.

The Code

The code for ephemeral-tweets is written in ES6 and uses features like const, fat arrow functions, destructuring, and Promises. I also use Webtask’s secrets (similar to environment variables, exposed via the microservice’s context parameter) for private Twitter credentials and the maximum age of the tweets you want to keep, represented in days.

module.exports = function(context, done) {
  const maxTweetAge = context.secrets.MAX_TWEET_AGE * dayInMs

  const twitterClient = new Twitter({
    consumer_key: context.secrets.CONSUMER_KEY,
    consumer_secret: context.secrets.CONSUMER_SECRET,
    access_token: context.secrets.ACCESS_TOKEN,
    access_token_secret: context.secrets.ACCESS_TOKEN_SECRET
  })

  ...
}

I use the twit library to connect to and query the Twitter API, mainly because it offers all the convenience methods you would expect, promises, and exposes the full response object (for watching rate limits, for example).

The ephemeral-tweets microservice retrieves 200 tweets per call from your timeline (as per Twitter’s API limit for GET statuses/user_timeline), filters them by MAX_TWEET_AGE and deletes the ones that are older.

In case you wondered why I left the console.log calls in there: Depending on how you develop your task (whether locally or inside the Webtask Editor) Webtask pipes console.log output to the console or to the editor’s log panel which is great help during development.

...

twitterClient.get('statuses/user_timeline', {
  count: 200
})
.then(({data: tweets}) => {
  let deleteRequests = tweets
    .filter(tweet => {
      return new Date() - new Date(tweet.created_at) > maxTweetAge
    })
    .map(tweet => {
      return new Promise((resolve, reject) => {
        twitterClient.post('statuses/destroy/:id', {
          id: tweet.id_str
        })
        .then(({data: deletedTweet}) => {
          console.log(`Deleted tweet #${deletedTweet.id_str}: "${deletedTweet.text}"`)
          resolve(deletedTweet)
        })
        .catch(err => {
          console.log(err)
          reject(err)
        })
      })
    })

  return Promise.all(deleteRequests)
})
.then(deletedTweets => {
  console.log(`Done. Deleted ${deletedTweets.length} tweets.`)
  done(null, { deletedTweets })
})
.catch(done)

This is it! You can find the code on GitHub and refer to the README for instructions on how to build, customize, schedule, and deploy this microservice for your own Twitter account.

A Note on (Rate) Limits

There are some limits I want to point out, especially to people with a lot of tweets on their timeline wanting to run this task often in the beginning: