How I track unfollower with Twitter's REST Api
Tags: php, laravel, twitter
Published: 2020-02-07 13:12:12

---
title: How I track unfollower with Twitter's REST Api
published: true
date: 2020-02-06 23:00:00 UTC
tags: php, laravel, Twitter
canonical_url: https://wildauer.io/track-twitter-unfollowers/
---

Sometimes, I'm curious about who unfollow me on Twitter.   
So I had the idea, to write a little script to save all my followers in a simple text file line by line and then, I use [Git](https://git-scm.com/ "Git") to see the changes since the last time I executed it.

So far so good. I started with the composer package [abraham/twitteroauth](https://twitteroauth.com/ "The most popular PHP library for use with the Twitter OAuth REST API.").

> The most popular PHP library for use with the Twitter OAuth REST API.

It's an easy to use library when you want to interact with Twitter's Rest API. All what you need is a registered App on Twitter.You can create a folder somewhere and type `composer require abraham/twitteroauth`.   
Now create a file like `follower.php` and write this:

```
<?php

use Abraham\TwitterOAuth\TwitterOAuth;                                                                                  
                                                                                                                        
require "vendor/autoload.php";

$api = new TwitterOAuth(
	CONSUMER_KEY, 
	CONSUMER_SECRET, 
	ACCESS_TOKEN, 
	ACCESS_TOKEN_SECRET
);
```

That's it. `$api->` gives you now a lot of methods to interact with the Twitter's REST Api.

## A list of my followers

I searched in Twitter's REST API documentation and the only thing I found was the the possibility to get a list of IDs who follow me. [GET followers/ids](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-followers-ids "GET followers/ids").

> Returns a cursored collection of user IDs for every user following the specified user.At this time, results are ordered with the most recent following first — however, this ordering is subject to unannounced change and eventual consistency issues. Results are given in groups of 5,000 user IDs and multiple "pages" of results can be navigated through using the next\_cursor value in subsequent requests. See Using cursors to navigate collections for more information.  
> This method is especially powerful when used in conjunction with GET users / lookup, a method that allows you to convert user IDs into full user objects in bulk.

That looks good. With the list of the IDs I can use another endpoint to fetch the correct usernames to the IDs.   
I don't have 5000 followers, so I can ignore the cursored stuff.

Fetch all IDs who follow me

```
<?php
$userIds = $api->get("followers/ids", [
    'screen_name' => 'mnlwldr',
    'count' => 5000,
]);
```

It works. I get a response with a long list of IDs who follow me. Now I try to call the other endpoint to get the correct usernames because it's easier to read `mnlwldr` than `14367681`! The [GET followers/ids](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-followers-ids "GET followers/ids") documentation gave me already the hint to use [GET users/lookup](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-lookup "GET users/lookup").

> Returns fully-hydrated user objects for up to 100 users per request, as specified by comma-separated values passed to the user\_id and/or screen\_name parameters.This method is especially useful when used in conjunction with collections of user IDs returned from GET friends / ids and GET followers / ids.

Ok, that means I can send up to 100 IDs per request. I chunk the array of IDs I got from [GET followers/ids](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-followers-ids "GET followers/ids") with PHP's `array_chunk()` method and use `implode()` to generate a comma seperated list of IDs.

```
<?php
/* chunk the array in smaller pieces of 100 Ids */
$chunkedUserIds	= array_chunk($userIds, 100);

foreach($chunkedUserIds as $chunk) {

	/* call the users/lookup endpoint with comma seperated list of IDs */
	$profiles = $api->get('users/lookup', [
		'user_id' => implode(',', $chunk)
	]);

	/* Iterate over the response and print the name line by line */
	foreach($profiles as $profile) {
		print $profile->screen_name.PHP_EOL;
	}
}
```

Now I have two posibilities to wrote this in a text file.   
I can pipe the output into a file with `php follower.php > follower.txt`or I do it in the script

```
<?php                                                                                                        
/* chunk the array in smaller pieces of 100 Ids */                                                                         
$chunkedUserIds = array_chunk($userIds, 100);                                                                            

/* 'w' place the file pointer at the beginning of the file and truncate the file to zero length */
$fp = fopen('follower.txt', 'w'); 

foreach($chunkedUserIds as $chunk) {                                                                                       
   $profiles = $api->get('users/lookup', [                                                                                 
      'user_id' => implode(',', $chunk)                                                                                    
   ]);                                                                                                                     
   foreach($profiles as $profile) {                                                                                        
   	fwrite($fp, $user->screen_name . PHP_EOL);
	}                                                                                                                       
}                                                                                                                          
/* close the file */
fclose($fp);
```

Everytime we execute the script now, `follower.txt` will be updated and we can use `git diff` to see the changes.

The whole script

```
<?php

use Abraham\TwitterOAuth\TwitterOAuth;

require "vendor/autoload.php";

$api = new TwitterOAuth(
	CONSUMER_KEY, 
	CONSUMER_SECRET, 
	ACCESS_TOKEN, 
	ACCESS_TOKEN_SECRET
);

$userIds = $api->get("followers/ids", [
    'screen_name' => 'mnlwldr',
    'count' => 5000,
]);

                                                                                                        
/* chunk the array in smaller pieces of 100 Ids */                                                                         
$chunkedUserIds = array_chunk($userIds, 100);                                                                            
$fp = fopen('follower.txt', 'w');                                                                                                         

foreach($chunkedUserIds as $chunk) {                                                                                       
	$profiles = $api->get('users/lookup', [
		'user_id' => implode(',', $chunk)                                                                                    
	]);                                                                                                                     
	foreach($profiles as $profile) {                                                                                        
		fwrite($fp, $user->screen_name . PHP_EOL);
	}                                                                                                                       
}                                                                                                                          
fclose($fp);
```

I'm a huge fan of [Laravel's collections](https://laravel.com/docs/master/collections "Laravel collections").To refactor this to collections, all we need is [tightenco/collect](https://github.com/tightenco/collect "tighten/collect").   
`composer require tightenco/collect`

```
<?php

use Abraham\TwitterOAuth\TwitterOAuth;
use Tightenco\Collect\Support\Collection;

require "vendor/autoload.php";

$api = new TwitterOAuth(
    CONSUMER_KEY,
    CONSUMER_SECRET,
    ACCESS_TOKEN,
    ACCESS_TOKEN_SECRET
);

$userIds = $api->get("followers/ids", [
    'screen_name' => 'mnlwldr',
    'count' => 5000,
]);
$fp = fopen('follower.txt', 'w');

collect($userIds->ids)
    ->chunk(100)
    ->flatMap(function (Collection $userIds) use ($api) {
        return $api->get('users/lookup', [
            'user_id' => $userIds->implode(','),
        ]);
    })->each(function (stdClass $user) use ($fp) {
        fwrite($fp, $user->screen_name . PHP_EOL);
    });
fclose($fp);
```
That's it. You can commit and push the `follower.txt` in a github repo and do whatever you want :)