node2dm ======


A node.js server for sending push notifications to Google's C2DM push notification server. Written by Instagram to support our Android application, and inspired by statsd's protocol.

Copy the provided exampleConfig.js into a config.js file, and follow the instructions in the file to fill out your application's Google account credentials. Then just run:

node node2dm.js /path/to/config/file

A sample upstart script is included for easy deployment on Ubuntu.

Messages are pushed to the service using simple UDP datagrams, separated by a colon; here's what our Python application server code looks roughly like:

c2dm_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
encoded_payload = '%s:%s:%s' % (
                         (c2dm_server, c2dm_port))

As you can see from the example, the datagram looks as follows:


We chose UDP because we wanted to minimize latency between our application servers and the node2dm service, and don't have hard delivery requirements for push notifications.

node2dm handles a variety of errors that may be passed back from the C2DM service:

  • 401: Will force a re-authentication with the C2DM service
  • 503: Will back off, respecting the Retry-After header
  • QuotaExceeded: In this case, your application has exceeded Google's quota for pushes for the day. node2dm will write out a quota.lock file and quit itself
  • DeviceQuotaExceeded: You're sending too many pushes to this device; node2dm will blacklist this token for an hour before trying to send any more messages
  • InvalidRegistration/NotRegistered: Something's wrong with this device token; node2dm will drop the message
  • MessageTooBig: node2dm will drop this message

node2dm supports a simple webhook-like callback on a bad token error from Google. To set it up, configure serverCallbackHost / serverCallbackPort / serverCallbackPath / serverCallbackSharedSecret in your config.js, and you should start receive POST requests with this payload:

device_token (the offending device token)
message_body (the body of the message that was being attempted; can be useful if you need to match something back up on your end)
shared_secret (the serverCallbackSharedSecret, can match up on your end to make sure it's the right server sending you a ping)

node2dm comes with a simple, telnet-able stats function. To use it:

> echo "stats" | nc localhost 8121
uptime: 226 seconds
messages_sent: 20583
messages_in_queue: 0
backing_off: false
total_errors: 9
rate_limited_tokens: 0
logged_in_to_c2dm: true
token_age: 221
memory_rss: 88793088
memory_heapTotal: 11075584
memory_heapUsed: 3658300

The project is BSD-licensed; please fork and submit a pull request for any improvements you'd like to see in node2dm.