1

I have set up a function to call the Bitly API to track total clicks for my links. It is set up in a column to track clicks for each individual link. It updates perfectly every time I open the spreadsheet.

enter image description here

Here is the code for this

function bitlyStats(bitlink_url) {
  var bitlink_url_parts = bitlink_url.split('://');
  var bitlink = bitlink_url_parts[1];
  var accessToken = 'token';
  var fetchUrl = 'https://api-ssl.bitly.com/v4/bitlinks/' + bitlink + '/clicks/summary?unit=day&units=1';
  var headers = {
    'Authorization': 'Bearer '+ accessToken,
    'Content-Type': 'application/json',
  };
  var params = {
    'method' : 'get',
    'headers' : headers,
    'muteHttpExceptions' : true
  };
  var response = UrlFetchApp.fetch(fetchUrl, params);
  var clickCount = JSON.parse(response).total_clicks;
  return clickCount;
}

I've set up a second function to append these results to a second tab in the sheet each day. I have set up a trigger for BitlyStats to update overnight, and then to run the append function. However I get an error on the trigger for BitlyStats..

TypeError: bitlink_url.split is not a function at bitlyStats(BitlyStats:10:39)

This causes the append function to copy "#NAME?" in every cell on the second tab. I am not sure why there is an error when the function works find on open?

Any advice would be highly appreciated! Thanks.

EDIT After some feedback and a potential answer, it is clear that the time based trigger wont work with a function that references what is input in the cell. I am now trying to create an API call function for "bitlink_url" instead so it creates a list of bitlinks instead of the list already being in the sheet.

However I am running into issues with the new code, any advice would be appreciated. I am still very new to this. Thankyou! This is the reference guide I am using https://dev.bitly.com/api-reference#getBitlinksByGroup

The log shows "null"

function getBitly() {
  var accessToken = 'x'; //access token
  var groupID = 'x' ; //group ID
  var fetchUrl2 = 'https://api-ssl.bitly.com/v4/groups/' + groupID + '/bitlinks?size=10';
  var headers = {
    'Authorization': 'Bearer '+ accessToken,
    'Content-Type': 'application/json',
  };
  var params = {
    'method' : 'get',
    'headers' : headers,
    'muteHttpExceptions' : true
  };
  var response2 = UrlFetchApp.fetch(fetchUrl2, params);
  var bitlinkList = JSON.parse(response2).link;
  Logger.log(bitlinkList);

##EDIT2 - resolved## Thanks to @lamblichus I was able to revise the code and resolve the issue of having to reference each cell that the Bit.ly URL was saved in using the map function. Final code below. I have also incorporated the Append values code into the same function.

function getStats() {
  var sheet = SpreadsheetApp.getActive().getSheetByName("VV Bitly Links");
  var bitlyurls = sheet.getRange(2,12,sheet.getLastRow()-1).getValues().flat();
  var clickCounts = bitlyurls.map(bitlink => [bitlyStats2(bitlink)]);
  sheet.getRange(2,6,clickCounts.length).setValues(clickCounts);
  var sheet2 = SpreadsheetApp.getActive().getSheetByName("Bitly Reporting");
  var data = sheet.getRange(2,6,sheet.getLastRow()-1,6).getValues();
  var lastrow = sheet2.getLastRow();
  sheet2.getRange(lastrow+1,1,data.length,data[0].length).setValues(data);
}

function bitlyStats2(bitlink) {
  var accessToken = 'xx'; //token
  var fetchUrl = 'https://api-ssl.bitly.com/v4/bitlinks/' + bitlink + '/clicks/summary?unit=day&units=1';
  var headers = {
    'Authorization': 'Bearer '+ accessToken,
    'Content-Type': 'application/json',
  };
  var params = {
    'method' : 'get',
    'headers' : headers,
    'muteHttpExceptions' : true
  };
  var response = UrlFetchApp.fetch(fetchUrl, params);
  var clickCount = JSON.parse(response).total_clicks;
  return clickCount;
}

function installTrigger() {
  ScriptApp.newTrigger("getStats")
  .timebased()
  .atHour(3)
  .everyDays(1)
  .create();
}

finally, since this references a lot of Bit.ly links, some of which aren't active any more and return 0 clicks in a day, I have created another function to delete empty cells from the second tab "Bitly Reporting"

var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName("Bitly Reporting");
var range = sh.getDataRange();
var delete_val = ""
var col_to_search = 1;
function deleteEmptys(){
  var rangeVals = range.getValues();
  for (var i = rangeVals.length-1; i >=0; i--){
    if(rangeVals[i][col_to_search] === delete_val){
      sh.deleteRow(i+1);
    };
  };
};

function installTrigger2() {
  ScriptApp.newTrigger("deleteEmptys")
  .timebased()
  .atHour(5)
  .everyDays(1)
  .create();
racker
  • 29
  • 6
  • Can I ask you about the detail of `a second function` of `I've set up a second function to append these results to a second tab in the sheet each day.`? – Tanaike Mar 11 '21 at 00:19
  • Can you provide the code related to this second function, as well as the function that is called by the time-trigger? If I understand you correctly, the trigger runs a function that includes `bitlystats` and your other function: `I have set up a trigger for BitlyStats to update overnight, and then to run the append function`. – Iamblichus Mar 11 '21 at 09:45
  • No worries, here is the append code function. I have set up triggers to fire function bitlyStats and appendValues to run overnight ```function clickhistory() { var ss = SpreadsheetApp.getActiveSpreadsheet(); var sheet1 = ss.getSheetByName("VV Bitly Links"); var sheet2 = ss.getSheetByName("Bitly Reporting"); var data = sheet1.getRange(2,6,sheet1.getLastRow()-1,6).getValues(); var lastrow = sheet2.getLastRow(); sheet2.getRange(lastrow+1,1,data.length,data[0].length).setValues(data); }``` – racker Mar 12 '21 at 01:09
  • Each morning I check the Bitly Reporting tab which the values are set to append to and new cells have been appended all with #NAME? in each cell. If I run the functions manually each day it works perfectly. It is something to do with the trigger overnight. – racker Mar 12 '21 at 01:11
  • Hi, I have posted an answer. If you provide more information on how you are retrieving `bitlink_url`, I could be more precise about the solution. In any case, I hope this is useful to you. – Iamblichus Mar 12 '21 at 09:31
  • `it is clear that the time based trigger wont work with a function that references what is input in the cell` This is not necessarily true. It's just that you cannot pass it as parameter, but you can retrieve it from inside the function. That would probably be easier than what you're trying to do now. Can you provide more details about how you retrieve `bitlink_url` when you run this manually? Are you using `bitlyStats` as a [custom function](https://developers.google.com/apps-script/guides/sheets/functions)? If you clarify that, I'll like to edit my answer in order to adapt it to your needs. – Iamblichus Mar 15 '21 at 08:51
  • Thanks @lamblichus sorry for my confusion. I have set up a Zapier automation so everytime a new bitlink is created, it ads the https://bit.ly.xxxxx link to my Google sheet in column A. I am using `bitlyStats` as as custom function in cell B (as per the screenshot in my original post) that references the A cell next to it. How can I avoid passing it as a parameter? – racker Mar 15 '21 at 23:01
  • Not sure if you are aware of this, but executing `bitlyStats` through a time-based trigger won't update the custom functions you have set up. Can you provide more details on why do you want to run this via a time-based trigger and, specially, where in your code (if anywhere) are you referencing `bitlink_url`, which you thought was getting passed as a parameter? – Iamblichus Mar 16 '21 at 09:25
  • If you just want to update column `B` periodically with the new counts, you could get rid of the custom functions and modify `bitlyStats` in order to retrieve all the urls, calculate the counts and write them to your sheet. If that's your purpose, I'd like to edit my answer explaining in detail how to do this. – Iamblichus Mar 16 '21 at 09:26
  • Thanks @lamblichus, yes I want column B (currently utilising bitlyStats) to update daily so I can then append the values to the second tab. This tab is being utilised in a data studio report. I know there is a way to call for a list of Bitly links through the API and that was what I was attempting to do with my additional code. Any advice here would be appreciated. Thankyou. – racker Mar 17 '21 at 02:22
  • Hi racker I have updated my answer, let me know if that works for you. – Iamblichus Mar 17 '21 at 09:13

1 Answers1

0

Issue:

You cannot pass parameters to a function triggered through a time-driven trigger. Because of this, bitlink_url is undefined, so bitlink_url.split('://') gives an error.

Solution:

  • Either set up a default parameter for bitlyStats:
function bitlyStats(bitlink_url = "YOUR_URL") {
  • Or call a wrapper function instead in your trigger, so that bitlink_url is defined:
function timeTriggeredFunction() {
  var bitlink_url = "YOUR_URL";
  bitlyStats(bitlink_url);
}

Update:

You have a series of URLs in column A, and you want to update column B periodically, based on those URLs (using bitlyStats).

In this case, I'd suggest not using custom functions, which cannot be called via a time-driven trigger, but install a trigger that will call a function (named triggeredFunction in the sample below) that will:

  • Retrieve the URLs from column A.
  • For each URL, retrieve its clickCounts, using bitlyStats.
  • Write the resulting clickCounts to column B.

Code sample:

function triggeredFunction() {
  var sheet = SpreadsheetApp.getActive().getSheetByName("Sheet1");
  var bitlink_urls = sheet.getRange(2,1,sheet.getLastRow()-1).getValues().flat();
  var clickCounts = bitlink_urls.map(bitlink_url => [bitlyStats(bitlink_url)]);
  sheet.getRange(2,2,clickCounts.length).setValues(clickCounts);
}

function installTrigger() {
  ScriptApp.newTrigger("triggeredFunction")
  .timeBased()
  .atHour(3)
  .everyDays(1)
  .create();
}

Note:

  • In the sample above, the time-driven trigger is installed programmatically by running installTrigger once, and by this, triggeredFunction would run every day between 3 and 4 AM. You could also install it manually and modify the trigger settings according to your circumstances.
  • In the sample above, it is assumed that the sheet with data is named Sheet1. Change that if it's not the case.
Iamblichus
  • 18,540
  • 2
  • 11
  • 27
  • Thanks @lamblichus for the potential answer. Since I have a long list of bitlinks to report on daily it would be too time consuming to create variables for each and every link. I have edited my original post to include the new code I am working on, if you have some advice for how to make this work. Thankyou! – racker Mar 15 '21 at 04:32
  • Yes thanks! I had to change the code a bit but I got it to work, i'll post my final code in the body of the question as an edit. – racker Mar 23 '21 at 07:20