At work I’m working on a project in which we need to track the share count of a URL. Below are my quick notes. In all examples I’m getting the share count of https://www.facebook.com/
. Note that I’m using the jq
notation to extract the actual result from the response.
Just GET it
Request:
curl --silent -X GET http://graph.facebook.com/?id=https://www.facebook.com/
UPDATE August 23, 2016
As of August 7, 2016 version 2.0 of the Graph API has been disabled. Version 2.1 is now the default one. In between 2.0 and 2.1 the response format has been changed. Thanks go out to Nabil Souk for pointing this out. This post has been updated to reflect this change. For archival purposes both responses (both the old, and new) are still included on this page.
Response (Graph API v2.0, pre August 7, 2016):
{
"id": "https://www.facebook.com/",
"shares": 42944662,
"comments": 1086
}
The count can be found in .shares
Response (Graph API v2.1 and higher, post August 7, 2016):
{
"og_object": {
"id": "10151063484068358",
"title": "Welcome to Facebook - Log In, Sign Up or Learn More",
"type": "website",
"updated_time": "2016-08-23T08:50:45+0000"
},
"share": {
"comment_count": 1335,
"share_count": 113774962
},
"id": "https://www.facebook.com/"
}
The count can be found in share.share_count
Unfortunately it’s not that easy (anymore). See below for a possible solution.
Request:
curl --silent -X GET 'https://www.linkedin.com/countserv/count/share?url=https%3A%2F%2Fwww.facebook.com&format=json'
Response:
{
"count": 1672,
"fCnt": "1,672",
"fCntPlusOne": "1,673",
"url": "https://www.facebook.com"
}
The count can be found in .count
Google Plus
Request:
curl --silent -H 'Content-type: application/json' -X POST -d '[{"method":"pos.plusones.get","id":"p","params":{"nolog":true,"id":"https://www.facebook.com/","source":"widget","userId":"@viewer","groupId":"@self"},"jsonrpc":"2.0","key":"p","apiVersion":"v1"}]' https://clients6.google.com/rpc
Response:
[
{
"id": "p",
"result": {
"kind": "pos#plusones",
"id": "https://www.facebook.com/",
"isSetByViewer": false,
"metadata": {
"type": "URL",
"globalCounts": {
"count": 430133.0
}
},
"abtk": "AEIZW7RT8UqRam+DqDUFw3fY9+GpV+OwizHp+BDdEKudWO37f2nItnJhQKKGNT3nMuz5XXwcRe8qSDQMNkHTiOOeHtxJCcvJdg=="
}
}
]
The count can be found in .[0].result.metadata.globalCounts.count
Other Services
More services (Buffer, Pinterest, etc.) needed? Check https://www.madebymagnitude.com/blog/getting-your-social-share-counts-with-php/ for inspiration.
Scripts / Inspiration
Some scripts that might help you out:
So, what about Twitter?
The problem
In the past it was possible to send a GET
request to https://cdn.syndication.twitter.com/widgets/tweetbutton/count.json?url={URL}
. However, the “Count Endpoint” has been shut down and now returns a 410 Gone
A possible solution
Use Twitter’s Search API:
The Twitter Search API is part of Twitter’s v1.1 REST API. It allows queries against the indices of recent or popular Tweets
Endpoint URLs that might be of interest:
But:
Before getting involved, it’s important to know that the Search API is focused on relevance and not completeness. This means that some Tweets and users may be missing from search results.
In detail: “Not all Tweets will be indexed or made available via the search interface.” and “[T]he Search API is focused on relevance and not completeness. This means that some Tweets and users may be missing from search results.” and “Search API usually only serves tweets from the past week.”
Oh.
A proper solution then?
As Twitter’s Search API mentions:
If you want to match for completeness you should consider using a Streaming API instead.
The Streaming API allows you to track Public Streams. Track that, and then count yourself.
This code snippet using the twitter-stream-api
NPM module should get you started:
var TwitterStream = require('twitter-stream-api'),
fs = require('fs');
// Create your keys at https://apps.twitter.com/
var keys = {
consumer_key : "consumer-key",
consumer_secret : "consumer-secret",
token : "your-token",
token_secret : "your-token-secret"
};
var Twitter = new TwitterStream(keys, false);
Twitter.stream('statuses/filter', {
track: 'npmjs.com/package/defer'
});
Twitter.on('connection success', function (uri) {
console.log('connection success', uri);
});
Twitter.on('connection aborted', function () {
console.log('connection aborted');
});
Twitter.on('connection error network', function (error) {
console.log('connection error network', error);
});
Twitter.on('connection error stall', function () {
console.log('connection error stall');
});
Twitter.on('connection error http', function (httpStatusCode) {
console.log('connection error http', httpStatusCode);
});
Twitter.on('connection rate limit', function (httpStatusCode) {
console.log('connection rate limit', httpStatusCode);
});
Twitter.on('connection error unknown', function (error) {
console.log('connection error unknown', error);
Twitter.close();
});
Twitter.on('data', function (obj) {
console.log('data', obj.toString());
});
Twitter.on('data keep-alive', function () {
console.log('data keep-alive');
});
Twitter.on('data error', function (error) {
console.log('data error', error);
});
Twitter.pipe(fs.createWriteStream('tweets.json'));
Note: Protected Streams won’t show up in here, of course.
Note: If the script is not running you’ll, as this is a “live” API, miss counts! Filling the gaps with a normal REST API request won’t be 100% accurate (see above).
Good to know: “Note that display_url
does not contain a protocol, so this is not required to perform a match.”
Need to know: “URLs are considered words for the purposes of matches which means that the entire domain and path must be included in the track query for a Tweet containing an URL to match.”
→ Translated: no partial URL matches!
Beware though: “Each phrase must be between 1 and 60 bytes, inclusive.”
→ Translated: no long URLS!
Why make it so difficult, Twitter?
Thank me with a coffee.
I don\'t do this for profit but a small one-time donation would surely put a smile on my face. Thanks!
To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.
Great post, Bramus!
I’d like to add some notes on Twitter:
1. Twitter Search is indeed not complete, however, it generally only omits results from very low quality accounts (like ones with < 10 followers). Those tend to a) produce very little tweets or b) produce too many spammy tweets so they're worth suppressing. So, generally you don't lose much with Search API.
2. Stream API seems like a more precise solution, but it's not. The problem is with shortened urls (and other url variants that do not mention the target domain name). Very big volume of shares happens through shortened urls. Twitter crawls all urls to determine the target destination, and that destination is indexed by Twitter search. So when you request domain name with Search API, you get tweets with short urls too. However, that is not the case with Stream API. Stream API will only get you tweets that mention the domain name explicitly. Which means that you lose all tweets with shortened urls. And of course you have to ensure 100% uptime of streaming client or you lose tweets too.
I'd recommend some third-party solution for tracking Twitter share counts, like newsharecounts.com (which I'm involved with), or twitcount.com. Those handle all the complexities and let you get your share counts without any pains.
Have a nice day!
It’s a great post that saved my day!
Glad to have helped.
Hello there.
Note that the Facebook response has changes. I just noticed that in my implementation. The response for the shares count is as following inside the api response object:
share: {
comment_count: 0,
share_count: 62
}
Cheers,
Thanks for pointing this out, Nabil. I’ve updated the post accordingly.
Kind regards,
Bramus.
Thank you Bramus! and Nabil. Our Facebook share counts unceremoniously disappeared Monday. If it weren’t for this post, I’d still be combing through the Facebook Developers pages.
– Joe
I have applied this way, thanks for the article 🙂
But I’m having some problems,
1. If I have not logged on facebook in the browser, the share count number does not appear.
2. I applied this share count method on my websites that have high traffic, and someday, count share number that appears is 0, and when i checked the response from facebook, “request access limit”.
Is there any way I can obtain share count without affected by the limitations of facebook?
Sorry if my english bad 😀
Hi,
Could you update the jsfiddle to reflect the Facebook API changes? Doesn’t seem to work 🙂
Best regards,
Asbjoern
It looks like the Facebook share_count returns “likes” and “shares” combined. Is there any way to get just the share count?
Hi Nathan,
The Graph API Docs have this description for the
share_count
(Graph API v2.1 – the now default one):Haven’t tested this, but it looks like the
share_count
should only hold the actual share count (sans the number of likes).HI!
First of all thanks for your post, i beleive this might help me a lot, since ALL my fb shares on mi blog are now gone…
My question is, how do i insert the code? Should i place it on the social plugin i user or where exactly? Once i do this, am i gonna be able to “retrieve” the old shares i’ve lost?
I’m pretty much a rookie on coding. Apreciate the help!
Hi
Why graph api gives share count for all urls of entire
domain summed up rather than particular url for which I am making a request?
Do I need to change any settings ??
How Do I get facebook like count my website ?