DEV Community

Cover image for Self-Destructing Tweets
Dennis O'Keeffe
Dennis O'Keeffe

Posted on • Originally published at blog.dennisokeeffe.com

Self-Destructing Tweets

I will be the first to admit it: I don't like social media.

It's not that I do not enjoy the idea of staying connected with the ones that I love and having a way to keep up with their lives. In fact, the dream would be to use social media for just that.

The reason I do not like social media is that social media has more control over me than I have over it. There, I admitted it. Happy?

Call me overly-optimistic, but I still believe that I can still somehow make it work. However, to make it work for me is going to require some fine tuning.

Fine-tuning for Facebook and Instagram meant deleting it. I did this six months ago. I am sure there will be a use case for the Facebook account down the track for business and advertising reasons, but applying Occam's razor to why I used both applications at the moment was not for business purposes, ergo I gave it the flick.

As for Twitter, it can be a real negative Nancy, however, I do get a number of really important notifications from there. What I want to do with Twitter is minimise the negativity and remove any trace of my history from the app where I can.

To start this process, I built a simple Twitter bot that runs on a cron job and will delete any tweet older than seven days from my profile.

In this tutorial, I will demonstrate the first part of deleting Tweets.

Prerequisites

  1. Basic Nodejs understanding.
  2. Basic Typescript understanding.
  3. Read my post on Building Your First Twitter Bot With JavaScript. I will not double over that content.
  4. Read my post on Using the AWS CDK to invoke a Lambda function during a cron job. I will not cover the cron job part today in this tutorial.
  5. Your required credentials for Twit.

Getting started

In a new folder of your choice, run the following:

npm init -y
npm i twit dayjs
npm i --save-dev @types/twit dotenv esbuild-node-tsc nodemon typescript
mkdir src
touch src/index.js tsconfig.json nodemon.json .env
Enter fullscreen mode Exit fullscreen mode

In this tutorial, I wanted to try out esbuild-node-tsc that I saw online last week and DayJS as I haven't yet had a chance to try that one out either!

Setting up Dotenv

If you followed the prerequisites, you will have your account keys.

Add the keys to the correct variable into .env:

TWITTER_CONSUMER_KEY=
TWITTER_CONSUMER_SECRET=
TWITTER_ACCESS_TOKEN_KEY=
TWITTER_ACCESS_TOKEN_SECRET=
Enter fullscreen mode Exit fullscreen mode

Setting up TypeScript, Nodemon.json and Package.json

In tsconfig.json, we are going to tell it to target Node requirements. We are adding the ES2020.Promise lib so we can make use of Promise.allSettled, but you could leave it out if you want to use Promise.all instead (not that any rejection will result in all rejecting if not allSettled).

Add the following to the file:

{
  "compilerOptions": {
    "target": "es2016",
    "module": "commonjs",
    "outDir": "./dist",
    "strict": false,
    "types": ["node"],
    "resolveJsonModule": true,
    "moduleResolution": "node",
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "esModuleInterop": true,
    "lib": ["ES2020.Promise"]
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "**/*.test.ts"]
}
Enter fullscreen mode Exit fullscreen mode

In nodemon.json, we are basically going to tell it is run etsc when a file changes with the ts extension.

{
  "watch": ["src"],
  "ignore": ["src/**/*.test.ts"],
  "ext": "ts",
  "exec": "etsc && node ./dist/index.js",
  "legacyWatch": true
}
Enter fullscreen mode Exit fullscreen mode

As for package.json, add the following to the scripts key (the rest is omitted for brevity):

{
  "scripts": {
    "build": "tsc -p .",
    "start": "nodemon"
  }
}
Enter fullscreen mode Exit fullscreen mode

Creating our Twitter helper file

# from the root
mkdir src/twitter
touch src/twitter/index.ts
Enter fullscreen mode Exit fullscreen mode

Inside of src/twitter/index.ts, add the following:

import Twit from "twit"
import { config } from "dotenv"
// Init env vars from the .env file
config()

// Initialise our twitter client
const client = new Twit({
  consumer_key: process.env.TWITTER_CONSUMER_KEY,
  consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
  access_token: process.env.TWITTER_ACCESS_TOKEN_KEY,
  access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET,
})

// enum to prevent hardcoded string issues
enum TwitterEndpoints {
  updateStatus = "statuses/update",
  destroyStatus = "statuses/destroy/:id",
  getUserTimeline = "statuses/user_timeline",
}

// Getting tweets from the user timeline
type GetUserTimelineFn = (params?: Twit.Params) => Promise<Twit.PromiseResponse>
export const getUserTimeline: GetUserTimelineFn = params =>
  client.get(TwitterEndpoints.getUserTimeline, params)

// Destroy Many Tweets
interface IDestroyManyParams {
  /* Tweet IDs */
  tweets: Twit.Twitter.Status[]
}
type DestroyManyFn = (
  params: IDestroyManyParams
) => Promise<PromiseSettledResult<Twit.PromiseResponse>[]>
export const destroyMany: DestroyManyFn = ({ tweets }) => {
  const promiseArr = tweets.map(tweet =>
    client.post(TwitterEndpoints.destroyStatus, { id: tweet.id_str })
  )
  return Promise.allSettled(promiseArr)
}
Enter fullscreen mode Exit fullscreen mode

This post expects you to be able to understand the above, but the long and short of it is that we are using dotenv to require the local variables from the .env file.

We then have two main functions getUserTimeline and destroyMany that will get up to n tweets from your account and then destroy all those tweets respectively.

Now it is time to write the main script that will make use of these functions.

Writing the main script

In src/index.ts, add the following:

import dayjs from "dayjs"
import { Twitter } from "twit"
import { getUserTimeline, destroyMany } from "./util/twitter"

type UserTimelineResponse = {
  data: Twitter.Status[]
}

export const main = async () => {
  try {
    // casting as typing Twit.Response gives incorrect data structure
    const res = (await getUserTimeline({ count: 200 })) as UserTimelineResponse

    const tweetsToDelete = []
    for (const tweet of res.data) {
      if (dayjs(tweet.created_at).isBefore(dayjs().subtract(7, "day"))) {
        tweetsToDelete.push({
          text: tweet.text,
          id_str: tweet.id_str,
        })
      }
    }

    const manyDestroyed = await destroyMany({
      tweets: tweetsToDelete,
    })
    console.log(manyDestroyed)
  } catch (err) {
    console.error(err)
  }
}
Enter fullscreen mode Exit fullscreen mode

Here we are waiting to get the maximum tweet count (200) with our getUserTimeline call, then iterating through the response data to figure out if the created date is older than a week. If it is, we are pushing it to a tweetsToDelete array and then finally passing that array to destroyMany.

We log out the manyDestroyed variable to see which requests were fulfilled and had the tweets deleted.

Running the script

To run the script mode, run npm start (to run with nodemon in watch mode). This will start Nodemon and if successful you will see your tweets older than 7 days beginning to delete!

If you've tweeted more than 200 times, you may need to run the script over again a few times until it is coming back with no more to delete!

Conclusion

This was a quick-fire post, but it was an overview of how I wrote a script to start deleting my tweets older than a week!

Moving on from here, I set up a cron job to run every day at midnight to re-check and delete any other tweets.

I am really hoping this gives inspires (I use the term loosely) to stop posting on Twitter and use it to consume. My next move with Twitter will be to add something that filters tweets on in my feed using some ML/AI.

Resources and Further Reading

  1. Building Your First Twitter Bot With JavaScript
  2. Using the AWS CDK to invoke a Lambda function during a cron job
  3. Twit - GitHub
  4. esbuild-node-tsc - GitHub
  5. DayJS - GitHub

Image credit: Patrick Perkins

Originally posted on my blog. Follow me on Twitter for more hidden gems @dennisokeeffe92.

Top comments (12)

Collapse
 
weedshaker profile image
weedshaker

Dude, I totally feel you!

For the same reason I wrote peerweb.site/, so that I can avoid posting on their servers and remove context from my account to/from the posted content.

I will also take your code as an inspiration, once I got to move everything to mastodon.social / minds.com/ or at least mirror it.

Collapse
 
csgeek profile image
csgeek

minds.com is new to me but it seems like every week there is a new 'own your data' insert bit-coin-of-some-kind implementation. mastodon is awesome though. I just wish i knew more people on it.

Collapse
 
okeeffed profile image
Dennis O'Keeffe

Yeah, nice! How good!

Collapse
 
csgeek profile image
csgeek

I wrote something similar in Java that basically adds a ttl to everything I post. My grand vision was to support all social media that just eats there breadcrumbs I leave behind.

I really wish self destructing messages were more common.

That's my favorite feature of keybase chat.

My week old conversation is irrelevant it has no reason to exist beyond that time frame.

Collapse
 
okeeffed profile image
Dennis O'Keeffe

Ahhh ttl is a great idea!

Agree on wishing for more self-destructing messages. I was looking at the Facebook Graph API as well and (unsurprisingly) it didn't look like they grant you much control over deletion.

Collapse
 
csgeek profile image
csgeek

My idea was to just have a service that ties to a web page where you can choose the media and give a TTL based on content. Then just have the service run every N time or be reactive depending on how you architect it but the general idea is:

tweet: delete every 7 days
DMS: keep?
FB photo: no TTL, or maybe 1 year.

Of course you can do this on a per message as well when you send it, but the more social services you add and supported content type the more complex it gets. Though if anyone wrote something like this, I would love to use it.

This needs a lot of love, but if anyone finds value in it, there's the code: github.com/SocialOxpecker/SocialOx...

Collapse
 
allands profile image
Lan

How do you think social media makes you tweet self destructive content? and why so?

Collapse
 
csgeek profile image
csgeek

Actually, my issue with a tweet is that it only has relevance for what.. a few hours? Maybe a day. After that it's only purpose for existing is a historical record of stupid things you probably should not have said.

So I'd love to have a self destruct ability that allows me to somewhat vent about something that's frustrating me and not have to worry about bitching about javascript being horrible (just an example) then applying to a nodejs gig and having to revisit that.

There's countless examples of people losing jobs and opportunities due to things said/done/take out of context and so on.

Collapse
 
allands profile image
Lan

thats why people usually have a non identified twitter. Professional profiles are usually on instagram. I get you though. It's weird how we simply get used to vent to the whole world, but at the same time it's not like we want an answer xd

Collapse
 
okeeffed profile image
Dennis O'Keeffe

In terms of the tweeting, it's (hopefully) not that I am tweeting content that needs to be removed but that I personally get addicted to checking it for interactions. It's not just social media - even work tools like Slack get to that point if I am constantly expecting notifications and checking it.

A lot of it for me is more along the lines of "if you don't want to eat chocolate, don't put it in the pantry". It is easier for me to remain self-disciplined that way!

Collapse
 
allands profile image
Lan

That line of thought works for me as well, but the way I try to implement it is by not using other social medias, except for twitter(as you said, theres some useful content there). The happy part is that it has already improved alot, since I don't really feel like using facebook or instagram anymore xd.

Really liked your article. Have a great day :)

Collapse
 
jessicagarson profile image
Jessica Garson

This is an interesting use case. Thanks for sharing.