Blog

Tag Archives: Tutorial

Automatically Track App Sale Referrals

I recently came across an article on Mobile Orchard about connecting click-throughs to app sales, which is a rather ingenious idea using the affiliate program LinkShare to create trackable links. As Apple record and report orders that come via these referral links, you can actually see the number of sales (not just views of the App Store page) that resulted from follows of the link. Plus you get a 5% cut of the sale!

I’m doing some experiments with advertising my live looper app Loopy lately, and want a way to track the success of various approaches. It occurred to me that the totally freeform nature of the LinkShare “signature” field (which you can use to track traffic sources) lends itself to an even more flexible approach than that presented in the Mobile Orchard article.

Here’s a way to use that signature field to report the domain name of any referrer who links either to the app page, or to a download link (like, say, http://loopyapp.com/download).

This way, if, say, TUAW link to your app site, if someone clicks through then clicks the download link on your app site and buys, the resulting order will be reported as coming from TUAW. If someone clicks through from your Facebook page, it’ll come up as coming from Facebook. You can even modify the script further to report more precise details (like the path), if you like.

It assumes you’re using PHP, but the principle’s the same for any other language (BYO code, though ;-)).

Step 1: Sign up to LinkShare

First, if you haven’t already, Sign up to the LinkShare program — Once you’ve created a LinkShare account, join the Apple affiliate program via the “Programs” tab. After 3 days, you’ll get an email welcoming you to the program, and you’ll be good to go.

Step 2: Create a product link

Once you’re admitted to the program, open up the “My Advertisers” sub-tab from the LinkShare Programs tab, and open the “Link Maker Tool”. This lets you search for products, and create a link that will open up your app’s App Store page, and will be associated with your LinkShare account.

Screen Shot 2011 09 13 at 13 17 31

Step 3: Create a download redirection script

Now we’re going to set up a script on your app site which will redirect the visitor to the URL you just created (which in turn, redirects straight to the App Store page). It’ll add a “signature” parameter to the URL, which corresponds to the original referrer, so you can track where orders came from.

Create a file called ‘download.php’ in the root of your app site, with the following content, with your LinkShare URL inserted where indicated:

<?php
// Replace the following URL with the LinkShare URL you created
$linkshare_url = "http://click.linksynergy.com/fs-bin/stat?id=/yGrgMJzFG0&offerid=146261&type=3&subid=0&tmpid=1826&RD_PARM1=http%253A%252F%252Fitunes.apple.com%252Fapp%252Floopy%252Fid300257824%253Fmt%253D8%2526uo%253D4%2526partnerId%253D30";
 
session_start();
$referer = $_SESSION['original_referer'];
if ( !$referer ) $referer = $_SERVER["HTTP_REFERER"];
 
if ( $referer ) {
    $signature = preg_replace("@https?://(?:www\.)?([^/]+?)(?:\.com)?/.*@", "$1", $referer);
} else {
    $signature = preg_replace("@^(?:www\.)?(.+?)(?:\.com)?$@", "$1", $_SERVER["HTTP_HOST"]);
}
 
$signature = preg_replace("@[^a-zA-Z0-9]@", "", $signature);
 
header("Location: ".$linkshare_url."&u1=".$signature);
?>

This script looks for the original referrer in a session variable (which we’ll set up in the next step), so that the domain of the site that links to your app site is used, not just your app site’s domain. Then it creates a properly-formatted signature parameter (just alphanumeric), appends it to your LinkShare URL, and sends the viewer onwards.

Bonus points: I prefer to get rid of the ‘php’ extension to make the URL a bit cleaner. Pop the following into your .htaccess file to access ‘download.php’ as just ‘download’:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule . %{REQUEST_FILENAME}.php [L]
</IfModule>

Step 4: Remember the referrer

Now, on the landing page script for your app site (or the site header), pop this in at the very start:

<?php
session_start();
if ( !$_SESSION["original_referer"] ) $_SESSION["original_referer"] = $_SERVER["HTTP_REFERER"];
?>

This stores the original referrer URL in a session variable, to use when we actually link the viewer through to the App Store.

Step 5: Test it

To make sure everything’s working properly, open download.php again, and replace “header” at the bottom with “echo”, so that instead of redirecting the browser, we just print out the URL where we would be redirecting to.

Open your appsite/download URL, and make sure the URL ends with “&u1=appsite“. That’s for direct visitors. Now, click through to your app site from another site, then click your “download” link. You should now see the name of the original site you linked from as the “u1″ parameter at the end of the URL.

Once you’re satisfied that you’re good to go, make sure you replace “echo” with “header” again.

Step 6: Track

Now that you’re ready to track referrals, you can give out your http://yourappsite/download URL as your app’s direct iTunes download link (to reviewers, in your press releases, etc).

You can view a report showing clicks and orders associated with each referrer on the LinkShare page — create an advanced report by clicking the “Advanced Reports” sub-tab, then select your desired date range (I use “Since Last Payment”, and under “Report Type”, select “Signature Activity”. Hit “View Report”, and you’ll see your clicks and sales versus each referrer (“Member ID”, on the report).

Voila! Omnipotence achieved.

Addendum: This technique works for tracking referrers, but if you’re wanting to track the performance of ads (say, with AdMob), you’ll want to use your original LinkShare URL, with a custom “&u1″ signature parameter. As ad platforms like AdMob link directly (and don’t, as far as I know, send a referer parameter), this script won’t pick up that it’s from your ad platform.

Addendum 2: LinkShare’s reports don’t distinguish between products, so if you’ve multiple apps, you might want to add a prefix to your signature parameter to tell ‘em apart. You could, say, replace that header("Location: ".$linkshare_url."&u1=".$signature); line with something like header("Location: ".$linkshare_url."&u1=myapp".$signature);.

Also tagged , , , | Comments closed

Playing audio in time using Remote IO

I got an email today with a question about how to handle playback of audio in time, synchronised with a clock. My ‘musical notepad’ app Loopy does this, and I thought I’d briefly explain how.

Any app that makes use of the Remote IO audio unit framework (which is generally necessary for the kind of responsiveness required in a realtime musical app) provides audio to the hardware via a callback, which is periodically called when the hardware is ready for more.

The trick here is to provide the right chunk of samples in this callback for the current time position.

Loopy achieves this by:

1. Keeping track of where in the timeline we are at the time the callback is called

This is easily accomplished by keeping a record of the time the clock was started, subtracting this from the current time, and possibly performing a modulus with the tempo. For example:

  • (now - startTime) % timePerBar gives the number of time units into the current bar (lets call it timeIntoBar).
  • timeIntoBar / (timePerBar/beatsPerBar) gives the number of beats into the current bar, and
  • timeIntoBar % (timePerBar/beatsPerBar) gives us the time into the current beat.

2. Determining first if we should be playing audio at this time, and if so, which samples should be playing

This involves first converting our time units from step 1 into samples. For instance, you can convert microseconds to samples by dividing your time by 1000000/yourSampleRate. Aside: Of course, you can convert back from samples to time by multiplying instead of dividing.

Next, in the case of Loopy’s metronome, for example, we test for whether samplesIntoBeat < sound.lengthInSamples. If so, that means we should be playing audio. If the sound was a loop, of course, we could be always playing.

The offset into the sound, in samples, is just samplesIntoBeat, in the case of the simple metronome. In the case of a loop, you probably will be more interested in the number of samples into your loop — so instead of determining (now - startTime) % timePerBar, you may be interested in (now - startTime) % timePerLoop.

So, we want to return the requested number of samples starting from this offset into the sample array representing our audio.

3. Returning smooth audio in time

Note that if you just go returning any old set of samples, willy-nilly, you’re going to get nasty clicks and pops from discontinuities you get by not matching the start of your next buffer to the last one.

To ensure smoothness, Loopy keeps track of the offset of the last samples we returned, and just return the immediately following bunch of samples — unless we’re more than some threshold number of samples out of time, in which case we’ll suffer the pop in order to stay synchronised. Actually, you can even generally avoid the pop if you smoothly blend buffers over a short time, removing any discontinuity.

Final words

The example above was a relatively trivial one, for a metronome sound. For longer audio that may span multiple bars, you’ll probably want to perform a modulus by the length of your audio clip, possibly quantised to your time signature, and possibly using a per-loop time base, so you can start the loop at any point in your timeline and have it begin from the start. This is something Loopy doesn’t currently do — Loopy will keep your loops synchronised so when you start a loop playing, it’ll play whatever part corresponds to the current timeline, not from the start of the loop. Maybe it’ll be an option in the future?

I wrote a little about the timing of loops in my second article on Loopy’s implementation.

Also tagged , , , | Comments closed

The Making of Talkie: Multi-interface broadcasting and multicast

Part 2

TalkieTalkie is my newest product, a Walkie Talkie for iPhone and Mac.

In Part 1 of this series, I wrote about basic broadcasting. This works fine with one network device, but it’s worth discussing how to send through all devices, so you can communicate with others connected via, say, Ethernet and WiFi simultaneously.

So, in Part 2 I’ll write about the approach I took in Talkie for broadcasting from all network devices (a.k.a. network interfaces), so that one can communicate with others connected via WiFi, Ethernet (on a Mac), and any other network devices simultaneously.

Read More »

Also tagged , , , , , , , , , | Comments closed

The Making of Talkie: Broadcasting

Part 1

TalkieTalkie is my newest product, the result of a collaboration with a good designer friend, Tim Churchward, who did the user interface.

Talkie is a little different from many of the other walkie talkie applications on the App Store (aside from the fact that much of it was written by me from our motorhome in Tunisia!), and I thought I’d write a little about some of the tech underpinning the app, and some of the choices we made. Along the way it may get a little tutorial-esque.

  • This first part will introduce our initial motivations, and will talk about basic broadcast communications — the broadcast communications part may be very familiar to some, in which case it may be worth skipping to the next instalment.
  • In the second part, I’ll continue the theme of networking, and will talk about what I ended up with for Talkie’s network code after addressing a couple of things, including switching to multicast.
  • Finally, I’ll talk audio, dual platform development, and anything else I think of along the way (Actually, I’m aching to talk about one particular upcoming feature that had me jumping up and down when I first thought of it, but for now, mum’s the word on that one.) Read More »
Also tagged , , , , , , , , | Comments closed

Using RemoteIO audio unit

I’ve had nasty old time trying to get some audio stuff going on the iPhone, no thanks to Apple’s lack of documentation. If you’re an iPhone developer interested in getting RemoteIO/IO Remote/whatever it’s called working on the iPhone… Do I have good news for you. Read on.

Read More »

Also tagged , , | Comments closed