Hard Numbers About My Book

numbers photo

Photo by MrHicks46

I self published a Developing Cross Platform Mobile Applications with Cordova CLI last fall. It’s about the Cordova command line tool (Cordova CLI). Cordova is a way for web developers to build mobile apps that are distributed via the various app stores and can access app functionality (your list of contacts, for instance). The CLI is the main method of interacting with Cordova–managing your files, building apps, etc.

You can see my take on writing the book and marketing it, but I wanted to give some hard numbers on the results.

I thought I’d share some lessons from this experience. I started on 8/29/2013, had my first purchase, for $4, on 9/3/2013 (Leanpub lets users buy in progress books and get any updates), and published the 100% complete version on 10/4/2013. The book is 54 pages long.

Sales numbers as of today:

  • 56 readers
  • 47 readers who paid for the book
  • 9 readers who received free copies (reviewers and members of the Cordova community, because I am grateful for the work they’ve done)
  • 2 refunds (Leanpub has a 45 day no questions asked “Happiness Guarantee” refund policy)
  • Price range: $4-$20
  • Current price range: $20
  • Total royalties: $572.73
  • Number of people who paid over list price: 2

Here’s a graph of when purchases took place:

Sales By Week for Developing With Cordova CLI

Visits/conversions from 8/29/2013 to 9/9/2014 to the leanpub page (note that these don’t match up with the above numbers because if someone disables Javascript or cookies from Google, Google Analytics won’t track the purchase, and also I didn’t enable conversion tracking until Sep 18, 2013):

  • 5897 sessions
  • 4731 visitors
  • 37 book purchases tracked
  • 0.63% conversion rate
  • 53.75% abandonment rate
  • 84.92% bounce rate
  • 79.67% new sessions

Traffic sources:

  • 59.4% of sessions are from organic search
  • 13.5% from referrals
  • 13.2% from social
  • 10.6% direct
  • 2.3% from “other”
  • 0.9% from paid search

Highest referral sites for visits:

  1. Stackoverflow
  2. mooreds.com
  3. devgirl.org (I wrote a guest post)
  4. twitter
  5. google groups
  6. cloudfour.com (I wrote a guest post)
  7. hacker news

Highest referral sites for conversions (out of 14 conversions):

  1. Direct
  2. devgirl.org
  3. Google (organic)
  4. mooreds.com (embed and referrals combined)
  5. twitter

Pricing matters.  I varied the price, depending on how close the book was to being complete. The vast majority of my royalties came when I priced the book at $20.  That felt fair to me for a fifty page ebook about a technical topic. If someone charges $60/hour and this book saves them an hour, they have a 3x ROI (yes, I probably should charge more).

Overall, writing a book has been a great learning experience (and the couple hundred dollars in my pocket feel good too).  I learned about writing, research, and marketing. I learned that very few people buy an ebook and return it. I learned that sometimes a single sentence in a book can take you an hour to verify. I learned that it can be fun to write and promote your book. In retrospect, the only thing I’d change would be to write on an evergreen topic.  Cordova is moving fast enough that, while there is still value in this book, it needs a refresh every six months or so to remain relevant.


My Book Marketing Process

bazaar photo

Photo by -Marlith-

Last year, I wrote a technical book, focused on a niche tool of a niche technology. I posted about my writing process, but wanted to write about my marketing process as well. As my father, who has published a few books, says: “once you finish the book, the hard work [marketing] begins”.  After all, the world, and even the Internet, is a big place, and no one was going to beat a path to my door (or yours).

I tried several different marketing channels. Here’s a list and some commentary on how each channel worked in terms of traffic and sales.  My main goal was to drive traffic to my leanpub book page, where purchase was only a click away.

  • I published a blog post about the book and put an embedded ‘buy now’ link on my blog sidebar. I also did some follow up posts about Cordova CLI, including one about accessing more info from hooks in later version of Cordova and running multiple version of Cordova. Hard to tell if the additional content helped, but I had quite a few sales referred from my domain.
  • I set up a Google alert for ‘cordova CLI’ to see if there was anyplace I could reply and help people with questions while linking to my book page.
  • Monitored and answered Stackoverflow questions about Cordova and Cordova CLI–these typically also figured prominently in the Google alert. SO was the third highest referrer to my leanpub book page.
  • Google adwords: this didn’t work so well. I had 7K impressions and a 0.52% CTR but no conversions. I ran the campaign for about two months, but most of the keywords were pretty obscure.
  • Guest posts at on topic blogs: this worked great. I posted two different posts–Three hooks your Cordova/Phonegap application needs and Phonegap makes mobile app development more accessible. The more aligned the blog post was with the audience of the blog, the better the conversion. I also engaged in the comments section as well.
  • Emails to tech influencers (often with a coupon for a free or reduced price book). This was both marketing and a ‘thank you’ to all the people who either help out with Cordova, or who I have read for years and just wanted to thank (ahem, Matt Raible). It did result in some tweets. Thanks to Jason Grigsby, Brian Leroux and Holly Schinsky
  • Posting on the phonegap google group about the book, with a coupon. This didn’t drive that many visits, but the ones who did converted very well (>25%).
  • Posting on the phonegap google group answering general questions with a link in my signature. This drove some traffic and lead to one conversion. It didn’t scale very well, as when I stopped answering questions, the traffic fell to zero quickly.
  • Emails to members of the phonegap developer directory. I ended up sending out about 50 of these (both myself and hiring someone from Odesk). Surprisingly, I didn’t see any sales from these emails, which were admittedly “cold calls”.
  • Posted to hackernews. No discussion, but a non trivial number of visits.

Here are some things I should have done, or should have done sooner:

  • Set up a custom domain, like this person did.
  • Build a useful email list.  I actually have one, but it’s hard to find out how to subscribe.  Oh, and post to said list.
  • Written and flogged a talk about Cordova. There are probably two or three meetups in the Denver or Boulder area that would have been happy to have me talk, and I expect I would have sold some books through that venue.
  • Added the book to Amazon and Barnes and Noble. I just did that (links to Amazon, Barnes & Noble). Leanpub makes it silly simple to do this, however the royalty hit you take for the distribution is high.
  • Written more articles and pitched them to online magazines. In fact, I should have, when writing the book, queued up 3-5 articles to pitch to publish on launch day.
  • Emailed my readers via leanpub and asked how I could help them (I did this, belatedly).
  • Kept the book up to date. (I still may review, expand and update the book, because it is still a topic that interests me (and there is interesting stuff happening with Cordova, like Ionic and Google Glass support.)

I missed some of these marketing opportunities because my life just got too busy. Others because we stopped using Cordova at my day job, which meant I had less interest in keeping up with Cordova in general. And that, in turn, made it hard to keep up with marketing effort.

The final piece of advice I would share about marketing an ebook is that it is a long game. I realized that even a book on a topic so short lived as a Cordova book–it covers 2.9, 3.0 and 3.1, and the current version is 3.5–there are still ‘long tail’ effects. I make sales now, almost a year after first release.


My Book Writing Process

writing photo

Photo by mrsdkrebs

I wrote an ebook last fall. It’s about the Cordova command line tool (Cordova CLI). Cordova is a way for web developers to build mobile apps that are distributed via the various app stores and can access app fucntionality (your list of contacts, for instance). The CLI is the main method of interacting with Cordova–managing your files, building apps, etc. It’s a niche, but one that I felt passionately about. I love the command line and I love webapps. I find the whole native app experience distasteful. (“Didn’t we already watch this movie?”)

I thought I’d share some lessons from this experience. This post will be about the writing, the next one about the marketing, and the final one about the results.

I wrote a series of blog posts, gathered here, to determine if I would enjoy writing a book, and to give me a head start on the content. Those blog posts were primarily written in July when my wife was away visiting family. I figured that if I didn’t want to write the book, the blog posts would have value anyway–writing clarifies issues for me. If they were useful and shared, then I would have some market validation.

On August 1, weeks after publishing my first Cordova blog post, I received an email from a reader who said the posts were useful, and asked a question. This was enough validation that I decided to start the book. It was five weeks from creating the project on leanpub to completing it (late August to early October).

During the book writing, I focused on expanding on the blog posts to make sure they were authoritative, adding new content as I came up with questions, and verifying all the claims using the Cordova software. I remember spending an hour trying to confirm one part of one sentence in the book. I also spent time answering and asking questions on the Cordova/Phonegap Google group. I also monitored the Cordova developer list, more for interesting topics than for dialog. And a new version of Cordova (3.1) was released just a week or so before I was done with the book, so I spent some time double checking how the new version of the CLI worked.

As far as time, I averaged an hour a day for that five week period–remember, a good chunk of the content was already written and I was simply revising it. I found time on the weekends and in the early morning.

I ended up finding a flickr image to use for the cover page–thanks Marc!

In the end, the writing was fun and a grind all at the same time. You just have to make the time.


Accessing more build information from your Cordova CLI hooks

Hooks now give you, as of cordova CLI 3.3.1-0.4.2, much more information about the environment you were executing in.

Before, if I had platform specific code, I needed to check at runtime:

App.config.flurryid = "";
    if (window.device && window.device.platform) {
        if (window.device.platform == "Android") {
            App.config.flurryid = /*REP*/ 'notreallyanandroidflurryid' /*REP*/ ;
        }
        if (window.device.platform == "iOS") {
            App.config.flurryid = /*REP*/ 'notreallyaniosflurryidxxx' /*REP*/ ;
        }
    }

Now, you can inject platform specific code at build time, via hooks. The runtime code is simplified to

App.config.flurryid = /*REP*/ 'myflurryid' /*REP*/;

and you just replace 'myflurryid' with the appropriate value from your configuration file (more on platform specific configuration files).

From the readme in the hooks directory:

All scripts are run from the project’s root directory and have the root directory passes as the first argument. All other options are passed to the script using environment variables:

* CORDOVA_VERSION – The version of the Cordova-CLI.
* CORDOVA_PLATFORMS – Comma separated list of platforms that the command applies to (e.g.: android, ios).
* CORDOVA_PLUGINS – Comma separated list of plugin IDs that the command applies to (e.g.: org.apache.cordova.file, org.apache.cordova.file-transfer)
* CORDOVA_HOOK – Path to the hook that is being executed.
* CORDOVA_CMDLINE – The exact command-line arguments passed to cordova (e.g.: cordova run ios –emulate)

Here’s a sample plugin which you can put in your hooks/before_prepare directory. If you do this and then run cordova -d prepare you can see the values for all the variables.

#!/usr/bin/env node

console.log("process.env.CORDOVA_VERSION: "+process.env.CORDOVA_VERSION);
console.log("process.env.CORDOVA_PLATFORMS: "+process.env.CORDOVA_PLATFORMS);
console.log("process.env.CORDOVA_PLUGINS: "+process.env.CORDOVA_PLUGINS);
console.log("process.env.CORDOVA_HOOK: "+process.env.CORDOVA_HOOK);
console.log("process.env.CORDOVA_CMDLINE: "+process.env.CORDOVA_CMDLINE);

Here’s the output for a test project.

Executing hook 

""/home/mooreds/git/testproject3/hooks/before_prepare/test.js" 

"/home/mooreds/git/testproject3""
process.env.CORDOVA_VERSION: 3.3.1-0.4.2
process.env.CORDOVA_PLATFORMS: android
process.env.CORDOVA_PLUGINS: 
process.env.CORDOVA_HOOK: /home/mooreds/git/testproject3/hooks/before_prepare/test.js
process.env.CORDOVA_CMDLINE: node /usr/local/bin/cordova -d prepare

Note that if you are using this for platform specific code, you will want to run the commands separately: cordova build android and cordova build ios. If you just run cordova build and you have both ios and android platforms installed, the process.env.CORDOVA_PLATFORMS variable will be android,ios, and your code won’t be able to differentiate between them.

If you want to know about more Cordova CLI changes, check out “3 Cordova CLI Changes You Should Know About” which covers version 3.3.1-0.3.1.


Running multiple versions of Cordova 3.x

cordova, the command line interface to the Cordova development framework, is a node package. npm, the node package manager, has the concept of a ‘global’ install and ‘local’ installs. Typical installs of the cordova command line interface instruct you to perform a global installation. That is what the -g in npm install -g cordova (from the docs) means. Installing globally means that one version of cordova is available to every user on that computer, and will be installed in a system directory (for example, /usr/local/lib/node_modules, on linux). If you upgrade that one version, everyone and every project on the system will be upgraded (or forced to upgrade, depending on your perspective).

If you want to run different versions of cordova for different projects, you have to install locally. That means that all the cordova code will be installed in a local directory, rather than a system wide directory.

Why might you want do this? Any number of reasons, but primarily because the relationship between your application and a particular version of Cordova is important.

  • If your application depends on bugs or feature behavior that has changed between versions, you could need to freeze your application at a given version of Cordova, at least until you were able to update your application and test it against a newer version.
  • You could have multiple applications that were developed at different times, and the older ones could crash if upgraded (or perhaps you don’t have the time to test against the latest cordova version).
  • Applications under active development may be at the latest and greatest version of cordova, while the others may be sitting at what was the latest and greatest when they were last modified.
  • A local install will let you test your application against a new version of cordova without committing a global install, which might affect other team members, other projects, or necessitate a downgrade if the new version has issues.
  • You might be working on a platform that is not amenable to being place in a virtual machine (like iOS) and yet still want to run different versions of Cordova on the same machine.

Below, I outline steps to follow if you want to have one project using Cordova 3.3 and another using Cordova 3.1. npm view cordova lets you view the available versions–typically you want the latest minor revision (3.3.1-0.1.2 is better than 3.3.0-0.1.0). These are steps for Android, but it would be similar for any target platforms. And these steps assume you have successfully installed the target platform tools for Android previously.

mkdir cordova3.3 # or cordova3.1
cd cordova3.3 # or cordova3.1
npm install cordova@3.3.1-0.1.2 # or 3.1.0-0.2.0
mkdir project
cd project 
../node_modules/cordova/bin/cordova create test33 io.cordova.HelloWorld33 # or test31 io.cordova.HelloWorld31
cd test33 #(or test31)
../../node_modules/cordova/bin/cordova platform add android
../../node_modules/cordova/bin/cordova plugin add org.apache.cordova.device

Don’t forget to add the device feature to your config.xml

<feature name="Device">
    <param name="android-package" value="org.apache.cordova.device.Device" />
</feature>

You need to update the www/js/index.js file to display your Cordova version. This is only to prove you have different versions of Cordova running on the same machine

onDeviceReady: function() {
        alert(device.cordova);
        //app.receivedEvent('deviceready');
    },

Finally build the application and run it on your emulator:

emulator -avd avdname # start a previously created avd via the android command
../../node_modules/cordova/bin/cordova build android
../../node_modules/cordova/bin/cordova emulate android

Note that there should be no issues with running applications built with different versions of cordova on the same device–the applications are all sandboxed.

If you are often in this situation, you can create aliases that point to the correct version of the cordova command, since the results are indeterminate if you mix and match calls to different versions. For example:

alias cordova31='/path/to/cordova3.1/node_modules/cordova/bin/cordova'
alias cordova33='/path/to/cordova3.3/node_modules/cordova/bin/cordova'

Incidentally, I tried these steps out with the latest version of the android tools (version 19 of the Android build tools) with all four of the latest minor revisions of cordova: 3.0.10, 3.1.0-0.2.0, 3.2.0-0.4.0, and 3.3.1-0.1.2, and could only get the 3.1.x and 3.3.x versions to work. So another reason to do a local install is to perform a quick check to see if your platform installation is compatible with a given version of Cordova.

Do you have different versions of Cordova installed on the same machine?


PhoneGap Usage Survey Results

A few weeks ago, I asked the PhoneGap google group members to fill out a simple usage survey. I was interested in versions of Cordova/PhoneGap used, as well as what device platforms were targeted. I had 30 responses over just under two weeks. Note that this survey closed on the 29th, before Cordova 3.1 was released.

Here are the results. (Some questions allowed multiple answers, so the number of responses may exceed 30.)

“What version of Cordova/PhoneGap do you mainly use?” A solid majority was on a modern version, either 2.9 or 3.0.
Which version of cordova do you use?

“What device platforms do you target?” The vast majority of respondents target iOS and, to a slightly lesser extent, Android. There are a smattering of other platforms being targetted.
what-device-platforms-do-you-target

“What versions do you have in production?” Every version of the 2.x line was represented. I think this shows that upgrading PhoneGap/Cordova projects used to be a pain (and, once an app is finished, there often times is no need to revisit).
Which versions do you have in production?

“Do you use Cordova or PhoneGap?” This is interesting to me because I think there is a lot of confusion around the difference. Most people were pretty clear.
do-you-use-cordova-or-phonegap

The results of this survey was interesting to me and I hope to you as well.



How to collect usage statistics in your phonegap/cordova application

My company recently wrote a couple of mobile applications. Since one is for consumer use (search for ‘8z neighborhood’ in the App Store/Google Play if you live in Colorado or the Bay area and want to check it out), I wanted to know what type of users were downloading and installing it, what was being used, and other general usage statistics.

I asked a mobile app vendor we’ve worked with what they used for usage stats, and they said Flurry. I also looked at Google Analytics, Mobile–this is a nice q&a explaining the major players in the mobile analytics market. We didn’t want anything complicated, just basic stats with the possibility of collecting further information in the future, so I went with the vendor recommendation. Flurry also works with the two platforms we were targeting: IOS and Android, as well as many others.

Flurry is zero cost, but nothing’s free–they want your data and you grant them a “right, for any purpose, to collect, retain, use, and publish in an aggregate manner” all data collected from your application. I’ve seen similar TOS from most of the free analytics vendors, so this was no surprise.

To use Flurry with cordova/phonegap, and with plugman, I was ready to plugmanify an existing Flurry phonegap plugin. Luckily, someone else had already done it. All I had to do was update the plugin to work with Cordova 2.9, and to use the latest IOS7 compatible Flurry library.

After you install the plugin (I recommend doing so in an after_platform_add hook script), you simply add this to your code after the deviceready event fires: window.plugins.flurry.startSession(sessionkey). I inject the session key using a hook script, because I wanted a different key for stage and production builds, and also for each device platform (Flurry requires the latter). Because hooks only get the root directory as context (although this is supposed to change) I had to put some logic in the javascript to call startSession with the appropriate key:

 App.config.flurryid = "";
    if (window.device && window.device.platform) {
        if (window.device.platform == "Android") {
            App.config.flurryid = /*REP*/ 'notreallyanandroidflurryid' /*REP*/ ;
        }
        if (window.device.platform == "iOS") {
            App.config.flurryid = /*REP*/ 'notreallyaniosflurryidxxx' /*REP*/ ;
        }
    }

Although I have not used any of the more specific event tracking, the basic statistics are a great start (including new users, retained users, device versions, etc).

Don’t fly blind when you release your phonegap/cordova mobile app–use Flurry or something simliar.


Releasing with Cordova CLI

When you are done developing your mobile application, you will want to release the binary, and have it distributed by whatever means is typical for that platform (typically some kind of app store).

How does Cordova CLI help with this? It doesn’t.

Typically, the best way to release a cordova/phonegap application for a given platform is to find out how to do a release for that platform from the platform’s documentation, and follow that. For instance, for android, you can run ant release and sign an apk with custom keys–all of that process is independent of Cordova CLI.

It’s worth reiterating that cordova CLI is a toolset to help with development of applications–deployment is still platform specific.

Next up, a conclusion.

Subscribe to my infrequent Cordova newsletter


How to ‘plugman’ify an existing plugin

In a previous post, I talked about adding a new plugin that you wrote to your Cordova CLI project. However, there are a ton of existing plugins out there, and many of them haven’t yet migrated over to the new plugman architecture. What should you do when there is a plugin that solves your problem, but is not installable via plugman?

Your options include:

  • install the plugin the old fashioned way, by downloading and copying its files into your project directory. This is a a bad idea because if there are future bug fixes or feature improvements to the plugin, you’ll have to manually pull them in.
  • forego the plugin. But you are looking at it specifically to save you time or allow you to implement a feature that would otherwise be too hard or time consuming–so you can’t exactly ignore it.
  • search for another plugin that does the same thing–great, if you can find it.
  • make the plugin plugman compatible–this is the best option.

The first step to making a plugin plugman compatible is to file a bug/issue with the project. Perhaps they are already planning to do this work, and a request from you will get it moved up the queue. If so, fantastic–see when they think it will be done. If not, at least you’ve let them (and others who look at the issues list) know that this is something they should do.

If it won’t be done in your timeframe (or at all), you can do it yourself. The main tassks are writing a plugin.xml file, and possibly modifying some javascript files. Start with the plugin.xml spec.

Before you plunge in, though, think about the licensing surrounding the plugin, as, unless you are replacing everything or the license is extremely permissive, your contributions will need to be under the same or a compatible license as the original code, especially if you want to contribute the changes back.

You want to make sure you use version control. If you are modifying a plugin on github, it is as simple as forking that project. You may be able to take the plugin code and import it into your version control system.

Write the plugin.xml file, and make sure to check it into the version control system. Writing a plugin.xml file is straightforward; however, there are two ways to handle javascript–you can treat it as an asset, where plugman dumbly copies it to the www directory wherever you tell it to, or you can treat it as a js-module. Plugman does some extra work for js-module javascript, including injecting it into the index.html and adding the created javascript object to the window object. Using js-module is the preferred method, but you may have to edit the javascript files and remove any cordova.define syntax. Also, if you need to move plugin files around, or rename them to help code maintainability, do so.

Test and install it just as you would any other plugman managed plugin (cordova plugins add http://...).

Once you’ve done this and it works, consider pointing to your plugin.xml in your open bug. Some authors may be receptive to code contributions or pull requests.

In the next post, I’ll discuss how Cordova CLI helps you release your application.

Subscribe to my infrequent Cordova newsletter



© Moore Consulting, 2003-2017 +