In October 2009 I started a project called Notify.io and a month later announced it. I talked about how it will bring notifications to the web. Now that it’s basically alpha complete, I’ll give you a quick walkthrough of what makes it so great.

Overview
At a really high level, you can think of Notify.io as a notification router. As a web service, it provides a singleton endpoint for any web-connected program, whether a web application, desktop application or user script, to send notifications to somebody. For users, you can control what notifications you get and how you get them. In this way, Notify.io is like a global, web-accessable version of the popular Growl application for OS X (which should honestly just ship with OS X). Only it’s even better.

Desktop Notifications
The original inspiration for Notify.io was to make Growl more useful by fixing its ability to receive notifications from the Internet. Out of the box, Growl is effectively only good for notifications from sources running on your machine. If you wanted to get notifications from a web app, you’d have to wait for them to release a desktop notifier, which hopefully would use Growl to actually display the notifications. So you end up with all these desktop notifiers running for some apps, and have no option of desktop notifications for others.

This is probably the killer feature of Notify.io: it lets you get desktop notifications from any web app that supports it, which is an order of magnatude easier for them to do than build their own desktop notifier.

Sources and Outlets
The language of Notify.io is based around Sources and Outlets. Sources are pretty straightforward. They’re a source of notifications. They could represent an application, script, company, person (or perhaps object?) that can send you notifications.

Outlets repesent the other major feature of Notify.io. They’re ways you can get a notification. The Desktop Notifier is your first and default outlet, but is just one of several options. Currently supported Outlets besides Desktop Notifier are Email, Jabber IM, and Webhooks. Outlets to look forward to are SMS, Twitter, IRC, and perhaps telephone.

The magic is in routing notifications from Sources to Outlets. Currently this is a simple mapping of Source to Outlet. For example, you can get notifications from Source A on your desktop, while notifications from Source B go to IM. This simplistic routing is just the beginning. We’ll talk about how we’ll do advanced routing when we get to the Roadmap.

The Nio Client
For developers, it’s worth mentioning that the pipe for our Desktop Notifier is really just a Comet HTTP stream. It can be consumed by pretty much anything. We were originally talking with Growl and authors of other desktop notifiers of direct integration. This is still a possibility, but just so we could move forward, we built our own client for OS X. Clients for other systems are available (but not yet “officially” supported) or are in progress, including Windows and Android.

Our OS X client is called Nio, short for Notify.io, so you can pronounce it N-I-O, but I tend to pronounce it “neo”. It’s basically just an application that sits in your menu bar listening to HTTP streams (yes, plural) for notifications and pipes them into Growl.

For ease of installing streams, we made it handle files of the extension ListenURL. Once Nio is installed, you can download a ListenURL file containing a URL and it gets installed by Nio. The URL we give you is basically a “capability URL” or secret URL. This means streams are not super secure, but this is by design. If you wanted, you could share your URL with somebody so you both get notifications sent to that Outlet. You can always delete the Outlet and make another to disable that URL.

The other cool thing about our client is that it has a shell script notification hook. This means you can have notifications trigger a shell script that’s passed the notification details. This is pretty powerful because it means you can do things like create your own local logging, hear your notifications with text-to-speech, or make certain notifications trigger a more obstrusive means of notifying you, such as Quicksilver’s Large Type feature. This kind of programmability is central to our approach to design, as you’ll see later on in the Roadmap.

Simple API and Approval Model
For proper adoption, we need web apps to integrate Notify.io, so we have a super simple API for Sources. It’s a simple REST API based on an endpoint constructed by the target of your notification. Like Gravatar, we use an MD5 hash of a user’s email address to identify targets. For example, to send a notification to test@example.com, you’d do an HTTP POST to this URL:

http://api.notify.io/v1/notify/55502f40dc8b7c769880b10874abc9d0

You’d pass a few parameters, with at least your API key (meaning you need an account) and the text you want to send, and optionally an icon URL, link URL, title text and whether the notification should be “sticky”. That’s it. The request should respond immediately so it may be quick enough to be done inline in your app, but we recommend it be done asynchronously.

Then what happens is the first notification you send actually triggers a notification to that user that you want to send them notifications. If they accept, future notifications will be sent and your previous notifications will show up in their history. This may change to replay previous notifications on approval, but the point here is the user has to approve notifications before they get them. In this way, it’s similar to Jabber’s approval model and helps avoid spammers.

Public Service Software
Notify.io and its clients are open source. The service is free. Or rather, it’s not-for-profit donationware. Notify.io is being run under a model I’m developing called POSS, the goal of which is to automate/abstract away the maintainence and funding of its operation. The end result should be: the service exists, it’s open source, and some in the developer community can deploy changes. But no single person is financially responsible for it, and it’s run on maintained cloud infrastructure. In this case it’s mostly App Engine.

This means that Notify.io is not a startup. It’s public infrastructure. Ideally, I’m not even in the loop. It should be a self-sustaining public service. This is not fully realized, but it will be as it starts to consume more resources. For more information, you can read more on POSS or join our discussion group.

For now, the important thing is that Notify.io is open source. This means anybody can contribute bug fixes, new outlets, new desktop clients, etc.

Roadmap
Okay, sure, Notify.io is pretty cool now. But here are some of the major things that will be coming soon. Hopefully with your help!

Advanced Routing and Filters
From the beginning, I wanted really powerful routing and filtering. My evangelism of webhooks has given me the obvious answer to this, but in a more integrated way. Basically, how do you allow any routing scheme imagineable by users? Let them write code. Originally it was going to be powered by Scriptlets, but since I split the eval engine out as DrEval, it will be based on that.

Basically, just a imagine a UI with a little textarea for writing JavaScript that can make web calls. Route notifications based on your IM status, your location, what music you’re listening to, arbitrary time schedules, or anything you can code.

More Outlets
Obviously, more Outlets are good. Obvious ones are IRC, SMS, and Twitter DM. With Twilio we can do voice call notifications. Integration with push clients like the iPhone’s Prowl app would be easy to do. Our outlet system is very simple, so you can look at the source of our existing ones, write an outlet and it’s likely we’ll deploy it.

OpenID Support
Right now, you authenticate with Google. I don’t believe in creating authentication systems, and Google was the quickest given the platform. It’s also pretty popular and ensures you have an email address we can use. However, there are plenty of people that don’t like the idea of using their Google Account, so at some point we’ll support OpenID login and then go from there.

Multiple Email Support
Ideally, a web app can use whatever email address you used to register with them to send you notifications. However, unless Gmail is your primary email you use for registration, they’ll still need to ask you for your email. It’s the Gravatar model. So like Gravatar, we’ll need to let you add multiple emails to your account, allowing web applications to be able to send notifications based on any of them.

Convenience Libraries
Our API is simple, but people are lazy. We’re currently working on convenience libraries for popular langauges that it make that much easier to integrate with Notify.io. If you use a neat language, you should make a libnio package for it!

Ad-hoc Sources
Sources require an account, which is a bit heavyweight. Sometimes you want to create your own distinct sources to share with others or use in your scripts to easily send yourself notifications. This is the idea of Ad-hoc Sources, inspired by David Reid and capability URLs. The idea is simple: create an ad-hoc source and you get a secret URL. This URL acts just like the notify API endpoint, only you don’t need an API key. You can use this in public scripts or give it to others to send you notifications, and if it’s ever abused or falls in the wrong hands, just delete it and make another.

More Supported Clients
A developer in Japan started a Windows client based on Nio that we’re planning to support as our primary Windows client. Another developer is working on an Android client. iPhone users have Prowl, so once there is a Prowl outlet, you can get them on your iPhone. But Prowl is not free, so perhaps it would be helpful if we had our own iPhone client. There are the beginnings of a Linux/libnotify client. These are all ways you can start contributing to Notify.io. ;)

That’s about it. You can probably see why I describe Notify.io as the open notification platform of the web. It’s simple, powerful, and open source. It’s come a long way in just 3 months thanks to the contributions of Abimanyu Raja, Amanda Wixted, Mike Lundy, David Reid, Christopher Lobay, Hunter Gillane, Nakamatsu Shinji, and everybody that’s given user feedback so far. I recently made a quick screencast for the homepage that I’ll end with so you can see it in action.

The “real-time web” is a popular topic right now. My WebHooks initiative is both riding on this success and helping make it a reality. One sector of this trend is about notifications. Real-time notifications to you about events you care about.

For a long time we’ve had helper apps like the Google Notifier and more recently the Facebook Desktop Notifications app that bring events from the web to your desktop. Twitter has created a whole ecosystem of clients that not only let you actively check Twitter, but passively get updates from Twitter.

Simultaneously, we’ve had a bunch of systems like Growl emerge that give you a consistent, well-designed and customizable system for local applications to give you notifications. While your IM client is in the background, it can tell you somebody IM’d you and what they said in an unobtrusive way. It integrates with email applications to tell you of new emails. It gives any application developer a nice way to present notifications to the user in a way that’s in their control.

Some of the apps that bring web applications to your desktop like Tweetie, Google Notifier, etc will integrate with Growl (which has a counterpart on pretty much every platform, including the iPhone). The problem is that you only get these notifications when the desktop apps are running, despite the fact web apps are always running. And yes, you have to have an app running for each web application you use.

And that’s only if they built a desktop app and you were convinced to download it. Most web applications are never be able to notify you with any means other than email. But as I’ve argued before, notifications don’t belong in your inbox!

Another minor point is that all these apps use polling to get updates. In some cases this doesn’t matter, but as data starts moving in real-time, this batches your notifications into bursts that you may not be able to parse all at once. I use Tweetie to get Growl notifications from Twitter at the moment, and if a lot of people are updating, I get a huge screen of updates that I don’t have time to read before they disappear. It becomes useless.

A while back I attempted to make an app called Yapper that lets anybody send real-time notifications to your desktop via XMPP. It was an experiment, and ultimately not the answer. It was only part of the solution.

But today I’m announcing the full solution: a free, public, open-source web service called Notify.io (Notify-I-O).

Notify.io integrates with Growl and other local notifiers (as well as email, Jabber, Twitter, and webhooks) and provides a dead-simple API for any web developer to send real-time notifications to their users.

You can think of Notify.io as a web-level Growl system. It empowers users with a consistent, controllable way to get notifications, and it provides developers with a simple, consistent way for sending those notifications.

Notify.io is an open platform for notifications. It’s still in a pre-alpha state, but it already has several useful notification sources. Last Thursday I built Feed Notifier, which uses PubSubHubbub to give you real-time desktop notifications of Atom and RSS feed updates.

At SHDH 35 last Saturday, Abi Raja built a Facebook notification adapter for Notify.io that’s yet to be released. And there a couple more in the pipeline (by me and others) to show the power of Notify.io.

Again, it’s pre-alpha, so before I talk much more about it, I should probably finish more of it. I just wanted to make sure I blogged about it in somewhat of a timely fashion. I seem to have a backlog of blog posts about apps I’ve built recently. However, Notify.io is a pretty significant one. Feel free to check it out, just remember that despite its looks, it’s nowhere near finished — but it does work.

Update: I’ve basically stopped development and support of Yapper because Notify.io is the right way to solve this problem. However, this post describes that problem and is still worth the read. ;)

Yapper, a Jabber/XMPP interface for Growl

Today I released Yapper, a full featured Jabber/XMPP interface for Growl. It was based on the simple Twisted script I wrote while building my notification email to Growl piping. Although it’s limited to OS X users, I still think this is a big deal. Let me explain.

If you haven’t heard of Growl, it’s a global notification system that lets applications notify you of events in a consistent, customizable way. It’s been around for a while and is integrated or has plugins for lots of popular apps like iTunes, Adium, and Tweetie. It has bindings for a bunch of languages and also has a command line tool that you shell scripters can use to pipe notifications into. For example, I used this recently for my reminder system.

I think Growl is great particularly because it very nicely solves passive real-time notifications. That is, you want to be notified, but you don’t want it to interrupt you by requiring action. This is why I hate email notifications.

However, the major problem with Growl is that for the most part, it’s limited to local notifications. Sure, you can get notifications from “out there,” like Twitter or IRC or Gmail … but it requires you to have a local application that pushes them into Growl. One for each, in fact.

It turns out, I don’t actually care about most local notifications. Telling me a file is done downloading or what song is playing in iTunes is not terribly notification worthy. If I’m sitting there to get the notification, I probably already know. The most useful notifications are of events important to me that I’m nowhere near … events from things out on the Internet.

So Growl needs a network interface. Oh, wait! It has one! Well, what’s the problem? Two things: it’s a non-standard protocol, and it requires a direct connection. That not only raises the bar for things “out there” to notify you with Growl, but it literally makes it impossible if you’re constantly changing IPs, sitting behind a firewall or NAT, etc.

Let’s see… who’s solved this problem already? Right, IM! XMPP, the open standard for IM and real-time message passing (also known as Jabber), seems to have everything we need. It’s a popular protocol, fairly accessible from any language, and doesn’t require a direct point to point connection. So it’s a perfect transport for network Growl notifications!

Since I’m not one to wait around for people to implement what I think they should implement, I solved this problem by making Yapper. Yapper is a lightweight Jabber client made specifically to receive Growl notifications. It starts when your machine starts and sits in the background just waiting for whatever you have sent to it so it can pop it up with Growl.

You can now easily have Growl notifications sent to you from anywhere. Websites have less of a reason not to directly notify you with Growl for events that are important to you. More importantly for me, I can more easily set up Growl notifications for whatever I want. With the rise of webhooks, so can you. Anyway, to me this generally makes Growl much more useful.

Give Yapper a look. It’s on GitHub under MIT license. It’s the first release, but it should work fine. If not, drop off an issue and it’ll likely be taken care of.

The other day I realized I hate notification emails. In particular I’m talking about SVN commit notifications. I have them set up to skip my inbox and filter into a label on GMail, but this doesn’t really help. They don’t pollute my inbox, but I still have to go out of the way to read them. Or at the very least, mark them as read, which is still quite annoying!

Growl is supposed to help solve this problem. In fact, when I was retooling the notification system at work, I would have loved to integrate Growl … except that Growl’s network interface requires a direct connection.

Taking a step back, it’s not just work notifications. A lot of us get a lot of notification emails about a lot of things. Most of them are poorly designed, for example, without important details of the notice in the subject. Plus, as email they require disrupting action. Not just to open and read if you have to, but just to archive and/or mark as read.

It’s great to have an archive in email, but email is just not ideal for notifications. If I’m around to receive them, I should get the important information passively and not have to do anything else until I need to reference it later, if ever. That means Growl.

Getting Notification Emails to Growl

I thought to myself, “I should be able to rig this up. And it should be easy.” And if the infrastructure and plumbing I’ve wanted was in place, it would be easy. So I decided to lay it down and make it happen. Here’s what I needed:

  • An email to webhook bridge, like my old Mailhook service.
  • An XMPP to Growl bridge. We all want this anyway, right?
  • An HTTP to XMPP bridge. Why? You’ll see.
  • Glue code that can run in the cloud. This is what Scriptlets is for.

I’ve since turned off Mailhook, but I’ve been planning to roll its code into my still early Protocol Droid project. This is an HTTP to anything bridge written in Python with Twisted that makes heavy use of webhooks. I’d plan to roll the HTTP to XMPP bridge in there as well. For now, the XMPP to Growl bridge would be separate.

Having all that, here was the pipeline I envisioned:

  • A notification email would come into Gmail and get filtered
  • It would forward to an address that points to Protocol Droid
  • Protocol Droid would post the email to a script on Scriptlets
  • The script would use Protocol Droid again to send an XMPP message
  • The message would be sent to a JID for my laptop if online
  • The XMPP to Growl bridge on my laptop would receive and notify me

Building the Infrastructure

I decided to build all this last Friday night. I got caffeinated and went to work, starting with Protocol Droid. I hadn’t touched it since I was trying to build an HTTP to SMTP module for it. It wasn’t part of this project, but I decided to finish it off. You know, to get warmed up and have an early win.

That happened pretty quickly, so I was excited get started on the next task: an email to webhook bridge. This was a little different. So far everything in Protocol Droid was for outgoing connections. This would be the first listening module. The idea was that it would be an SMTP server that would parse incoming email and post it to a callback URL registered for a recipient domain. I’d written several of these before for mailhook.org, so I ported the code to Twisted for Protocol Droid. Another pretty easy win. I used PostBin to debug this, obviously.

At that point, I decided to take a break and watch an episode of Pushing Daisies. I still haven’t seen all of the second season!

Then came the hard part. Well, I thought it would be easy. The HTTP to XMPP bridge. It turns out the XMPP support in Twisted isn’t very well documented and slightly underdeveloped. I had to build a couple of prototypes to get the hang of it. Even then, building this module and the XMPP to Growl daemon took about 7 hours! Compared to the 3 hours spent doing the last two modules. XMPP is definitely a bit hard to really get into.

By 8am I had all the pieces working. I thought about going the last mile and getting it all online and set up the pipeline … but I decided I deserved some sleep. I’d do it when I wake up.

Getting the Pipeline in Place

When I woke up on Saturday, I was still burnt out from coding. I spent the day hanging out with friends. Then later I invited some more friends over for hacking at my place. There I spent more time than I wanted getting my code to run on my server. Apparently OpenSSL for Python wasn’t installed and the Google Talk servers required TLS. It took a while to figure this out since no error was raised and Google would just drop my connection.

I finally got all the infrastructure I built online and tested. Finally, I could work on the actual pipeline. It was supposed to be easy from that point on. And it was! Except for one bit …

I got almost all the pieces connected and it all came down to the glue code on Scriptlets. The script would parse the email however I like and set up the message that would end up on my laptop via Growl. It turns out Scriptlets is a bit of a pain to use. No edit, no debugging, crappy error messages. Since I built it as a proof of concept, I hadn’t done much development on it, let alone with it. Anyway, I learned a lot and have some things to fix. But! I was still able to get everything working!

I had my friend Adam send the first test email that would go through the entire pipeline I outlined above. He sent it from his phone, just to add a little to the magic. Low and behold, it worked perfectly, quite quickly. It took 4 seconds from him sending to the notice appearing … but about 3 of those seconds were the time it took for the phone to send the email. Nevertheless, brilliant!

Next Steps

I’ve since found out about Wokkel, which might simplify some of my XMPP code. I have some other enhancements to make to each piece to make them more general. And I mentioned some of the things I need to add to Scriptlets.

Functionally, the pipeline is pretty good. The only addition I can think of would require an HTTP to IMAP bridge in Protocol Droid (something I’ve already prototyped). I’d use this to mark the notification email as unread if it wasn’t able to deliver the IM. But for now, I think I’m done on this project. And you can all take advantage of the infrastructure I built out for rigging up your own cool hacks.

Most of the code this weekend went into these two projects, so check them out!

For my todo system, I’ve been using Quicksilver with Remember the Milk for a while. It’s great for being able to throw things into my todo list at anytime (as long as I’m at my laptop). Especially with its natural language date parsing: “buy some cheerios tomorrow” or “see brothers bloom tuesday.” However, it’s not a very good reminder system.

Occasionally I’d use it with a specific time (“dentist appointment tomorrow 9am”), but for the most part, Remember the Milk todos are not about micro time management within the day. Especially since they don’t have a good notification method. So for reminders, I had to build my own system. Here’s what I wanted:

  • Simple text scheduling from Quicksilver
  • Growl for the reminder
  • Natural scheduling (“go home at 7pm”, “eat lunch in 5m”)

Since most Unix systems (including OS X) have the `at` command for scheduling commands with a decent syntax, and Growl has the `growlnotify` command, I decided to start at the command line with a shell script.

#!/bin/bash
growlnotify=/usr/local/bin/growlnotify
normal=$(echo $1 | sed -e 's/ in / at /')
what=${normal%% at*}
when=${normal##*at }
when=$(echo $when | sed -e 's/^\([0-9]*\)m$/now + \1 minutes/')
when=$(echo $when | sed -e 's/^\([0-9]*\)h$/now + \1 hours/')
result=$(echo "$growlnotify -s -m '$what' > /dev/null 2>&1" | at $when 2>&1)
if [ $? -eq 0 ]; then
    result=${result##*at }
    result="Scheduled for $result"
fi
$growlnotify -m "$result"

This script takes a single argument string in the format I described above, splitting $what and $when with either “at” or “in”. Then I expand relative time (“10m” or “2h”) into the format `at` wants (“now + 10 minutes” — which I didn’t want to have to type). It schedules the command to use `growlnotify` with $what (as a sticky notification, so it won’t go away until I click it), and then immediately tells you when it was scheduled for if successful, or it tries to show you the error if not.

So that works fine. Now Quicksilver. You can write new actions in AppleScript, but I didn’t want to try and figure out how to write the above in AppleScript. It was hard enough figuring it out in bash. So the AppleScript action is just going to call out to that shell script.

using terms from application "Quicksilver"
	on process text str
		do shell script "/Users/Jeff/.scripts/growlat.sh \"" & str & "\" > /dev/null 2>&1"
		set selection of application "Quicksilver" to str
	end process text
end using terms from

Apparently AppleScript files are not plain text, so you have to write it using Script Editor. Make sure the path to growlat.sh points to the shell script above. Then save this as Remind.scpt in your user’s “~/Library/Application Support/Quicksilver/Actions” directory. If it doesn’t exist, just make the directory. Restart Quicksilver and you should now have a Remind action! It’ll look like this: