Getting WordPress / JetPack Subscriber Counts via the API... the hard way


People can subscribe to receive my blog via email. This is managed by the JetPack plugin.

I want to be able to display something like "Join 1,234 subscribers and receive updates via email". So, how do I get the subscriber count from the API?

As documented in the JetPack HTTP API, it is possible to interact with JetPack programmatically.

A good starting point is /wp-json/ - that will show you all the API endpoints available on your blog.

By filtering on "subscribers", we find:

"/jetpack/v4/stats-app/sites/12345/subscribers/counts": {
    "namespace": "jetpack/v4/stats-app",
    "methods": ["GET"],
    "endpoints": [{
        "methods": ["GET"],
        "args": []
    }],
    "_links": {
        "self": [{
            "href": "https://shkspr.mobi/blog/wp-json/jetpack/v4/stats-app/sites/12345/subscribers/counts"
        }]
    }
},

Can we just visit that URl and get the data? Nope!

If you're logged in to your blog, and on the JetPack dashboard, you can run this scrap of Javascript in your browser's console:

fetch( '/wp-json/jetpack/v4/stats-app/sites/12345/subscribers/counts', {
    credentials: 'same-origin',
    headers: {
        'X-WP-Nonce': Initial_State.WP_API_nonce,
        'Content-type': 'application/json' }
} )
    .then( response => response.json() )
    .then( response => console.log( response) )
    .catch( error => console.log( error.responseText ) );

That returns:

{
  "counts": {
    "email_subscribers": 443,
    "social_followers": 0,
    "paid_subscribers": 0
  }
}

OK! So we know it is possible for an admin to get these data. How can we regularly fetch the count from the API and cache it for later use?

Well, that's where I get stuck. The documentation for the WordPress REST API says this:

It is important to keep in mind that this authentication method relies on WordPress cookies. As a result this method is only applicable when the REST API is used inside of WordPress and the current user is logged in. In addition, the current user must have the appropriate capability to perform the action being performed.

So we're stuck without a cookie? Not quite!

The documentation also says we can use Application Passwords. You can read more about them but, basically, go to your user profile screen at /wp-admin/profile.php and you should be able to generate an app password.

Once done, you can test it by running this on the command line:

curl --user "admin:p4ssw0rd" https://example.com/wp-json/jetpack/v4/stats-app/sites/1234/subscribers/counts

(Obviously, use your own username, password, URl, and site ID.)

This means we can add something like this to our functions.php file to get the data and store it for a day:

<?php
if( get_transient( 'jp_sub_stats' ) ) {
    $jp_sub_stats = get_transient( 'jp_sub_stats' );
} else {
    $headers = array(
        'Authorization' => 'Basic ' . base64_encode( 'admin:p4ssw0rd' )
    );

    $api_url = 'https://example.com/wp-json/jetpack/v4/stats-app/sites/1234/subscribers/counts';

    $response = wp_remote_request(
        $api_url,
        array( 'headers'   => $headers )
    );

    $json = json_decode( $response );
    $count = $json->counts->email_subscribers;

    set_transient( 'jp_sub_stats', $count, DAY_IN_SECONDS );
}

Of course, you'll probably want to store the password somewhere securely rather than in your source code. And you'll probably want to do some error checking on what the API returns.

But, there you go. A somewhat convoluted way to get your JetPack subscriber count via an API call. Enjoy!

The Easy Way

Oh! You wanted to do this with the minimum of fuss?

There's a built in function which stores the count in a transient.

So you can simply do:

$cache_key  = 'wpcom_subscribers_total';
$subs       = get_transient( $cache_key );
$subs_count = $subs["value"];

Share this post on…

What are your reckons?

All comments are moderated and may not be published immediately. Your email address will not be published.Allowed HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <p> <pre> <br> <img src="" alt="" title="" srcset="">