# Fetching GitHub repository Traffic data using API v3

GitHub records the **traffic data** (number of views and clones) to every repository. This can be seen in the `Insights -> Traffic` in the repository. Generally, the graph in the traffic tab shows the views and clones for the last 14 days. It shows not just the total views but also the number of unique visitors to the repository as shown in the below image. How can we fetch these data to populate into our own UI or to consume into some analytics?   

![Traffic data](https://docs.github.com/assets/cb-79092/images/help/graphs/repo_traffic_graphs_tooltip_dotcom.png)

This is where  [GitHub API v3](https://docs.github.com/en/rest/guides/getting-started-with-the-rest-api)  comes into the picture. Note here that `v3` stands for version 3 of API which works using standard HTTP. The latest version of GitHub API is `v4` which works on GraphQL. We are specifically using `v3` because the schema related to traffic data is not yet available for `v4`.  

Let us get started. First of all, let us initialize the new project by executing the command `npm init`. This will create a `package.json` file in the current directory.  

We need to  [create personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)  from GitHub to use API.  Once we get the token, create a `.env` file to store the token. Do not forget to add the `.env` file to `.gitignore` so that you don't commit the token accidentally to the public repository. The `.env` file looks as follows:
```
TOKEN=<PASTE YOUR TOKEN HERE>
```

We can install the required dependencies using the below command:
```
$ npm install octokit
$ npm install dotenv
```
 [Octokit](https://github.com/octokit/octokit.js) is an `npm` package created by GitHub to use GitHub API v3. It provides objects and functions to interact with API and to fetch the data smoothly.  
[Dotenv](https://github.com/motdotla/dotenv) is also an `npm` package that lets us use the variables defined in the `.env` file.  

Once the above setup is completed, we are ready to get started with the actual code to fetch the data.
Initially, we import the `Octokit` class from the `octokit` package and create an authenticated client object as shown below:
```
import dotenv from 'dotenv';
import { Octokit } from 'octokit';

dotenv.config();

client = new Octokit({ auth: process.env.TOKEN });
```
We import `dotenv` and call the `config()` method in the beginning of the flight so that it loads all the variables defined in `.env` files and we can use them by `process.env.<VARIABLE_NAME>`.  
We are using `Octokit` class to create a client object which takes the authentication token as an argument.  

You can take a look at  [API specifications](https://docs.github.com/en/rest/reference/repository-metrics#get-repository-clones) to understand more about the API. Here, we are only going to use `/clones` and `/views` endpoints to get the data but you can use any other endpoint as mentioned in the specification documentation.  

As mentioned in the documentation, both endpoints `/clones` and `/views` requires information about the `repository` name for which you want to get the traffic data and also GitHub `username` of the owner of the repository. Let us create a method that takes the above arguments and makes an API call to fetch the data (views and clones) 
```
async function getViewers(owner, repository) {
    return await octokit.request(
        `GET /repos/${owner}/${repository}/traffic/views`
    );
}

async function getCloners(owner, repository) {
    return await octokit.request(
        `GET /repos/${owner}/${repository}/traffic/clones`
    );
}
```
That is all we require to fetch the data. You can now observe that `octokit` makes life easier. We just need to provide URL of the endpoint and it gets the data. If you look at other endpoints in API documentation, you will see that it provides similar flexibility for `POST`, `PUT`, `DELETE` endpoints as well.  

Let us call above created methods and print the fetched data on the console with the following code:
```
let owner = 'ashutosh1919';
let repository = 'masterPortfolio';

getViewers(owner, repository)
    .then(res => console.log(`Viewers: ${res}`));

getCloners(owner, repository)
    .then(res => console.log(`Cloners: ${res}`));
```
Note that `getViewers()` and `getCloners()` are async method so either we can use `await` to get the response synchronously or we can use `then()` to get the response asynchronously.  

Below is the code for the entire file that we have written as of now:
```
import dotenv from 'dotenv';
import { Octokit } from 'octokit';

dotenv.config();

client = new Octokit({ auth: process.env.TOKEN });

async function getViewers(owner, repository) {
    return await octokit.request(
        `GET /repos/${owner}/${repository}/traffic/views`
    );
}

async function getCloners(owner, repository) {
    return await octokit.request(
        `GET /repos/${owner}/${repository}/traffic/clones`
    );
}

let owner = 'ashutosh1919';
let repository = 'masterPortfolio';

getViewers(owner, repository)
    .then(res => console.log(`Viewers: ${res}`));

getCloners(owner, repository)
    .then(res => console.log(`Cloners: ${res}`));
```
Above code does fetches the viewers and cloners (traffic) data and prints on the console. If the filename where the above code is stored is `index.js`, we can run it using `node index.js`. Make sure that you have latest stable version of  [NodeJS](https://nodejs.org/en/).  

On executing the above file, we get result shown as below:
```
Viewers: {
.
.
.
"data": {
    "count": 2973,
    "uniques": 970,
    "views": [
      {
        "timestamp": "2021-11-18T00:00:00Z",
        "count": 1,
        "uniques": 1
      },
      {
        "timestamp": "2021-11-19T00:00:00Z",
        "count": 189,
        "uniques": 63
      },
      {
        "timestamp": "2021-11-20T00:00:00Z",
        "count": 156,
        "uniques": 55
      },
      {
        "timestamp": "2021-11-21T00:00:00Z",
        "count": 186,
        "uniques": 76
      },
      {
        "timestamp": "2021-11-22T00:00:00Z",
        "count": 175,
        "uniques": 76
      },
      {
        "timestamp": "2021-11-23T00:00:00Z",
        "count": 278,
        "uniques": 77
      },
      {
        "timestamp": "2021-11-24T00:00:00Z",
        "count": 182,
        "uniques": 75
      },
      {
        "timestamp": "2021-11-25T00:00:00Z",
        "count": 181,
        "uniques": 84
      },
      {
        "timestamp": "2021-11-26T00:00:00Z",
        "count": 128,
        "uniques": 68
      },
      {
        "timestamp": "2021-11-27T00:00:00Z",
        "count": 208,
        "uniques": 73
      },
      {
        "timestamp": "2021-11-28T00:00:00Z",
        "count": 310,
        "uniques": 82
      },
      {
        "timestamp": "2021-11-29T00:00:00Z",
        "count": 331,
        "uniques": 104
      },
      {
        "timestamp": "2021-11-30T00:00:00Z",
        "count": 212,
        "uniques": 92
      },
      {
        "timestamp": "2021-12-01T00:00:00Z",
        "count": 282,
        "uniques": 83
      },
      {
        "timestamp": "2021-12-02T00:00:00Z",
        "count": 154,
        "uniques": 67
      }
}

Cloners: {
.
.
.
"data": {
    "count": 164,
    "uniques": 112,
    "clones": [
      {
        "timestamp": "2021-11-19T00:00:00Z",
        "count": 12,
        "uniques": 5
      },
      {
        "timestamp": "2021-11-20T00:00:00Z",
        "count": 1,
        "uniques": 1
      },
      {
        "timestamp": "2021-11-21T00:00:00Z",
        "count": 9,
        "uniques": 7
      },
      {
        "timestamp": "2021-11-22T00:00:00Z",
        "count": 12,
        "uniques": 12
      },
      {
        "timestamp": "2021-11-23T00:00:00Z",
        "count": 15,
        "uniques": 11
      },
      {
        "timestamp": "2021-11-24T00:00:00Z",
        "count": 11,
        "uniques": 8
      },
      {
        "timestamp": "2021-11-25T00:00:00Z",
        "count": 9,
        "uniques": 8
      },
      {
        "timestamp": "2021-11-26T00:00:00Z",
        "count": 11,
        "uniques": 9
      },
      {
        "timestamp": "2021-11-27T00:00:00Z",
        "count": 24,
        "uniques": 11
      },
      {
        "timestamp": "2021-11-28T00:00:00Z",
        "count": 7,
        "uniques": 6
      },
      {
        "timestamp": "2021-11-29T00:00:00Z",
        "count": 24,
        "uniques": 15
      },
      {
        "timestamp": "2021-11-30T00:00:00Z",
        "count": 13,
        "uniques": 13
      },
      {
        "timestamp": "2021-12-01T00:00:00Z",
        "count": 7,
        "uniques": 7
      },
      {
        "timestamp": "2021-12-02T00:00:00Z",
        "count": 9,
        "uniques": 7
      }
}
```
The above data can be consumed for different purposes in the applications, dashboards or CI/CD pipelines.

I (Ashutosh Hathidara) am an artificial intelligence engineer, full-stack developer, and designer. I can be reached via:  
Email: ashutoshhathidara98@gmail.com  
Twitter: [@ashutosh_1919](https://twitter.com/ashutosh_1919)  
Github: [@ashutosh1919](https://github.com/ashutosh1919)  
Discord: [DevSense](https://discord.gg/GkcbM5bwZr)  

