Tutorial: Adding Analytics to the CryptoPunks V1 Site
Published: 2022-04-13 18:29:17

For an NFT project, it can be hard to add items like recent sales and charts to a website. There are existing NFT APIs; however most require API keys that you wouldn't want to expose to your users. Let's use the fully open (and free) [Sort API](https://docs.sort.xyz) to add analytics to the CryptoPunks V1 website using only client-side Javascript.

We'll include the full example (which you can inspect to see the code) below.

![Screenshot of completed site](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jv789v5zzwn579v6ngnz.png)

## Adding a real-time sales feed

**First, we are going to query the [transaction API](https://docs.sort.xyz/api-docs/reference/api-reference/transaction) using a POST call to get some information about the punks contract**

```
POST https://api.sort.xyz/v0/transaction

BODY:
{
      "nft_event": "sale",
      "nft_address": "0x282bdd42f4eb70e7a9d9f40c8fea0825b7f68c5d",
      "limit" : 10,
      "timestamp" : "gte:2022-04-01",
      "fields" : { "logs" : 0, "function" : 0 }
}
```

- nft_event - only look for sales
- nft_address - use the CryptoPunks V1 contract address
- limit - get the latest 10 results
- timestamp - only search after 2022-04-01 (greater than or equal to, gte)
- fields - omit 2 very long fields from the response to increase performance

**Write our Javascript**

```
var sortxyz_result = await axios.post('https://api.sort.xyz/v0/transaction',
    {
      "nft_event": "sale",
      "nft_address": "0x282bdd42f4eb70e7a9d9f40c8fea0825b7f68c5d",
      "limit" : 10,
      "timestamp" : "gte:2022-04-01",
      "fields" : { "logs" : 0, "function" : 0 }
    }
);
 
let sortxyz_data = sortxyz_result.data.result;
for (var i=0; i<sortxyz_data.length; i++) {
  // Fill in our HTML
}
```

Notice the field values from the API response we'll use in our HTML:

```
 new_sale.innerHTML = 
    "<div class=\"row\"> " + 
      "<div class=\"col\"> " +
        "<img width=\"75\" class=\"lazyload\" src=\""+sortxyz_data[i].nft.image_url+"\" />" +
      "</div>" +
      "<div class=\"col\">" +
        "<div>" + sortxyz_data[i].nft.value_eth + "</div>" +
        "<div>#" + sortxyz_data[i].nft.token_index + "</div>" +
      "</div>" +
    "</div>";
```

- nft.image_url - The URL to the image of the punk sold
- nft.value_eth - Value of sale in ETH (no conversions needed)
- nft.token_index - The ID of the punk sold

**Display our feed**

![CryptoPunks V1 Sales Feed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bd0epf3p2ssui91hjmcu.png)

## Adding a scatter plot chart for recent sales

We'll use the same API call from the previous sales feed, however, we'll use the timestamp from the transaction in our bubble/scatter plot chart.

```
POST https://api.sort.xyz/v0/transaction

BODY:
{
      "nft_event": "sale",
      "nft_address": "0x282bdd42f4eb70e7a9d9f40c8fea0825b7f68c5d",
      "limit" : 10,
      "timestamp" : "gte:2022-04-01",
      "fields" : { "logs" : 0, "function" : 0 }
}
```

**Use the timestamp in our chart**

```
let sortxyz_data = sortxyz_result.data.result;
for (var i=0; i<sortxyz_data.length; i++) {
  let chart_item = {
      "y": sortxyz_data[i].nft.value_eth,
      "date" : sortxyz_data[i].timestamp,
      "value": sortxyz_data[i].nft.value_eth,
      "image": sortxyz_data[i].nft.image_url,
      "punk" : sortxyz_data[i].nft.token_index
  }
  ...
}
```

- For the date of the transaction, we'll use 'sortxyz_data[i].timestamp'

**Add our chart**

![Recent sales chart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0uqyuxzf15t33pywukki.png)

## Adding a chart for average sale price

We'll need to aggregate data to get the average CryptoPunks V1 sales price per day.

```
BODY:
{
      "nft_event": "sale",
      "nft_address": "0x282bdd42f4eb70e7a9d9f40c8fea0825b7f68c5d",
      "aggregate" : { "op" : "avg", "by" : "day", "field" : "nft.value_eth" },
      "limit" : 10,
      "timestamp" : "gte:2022-04-01"
}
```

- nft_event, nft_address - same as before, no changes here
- aggregate - get the avg value of the field 'nft.value_eth', bucketed by day
- limit - last 10 results
- timestamp - start at 2022-04-01

**Parsing the aggregation API result**

```
let sortxyz_data = sortxyz_result.data.result;
let position = 0;
for (var i=0; i<sortxyz_data.length; i++) {
    let chart_item = {
      "y": sortxyz_data[i].total,
      "x": position,
      "date" : sortxyz_data[i].timestamp
}
```

The result from this API call has a different format from previous API calls, since we're aggregating data instead of returning enriched transactions.

**Add our chart**

![Average Daily Price](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bol8zjpntihnr0ohjhts.png)

## Bonus: Add contract events

We can add additional information, such as contract events (not shown within the mockups).

```
POST https://api.sort.xyz/v0/transaction

BODY:
{
      "contract_address": "0x282bdd42f4eb70e7a9d9f40c8fea0825b7f68c5d",
      "limit" : 10
}
```

## Putting it all together

Access the [completed example here](https://sort.xyz/mockups/punksv1.html) (view source code to see complete Javascript examples). 

View the [Sort API docs](https://docs.sort.xyz) to learn more, and create even more complex aggregations and queries.