Twitter ad data: bad.

Twitter’s reported data vs. actual

Discrepancies exist between actual activity and activity in analytics repots. No getting around it.

I’d guess that major twitter advertisers see discrepancies of 2-5%. so knowing that I’d have significantly less activities, I expected discrepancies of maybe 10-20%.

I was WAY off. Here’s the email* I sent to Twitter explaining the situation.

Hi – there is nothing in your help files that matches my issue.
The data Twitter is giving me on followers is wrong
It’s not off, it’s straight up WRONG. 

As of 4:00 PM ET, Twitter analytics says I have gotten 60 follows and 42 unfollows for 8/6/18.

This is not true. 
In the last day, I have gotten 22 new followers, with 2 unfollows. The data is provided below.

Count/Follow time/Username
1.  8/6/18 15:04 @breysstory_
2.  8/6/18 14:50 @Didgeridood
3.  8/6/18 14:48 @AngelR95
4.  8/6/18 14:47 @gmiller1643
5.  8/6/18 14:28 @BeakersBro
6.  8/6/18 14:15 @farkas_jerry
7.  8/6/18 14:14 @pinkyapplepie
8.  8/6/18 14:03 @tacomike750*   unfollowed: 8/6/18 14:05
9.  8/6/18 13:52 @DanSumners1
10.  8/6/18 13:45 @xoxomeb
11.  8/6/18 13:45 @Flash94710833*   unfollowed: 8/6/18 13:45
12.  8/6/18 13:34 @BarbBondVO
13.  8/6/18 13:05 @Meghanb33
14.  8/6/18 12:56 @smittylou55
15.  8/6/18 12:33 @adaytoroberta17
16.  8/6/18 12:33 @ArtMcDonald11
17.  8/6/18 12:26 @reed180a
18.  8/6/18 12:19 @alexhibbert
19.  8/6/18 11:35 @leelarose100
20.  8/6/18 11:25 @Dani3lTravieso
21.  8/6/18 11:05 @SeymourZoe
22.  8/6/18 9:35 @raymond50128623

All of these followers were acquired on the calendar day 8/6/2018.
Even so, calendar day aside, there were no followers added yesterday after 3PM ET. 

SO: Accounting for any time changes, in the last 24 hours:
Twitter reports: 60 new followers.
In reality, there were: 22 new followers.

This is a discrepancy of more than 63%.

I’ve got my account set so that I am paying for followers, with my budget at $40 per day.
Analytics says that between my 2 campaigns, I am paying an average of $.67 per follow.
$.67 per follow isn’t bad. Mathematically, it’s right… if you’re using the incorrect follower count from Twitter.

Given the actual follower statistics (even including the unfollows), I am paying an average of $1.81 per follow.
So, per follower, the price I am being charged is 170% higher than the cost-per-follower fee shown to me by Twitter. 
That’s right – I’m being charged almost THREE TIMES what Twitter says I’m being charged.

Where are the missing followers?

Will Twitter change its data reporting to reflect reality?

Amanda Kruel

The actual follower data was pulled via Twitter’s API, which enabled me to collect data on all my followers once a minute.

Fun fact:
When you look for help on Twitter, you are asked to search their database.

If you search their database but don’t find what you’re looking for, you go to the reporting page and select that the issue is a data discrepancy and click to report it.

Instead of giving you any fields to fill and submit, they once again show you a list of articles about data discrepancies.

If you still can’t find what you’re looking for (it wasn’t there the first two times, so why would it be?), *then* they let you submit a report.

Fine. I submit one and instantly get a confirmation email with a case number back.

If you’re like me, you see the subject and think “Great, case number means it’s submitted, so they’ll email me back when they’ve got an answer.” And then you forget about it for a while, and then you notice it’s been several hours and you still don’t have an answer. So you open up that confirmation email, and … surprise!

Thank you for writing in. We see you have a question on Dashboards, Analytics & Ads Editor, under ‘I have another dashboard or analytics question.’ Your unique ticket number is: 90333778.

To save you time, many advertisers can get instant answers to questions on this topic through these articles in our Help Centre…

It’s not an email saying that my issue was submitted. It’s an email giving links to the same articles already linked to twice above. 🙄
But wait! All hope isn’t lost! Beneath that, it says:

If this has not answered your question, please reply to this case with more detail and we will try to provide more specific guidance. If you do not reply we will go ahead and close your case.

So, the “CASE #” in the email subject isn’t the number of an open case, it’s the number of a hypothetical case they’ll open only if I reply…

OK, so I just email back some details and then they’ll work on my case and get back to me, sounds good… Except the next line:

Please be aware that we cannot offer custom support to all queries.

OK. Great. Guess I’ll wait and see if they care about the little guy.

I’m still collecting data, we’ll see how these discrepancies continue over time.
I plan to continue this experiment indefinitely. I’m using my own money to pay for this, and I don’t make any money off the ads I show. If you’d like to help with my experiment, please donate below:

To contact me, email or visit my Twitter.

Twitter ad stats.

So, I’ve recently started advertising on twitter, not because I have a business to promote, just because I’m curious as to how it works.

It’s been a lot of fun, and it’s definitely interesting.
I’ve been looking at bits of data here and there, and I wasn’t really sure what to post, but I found some discrepancies that I believe merit pointing out.

What I’m paying for is followers. How it works:
Twitter shows my ad (which is a tweet I’ve written and chosen to “promote”).

My promoted tweet

Here is one of my ads.
When it shows up, there are several things that can happen.

  1. User ignores tweet, keeps scrolling.
  2. User views tweet or views my profile.
  3. User likes or retweets my tweet
  4. User follows me.

    Since the purpose of my campaign is to get followers, the only situation in which Twitter will charge me is number 4.

So, does it work? Let’s take a look. Here are some results.

Interesting. So, 241 follows, but 178 unfollows. That would be a net increase of 63 followers, right? Well, let’s take a look at my followers recently.

Now, wait a second! That shows only a net increase of 33 followers. What!?

Let’s take a look at the API data I’ve brought into my google spreadsheet.

You can’t see from that image, but there’s definitely a change in followers between the 4th and the 6th.

That data is really rough. I standardized it by calling once every 15 minutes, but if there really are all these apparent unfollows, I’m gonna have to pull data more often.
So, I have every-15-minutes data from 8/5/18 at 9 AM ET – 8/6/18 at 4:17 AM ET.

After that point, I have data for every minute (and it’s continuing to update).

Not much to show or tell right now, but I haven’t gotten a new follower since around 3:00 PM ET 8/5/18 (yesterday, ~18 hours ago).

I’ve emailed Twitter’s tech support twice about some of these discrepancies, but I have yet to hear back.

I’m going to update more in the future as I obtain more data. Hope you find this as interesting as I do!

A Google Apps Script function I wrote

I code in javascript all the time, but it’s usually stuff that only I would find useful. Additionally, the code is often too sloppy to make sense. But I cleaned up this function and I’m happy to share it with the world, in hopes that it might save other folks some time.

function CycleSheets()
If you’re like me, you’ve got too much data in your workbook and it’s maddeningly slow to scroll through all the sheets

If there are several sheets that you want to delete, it’s a pain to go navigate to each sheet and right click to delete and then confirm in an alert box.

So, this is a function that will show the user each sheet by name and size, giving them the choice as to whether or not to delete that particular sheet.
After all the sheets have been cycled through, the user will be shown a list of the sheets they’ve selected to delete, at which point they can confirm and delete or cancel.

function cycleSheets(){
   var ui       =   SpreadsheetApp.getUi();
   var ss       =   SpreadsheetApp.getActive();
   var sheets   =   ss.getSheets();
   var sheetCt  =   sheets.length;
   var delArr   =   [];
   for (var a = 0; a < sheetCt; a++){ var thisSheet = sheets[a];
      var thisCount =  a + 1;
      var sheetID   =  'Sheet ' + thisCount + '/' + sheetCt + ', named: ' + thisSheet.getName();
      var sheetData =  sheetID + '\nSheet contains ' + thisSheet.getLastRow() + ' rows.';
      var deleteYN  =  ui.alert('Delete this sheet?', sheetData, ui.ButtonSet.YES_NO_CANCEL);

      if (deleteYN  == ui.Button.YES)    {
         delArr.push(thisSheet); Logger.log('Sheet ' + thisCount + ' will be deleted.');
      if (deleteYN  == ui.Button.NO)     {
         Logger.log('Sheet number ' + thisCount + ' will *not* deleted.');
      if (deleteYN  == ui.Button.CANCEL) {
         var a = sheetCt + 1; ui.alert('Cancelled!'); return
      if (deleteYN  == ui.Button.CLOSE)  {
         var a = sheetCt + 1; ui.alert('Closed and cancelled!'); return
   if (delArr.length > 0)   {
      var sheetNames   =   '';
      for (var b = 0; b < delArr.length; b++)   {
         var sheetNames = sheetNames + delArr[b].getName() + '\n'
      var deleteConf   =    ui.alert('Are you sure you want to delete all of these sheets?', sheetNames, ui.ButtonSet.YES_NO);
      if (deleteConf   ==   ui.Button.YES){
         for (var c = 0; c < delArr.length; c++){
         ui.alert('You deleted ' + delArr.length + ' sheet(s). \nNow there are ' + ss.getSheets().length + ' sheets left.')
      else {   
         ui.alert('You cancelled this deletion.')
   else {
      ui.alert('You didn\'t choose any sheets to delete!')

Anyway, I hope you get some use out of it. Tweet me @skweeds to let me know how it works out!

The birth of Skweeds.


It’s the year 2001, and I’m a computer nerd. I have to make a username and password for every website which sucks.

If my preferred username is taken, I could add some numbers or XoX to the end and get something available, but that looks lame.

If I want a memorable username with no numbers, maybe I should make up a fake word that won’t mean anything to anybody, and then I’ll always have that as my username on every single site.

If someone asks me if I smoke, I think they’re talking about cigarettes. As a 15 year old, I am more naive than I want to admit.

man alive!

Re: Diluting the definition of racism.

Imagine this situation:

Alex doesn’t hate Chinese people, but asks, “Don’t a lot of Chinese people own laundromats?”
Upon hearing this, Chris interjects with, “That’s a racist thing to say, you’re a racist.”

… later, Alex sees a headline proclaiming “Institutional Racism: why it’s our country’s greatest problem.”

What will Alex think now?

After Chris’ chastisement, Alex may just think that institutional racism consists primarily of ‘microaggressions’ and stereotyping.
If cops hear that a suspect works at a laundromat, and they go to Chinatown to look for him, that’s racism? This doesn’t seem like that big of a deal to Alex.

What’s next for Alex?
Will Alex become more or less ‘racist’ after Chris’ intervention?
Will Alex think that alleged ‘racist’ cops are truly a threat?
Will Alex be more or less likely to want to learn about different cultures?

Counting uniques: updated

I previously posted a script I wrote to count uniques. It’s kind of a crappy script. It can only draw values from an array (as opposed to multiple selected values in the sheet) and it just leaves 2 arrays, 1 with each unique value, and a corresponding array with the count of each respective value. So, 2 arrays of numbers. Not very useful unless you are 100% aware of and confident about what you’re doing, and I certainly am not. So here’s a better script.

Use this in a google apps script bound to a spreadsheet. With the onOpen function, a menu will appear in the spreadsheet itself and you can run the function from within the document (as opposed to running it from the bound code.)

This will log each value and its corresponding count pretty clearly. Unfortunately, logs can only be viewed from the bound script editor, so I will update this code with something that will show an alert or HTML file within the spreadsheet so one can run the function and get the results without being forced to open the script editor.

function onOpen(){
var ui = SpreadsheetApp.getUi();
 .addItem('Count instances', 'countSelected')

function countSelected(){
var sheet = SpreadsheetApp.getActive().getActiveSheet();
var range = sheet.getActiveRange();
var row = range.getRow();
var col = range.getColumn();
var lastRow = range.getLastRow()
var numRows = range.getNumRows();

var rclr = 'Start row: ' + row + ', Column: ' + col + ', Last row: ' + lastRow + ', Number of rows: ' + numRows;

var selectedVals = []
for(var a = 0; a < numRows; a++){
var thisRow = row + a;
var thisValue = sheet.getRange(thisRow, col).getValue();

var arr = selectedVals;
var uniques = [];
var instCount = [];
var prev = '';
var arrCount = arr.length;
for(var a = 0; a < arrCount; a++){
if (arr[a] !== prev ) {uniques.push(arr[a]); instCount.push(1)}
else {instCount[instCount.length-1]++}
var prev = arr[a];}

for (var b = 0; b < uniques.length; b++){
 var variable = uniques[b];
 var instanceCount = instCount[b];
 Logger.log('There are ' + instanceCount + ' instances of the variable ' + variable);