// Blog

Making User Agents Useful

Originally published on the Clarify.io blog. View archived copy.

How many Java developers use our API?

Has anyone upgraded to our latest Ruby Gem?

Is going to that PHP conference going to be useful?

If you build or support APIs, odds are you’ve asked your team these questions. Fundamentally, they make sense. We want to know who is using our system, what they’re doing with it, and how to find current/new customers to engage with. But too often often, we have major problem:

You can’t answer any of them.

men-in-black-idIn some cases, you can track signups from specific events via coupon codes, traffic to the different languages sections in your documentation, check the download pages of your favorite package manager, or even survey your customers but unfortunately, none of these directly relate to usage. Even worse, most of these methods are error-prone, dependent on customer responses, or take manual collection. They’re inaccurate at best and deceptive at worst.

We decided to take a radically different but incredibly simple approach: User Agents.

If you’re not familiar with them, user agents are a simple concept:

In computing, a user agent is software (a software agent) that is acting on behalf of a user.

When a software agent operates in a network protocol, it often identifies itself, its application type, operating system, software vendor, or software revision, by submitting a characteristic identification string to its operating peer.

That “characteristic identification string” is the most important part. It what tells a server that you’re using Chrome vs curl vs Safari. While that’s great for a starting point, there are no hard and fast requirements on what to include, so we’ve added a few things.

If you look at any of our helper libraries, there’s a common pattern:

PHP:

	<div id="crayon-57fb3cf9aad1f375038654" class="crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes notranslate" data-settings=" minimize scroll-mouseover" style=" margin-top: 12px; margin-bottom: 12px; font-size: 12px !important; line-height: 15px !important;">
	
		<div class="crayon-toolbar" data-settings=" mouseover overlay hide delay" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"><span class="crayon-title"></span>
		<div class="crayon-tools" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"><div class="crayon-button crayon-nums-button" title="Toggle Line Numbers"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-plain-button" title="Toggle Plain Code"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-wrap-button" title="Toggle Line Wrap"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-expand-button" title="Expand Code"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-copy-button" title="Copy"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-popup-button" title="Open Code In New Window"><div class="crayon-button-icon"></div></div><span class="crayon-language">PHP</span></div></div>
		<div class="crayon-info" style="min-height: 16.8px !important; line-height: 16.8px !important;"></div>
		<div class="crayon-plain-wrap"><textarea wrap="soft" class="crayon-plain print-no" data-settings="dblclick" readonly style="-moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4; font-size: 12px !important; line-height: 15px !important;">

$this->client->setUserAgent($this::USER_AGENT . ’/’ . PHP_VERSION);

1
$this->client->setUserAgent($this::USER_AGENT . ’/’ . PHP_VERSION);

Ruby:

	<div id="crayon-57fb3cf9aad34603952850" class="crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes notranslate" data-settings=" minimize scroll-mouseover" style=" margin-top: 12px; margin-bottom: 12px; font-size: 12px !important; line-height: 15px !important;">
	
		<div class="crayon-toolbar" data-settings=" mouseover overlay hide delay" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"><span class="crayon-title"></span>
		<div class="crayon-tools" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"><div class="crayon-button crayon-nums-button" title="Toggle Line Numbers"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-plain-button" title="Toggle Plain Code"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-wrap-button" title="Toggle Line Wrap"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-expand-button" title="Expand Code"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-copy-button" title="Copy"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-popup-button" title="Open Code In New Window"><div class="crayon-button-icon"></div></div><span class="crayon-language">Ruby</span></div></div>
		<div class="crayon-info" style="min-height: 16.8px !important; line-height: 16.8px !important;"></div>
		<div class="crayon-plain-wrap"><textarea wrap="soft" class="crayon-plain print-no" data-settings="dblclick" readonly style="-moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4; font-size: 12px !important; line-height: 15px !important;">

def user_agent ruby_version = ”#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}” “clarify-ruby/#{Clarify::VERSION}/#{ruby_version}” end

1
2
3
4
def user_agent
    ruby_version = ”#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}”
    “clarify-ruby/#{Clarify::VERSION}/#{ruby_version}“
end

Python:

	<div id="crayon-57fb3cf9aad39770007482" class="crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes notranslate" data-settings=" minimize scroll-mouseover" style=" margin-top: 12px; margin-bottom: 12px; font-size: 12px !important; line-height: 15px !important;">
	
		<div class="crayon-toolbar" data-settings=" mouseover overlay hide delay" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"><span class="crayon-title"></span>
		<div class="crayon-tools" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"><div class="crayon-button crayon-nums-button" title="Toggle Line Numbers"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-plain-button" title="Toggle Plain Code"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-wrap-button" title="Toggle Line Wrap"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-expand-button" title="Expand Code"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-copy-button" title="Copy"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-popup-button" title="Open Code In New Window"><div class="crayon-button-icon"></div></div><span class="crayon-language">Python</span></div></div>
		<div class="crayon-info" style="min-height: 16.8px !important; line-height: 16.8px !important;"></div>
		<div class="crayon-plain-wrap"><textarea wrap="soft" class="crayon-plain print-no" data-settings="dblclick" readonly style="-moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4; font-size: 12px !important; line-height: 15px !important;">

user_agent = api_lib_name + ’/’ + version + ’/’ + PYTHON_VERSION

1
user_agent = api_lib_name + ’/’ + version + ’/’ + PYTHON_VERSION

Java:

	<div id="crayon-57fb3cf9aad3e864295541" class="crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes notranslate" data-settings=" minimize scroll-mouseover" style=" margin-top: 12px; margin-bottom: 12px; font-size: 12px !important; line-height: 15px !important;">
	
		<div class="crayon-toolbar" data-settings=" mouseover overlay hide delay" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"><span class="crayon-title"></span>
		<div class="crayon-tools" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"><div class="crayon-button crayon-nums-button" title="Toggle Line Numbers"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-plain-button" title="Toggle Plain Code"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-wrap-button" title="Toggle Line Wrap"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-expand-button" title="Expand Code"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-copy-button" title="Copy"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-popup-button" title="Open Code In New Window"><div class="crayon-button-icon"></div></div><span class="crayon-language">Java</span></div></div>
		<div class="crayon-info" style="min-height: 16.8px !important; line-height: 16.8px !important;"></div>
		<div class="crayon-plain-wrap"><textarea wrap="soft" class="crayon-plain print-no" data-settings="dblclick" readonly style="-moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4; font-size: 12px !important; line-height: 15px !important;">

userAgent = “clarify-java/“+SDK_VERSION+”/“+System.getProperty(“java.version”);

1
userAgent = “clarify-java/“+SDK_VERSION+”/“+System.getProperty(“java.version”);

which creates a string like:

clarify-language/x.y/a.b.c

The first portion is simply their language of choice. This gives us hints on how and where to reach potential users both in online communities and which events to attend, sponsor, etc.

The second portion – x.y – is the library version. Using this, we can track upgrade patterns and how long different versions of libraries are live. At a later time, we could theoretically track this back to specific accounts and contact users about new features their old library doesn’t support.

Finally, the third portion – a.b.c – is their language version. As we consider new language constructs or features for the libraries, this tells us how many could actually use it versus how many will have a bad day when we crash their app.

And voila. Now we have great information.

Going back to our original questions, they’re easy. In fact, we don’t have to bug our users, we just query the system and ask. In fact, we have a regular report that collects user agent trends and sends them to the entire team.

For context, approximately 80% of our requests comes through a helper libraries so while the above is great information, we know it is still not the whole picture.