Navigate / search

  • netmarks-logo


    Netmarks is the fastest way to share the interesting stuff you find online. All your favorite services are supported, and if they're not, well...there's an API for that. See for Yourself

  • config


    I'm always hacking away on a project or two. Usually born out of necessity, interest, or boredom. Check out my GitHub to see what I've been working on recently. Check it out!

iOS Links that Redirect to your App with a Web Fallback

I get really frustrated when I open an email on my iPhone and it’s not optimized for mobile devices. Especially since 65% of email is opened first on a mobile device.1 Links are the worst! Most of the time they redirect to mobile Safari and when they try to redirect me to the app it’s an awful experience. There’s a better way.

I work as a technical advisor to a company whose business model currently revolves around daily emails. They ran up against the very common issue of how to redirect users to their app from an email. At first glance it seems like a simple issue, until you put the typical roadblock in the way: Apple. Apple allows you to register a custom protocol for your app, but if the app isn’t installed, the redirect fails in a horrendous way (see screenshot below). A much better experience is the that user is gracefully redirected to the web version if the app isn’t installed.

Unsupported protocol error

StackOverflow is rife with proposed solutions and hacks. After researching it for a few days I came to the conclusion that there are a few viable solutions:

  1. Redirect to the app if it’s installed or the app store to download it.
  2. Have the web page try to open the app and show the error above if it fails. Optionally set a cookie so the page remembers and doesn’t alert them again.
  3. Show a preemptive alert giving the users the option to open the app if installed, go to the App Store to download it, or continue to the web page.

I decided that #2 was probably the best experience for the user and we started along that path.

Google+ Did Something Right

We started along that path until I opened a Google+ Circle notification and clicked “Add to Circles”. The link opened Safari and showed the unsupported protocol alert, but then something crazy happened: it dismissed the alert automatically and redirected me to the Google+ website.2 All within a half-second and without any effort on my part. That’s the experience we need to give our users. I modeled the HTML response below off of the Google+ redirect and you can demo it from your iPhone with the links below.

<!DOCTYPE html>
    <title>App Redirect</title>
      // 1
      var customProtocol = 'fb'; // Facebook app link protocol.
      var redirectURI = 'https:\/\/';
      var startTime =;

      // 2
      setTimeout(function() {
        // 3
        if ( - startTime < 2000) {
          window.location = redirectURI;
      }, 100);

      // 4
      window.location = redirectURI.replace(/^http[s]?/, customProtocol);

What’s going on?

  1. Add our app’s custom protocol to test if the app is installed and a link to the web fallback if it isn’t.
  2. Wait 1/10th of a second for the app to open before redirecting to the web fallback.
  3. If less than 2 seconds have elapsed then redirect to the web fallback. The logic being that if the app opened, the user most likely won’t return for more than 2 seconds.
  4. Attempt to redirect the user to the app.

Click here from your iOS device to open the Facebook app if installed.
Click Here to simulate the Facebook app not being installed and open the Facebook website instead.

This is the best experience I’ve had with app redirects on iOS. Our implementation relies on the query string to dynamically populate the `redirectURI`, but it can just as easily be server generated by your click-tracking endpoint. Let me know in the comments below if you have a different/better solution.

If you enjoyed this post, please follow me on Twitter.


For MySQL: Goodbye NodeJS, Welcome Back PHP

Talk about words you never thought you’d hear yourself saying!

If you’ve ever worked with me (or probably even spoken with me) you know I love Node.js. I love everything about it…Javascript, the frameworks, the community, everything. I’m especially fond of the trend toward NoSQL data stores in combination with Node.

Having used one or more NoSQL databases in my last few projects, I know they’re fast, usually Javascript based, and the absolute wrong choice for a project I just started. The right choice: a relational database. MySQL being my choice.

I’m not going to go into why that’s the right choice, or MySQL over PostgreSQL, or InnoDB over MyISAM. There are a number of reasons, but it mostly comes down to the project requirements and personal preference.


What does it matter? Isn’t the database independent of the scripting language?

Yes and no. They’re independent systems, but we still need drivers to interface between them. That’s where the problem lies.

With the focus on NoSQL data stores, I don’t think anyone has taken the time to write a performant MySQL driver. The situation gets even worse with ORMs and worse still with newer versions of Node. Most of the solutions I found don’t support Node 0.7.x.

Wanting desperately to “make it work,” I spent some time this weekend comparing different combinations of Node drivers and frameworks/ORMs with those available in PHP.  PHP is the clear winner.

| Driver/ORM           | Type   | Run 1 | Run 2 | Run 3 |Average|
| NodeJS_mysql         | driver | 4.53  | 4.58  | 4.65  | 4.58  |
| NodeJS_sequelize     | orm    | 11.64 | 11.70 | 11.74 | 11.69 |
| PHP_PDO              | driver | 2.14  | 2.21  | 2.21  | 2.18  |
| PHP_laravel_raw      | driver | 3.33  | 3.37  | 3.38  | 3.36  |
| PHP_laravel_eloquent | orm    | 4.52  | 4.38  | 4.37  | 4.42  |
| PHP_doctrine         | orm    | 2.43  | 2.44  | 2.54  | 2.47  |
| PHP_zenddb           | driver | 2.39  | 2.48  | 2.48  | 2.45  |

If you’re wondering how I arrived at those results, the repo is on GitHub. Feel free to fork it f you have another driver or ORM you think should be included.

The Point

Pick the right tool for the right job. Look at the results above. The right tool for MySQL is not Node. Not yet anyway.