Web APIs Articles

Sort by:


  1. Introducing navigator.mozPay() For Web Payments

    What’s wrong with payments on the web? Any website can already host a shopping cart and take credit card payments or something similar. The freedom of today’s web supports many business models. Here’s what’s wrong:

    • Users cannot choose how to pay; they have to select from one of the pre-defined options.
    • In most cases, the user has to type in an actual credit card number on each site. This is like giving someone the keys to your expensive car, letting them drive it around the block in a potentially dangerous neighborhood (the web) and saying please don’t get carjacked!
    • Merchants typically have to manage all this on their own: payment processor setup, costly processing fees, and possibly even PCI compliance.

    There are services to mitigate a lot of these complications such as PayPal, Stripe, and others but they aren’t integrated into web devices very well. Mozilla wants to introduce a common web API to make payments easy and secure on web devices yet still as flexible as the checkout button for merchants.

    As a first step, Mozilla will introduce navigator.mozPay() in Firefox OS so that web apps can accept payments.

    How Does It Work?

    navigator.mozPay() is a JavaScript API inspired by but modified for things like multiple payment providers and carrier billing. When a web app invokes navigator.mozPay() in Firefox OS, the device shows a secure window with a concise UI. After authenticating, the user can easily charge the payment to her mobile carrier bill or credit card. When completed, the app delivers the product. Repeat purchases are quick and easy.

    In an earlier article I talked about purchasing an app and receiving a receipt. navigator.mozPay() is different in that there is no concept of what product is purchased, it’s just an API to facilitate a payment for a digital good or service, whatever that may be.

    The payment starts and finishes in the client but further processing and notifications happen server side. This article briefly explains how it all fits together. For complete, in-depth documentation read the Firefox Marketplace guide to in-app payments.

    Integrating With A Payment Provider

    Multiple providers will facilitate payments behind the scenes of navigator.mozPay(). For example, the Firefox Marketplace will be able to facilitate payments.

    As a developer you will essentially grant permission to each provider that you would like to sell through. In the current design of the API, you do this by asking each provider for an Application Key and an Application Secret so that you can digitally sign payment requests. A signed request prevents unauthorized parties from selling your products and prevents users from tampering with the price, etc.

    Initiating A Payment

    When the user clicks a Buy button in your web app, you create a JSON Web Token (JWT) with your Application Secret. If you have agreements with multiple providers, you would create a JWT for each provider. Starting a payment looks roughly like this:

    document.querySelector('').onclick = function() {
        navigator.mozPay([mozillaJWT, otherJWT, ...]);

    Defining A Product

    A JWT is a signed JSON object that defines details like the product name and price. Here is an example with some attributes removed for brevity:

      "iss": APPLICATION_KEY,
      "aud": "",
      "request": {
        "name": "Magical Unicorn",
        "pricePoint": 1,
        "postbackURL": "",
        "chargebackURL": ""

    You define prices as price points so that the payment provider can handle currency conversions for you in each region. In this example, pricePoint 1 might be €0.89 or $0.99, etc. Micropayments in small amounts will be supported. Consult the navigator.mozPay() spec for details on how to construct a payment request JWT.

    Completing a Payment

    To complete the payment, you need to wait for the provider to POST a result to your server’s postbackURL (on success) or chargebackURL (on failure). A more complete example of requesting a purchase in JavaScript would involve waiting for the postback to arrive, like this:

    var request = navigator.mozPay([mozillaJWT, otherJWT]);
    request.onsuccess = function() {
      // The payment window has closed.
      whenPaymentResultReceived(function() {
        console.log('Success! User has purchased a Magical Unicorn.');

    To implement whenPaymentResultReceived() you might open a web socket to your server, wait for the payment result, and verify the incoming JWT signature. The navigator.mozPay() spec has details on how postback and chargeback notifications work.

    Try It Out

    Payments aren’t fully live yet in the Firefox Marketplace but you can simulate a payment to test out your code. Log into the Firefox Marketplace Developer Hub and generate an Application Key and Application Secret for simulations. With those keys you can add a special parameter to the JWT like this:

      "request": {
        "name": "Magical Unicorn",
        "pricePoint": 1,
        "simulate": {"result": "postback"}

    This will show a payment window on Firefox OS but it won’t charge you real money. It will let you test your client side JavaScript code and your server postback handlers to make sure everything is integrated smoothly. When you go live, just remove the simulate attribute. If you’re new to Firefox OS development, check out the Firefox OS Simulator.

    If you’re already working on a game or a web app for Firefox OS try thinking about using navigator.mozPay() to offer premium content.

    This Would Be Way Easier With A Library

    We thought so too! We built libraries for Node.JS and Python to make the server side logic for navigator.mozPay() as easy as possible. Libraries for more languages are on the way. We also are experimenting with removing the server prerequisite entirely.

    Current Status

    As you can probably tell by the prefix, navigator.mozPay() is an experimental API and might change drastically or become unprefixed without notice. It will process live payments on the first Firefox OS phones and evolve quickly from real world usage.

    Mozilla plans to work with other vendors through the W3C to reach consensus on a common API that supports web payments in the best way possible. After shipping in Firefox OS, Mozilla plans to add navigator.mozPay() to Firefox for Android and desktop Firefox.

    New Business Models

    Advertising has been the primary business model on the web for a long time but users have made it clear that they don’t want to see ads. Mozilla isn’t trying to directly disrupt the ad business but it is trying to fix serious privacy issues relating to ad networks.

    What if users explicitly paid for content instead? navigator.mozPay() enables this kind of direct payment model: if something is good on the web, you can pay for it. It already seems to be working well for existing mobile apps. Will mobile ads even generate the same revenue for content producers as they do on desktop? I don’t have answers to these questions but one thing is for certain: the web should support businesses of all kinds and payments should be a first class feature of the web.

    Is It Webby?

    Mozilla’s main goal with navigator.mozPay() is to give users and merchants choice, security, and an easy to use payments system. The details about how merchants interact with payment providers is not yet specified in the API and that is clearly a gap. The first Firefox OS phones will ship with a whitelist of allowed payment providers which is also not ideal.

    In a more webby model, all parties involved in the payment would be fully decentralized so that innovation can occur naturally and unknown payment providers could emerge. Who will be the next M-Pesa? An elegant API would support that. Building a secure decentralized payment API is an ambitious challenge; the solution would need to address these core trust issues:

    • How can customers trust that they will receive the goods after paying?
    • How would customers ensure that their payment credentials are handled securely?
    • How do merchants guarantee that they’ll get paid after delivering goods?

    As with anything related to money, there is incentive for fraud every step of the way. BitCoin is a digital currency that solves some of these trust issues with block chains and PaySwarm is a web payment protocol that solves some of these issues with decentralized assets, public keys, etc. Mozilla will be watching PaySwarm as well as other models and hopefully navigator.mozPay() can incorporate some of these concepts eventually.

  2. Introducing Web Activities

    One of the more powerful things lately for apps on various mobile phones have been intents. Register your app for handling certain types of actions, or specify in your app what kind of support you are looking for, for the thing you are trying to do.

    This is especially important in the case of Firefox OS. No matter how good your web app is to begin with, what really takes it to the next level is interaction with other apps and activities on the device.

    This is where Web Activities come into place.

    It is basically one of the new WebAPIs we’ve been working on to make the web even more powerful as a platform, and the idea is to have a simple API to both specify intent with your activity, but also declare that your app will be able to handle actions from other apps.

    If you haven’t looked into web apps yet, by the way, the best thing is probably to read Getting started with making apps. In their simplest form, a web app is just HTML5, CSS and JavaScript, with an app manifest added.

    Getting started with Web Activities

    There are a few ways you can work with Web Activities:

    • Call an activity and get presented with apps that can handle that
    • Register your activity support for your web app in the manifest file
    • Register activity support on-the-fly
    • Attach a handler to your app for when that activity occurs

    Calling an activity

    Let’s say you have a button in your app, and you want to be able to get a picture – either from the Gallery, Camera or any other app in Firefox OS that supports that activity. You can then call the pick activity, like this:

    var pick = new MozActivity({
       name: "pick",
       data: {
           type: ["image/png", "image/jpg", "image/jpeg"]}

    In this example, we specify the name pick and the data to be PNG or JPEG images. You will then be presented with a menu of available activities in Firefox OS:

    As a user, you choose the app you want to pick an image from – or take a picture with the Camera – and once you’ve done so, the result will be posted back to the requesting app (Note: it is chosen from within the app handling the activity what, and if, something will be returned).

    Handling the response

    For most WebAPIs, including Web Activities, you will have onsuccess and onerror event handlers. In the case of an image/file you will get a blob back. You can then represent that returned image visually directly in your app:

    pick.onsuccess = function () {// Create image and set the returned blob as the src
        var img = document.createElement("img");
        img.src = window.URL.createObjectURL(this.result.blob);
        // Present that image in your app
        var imagePresenter = document.querySelector("#image-presenter");
    pick.onerror = function () {// If an error occurred or the user canceled the activity
        alert("Can't view the image!");

    Register your app for an activity

    As mentioned above, you can also set your app as a handler for certain activities. There are two ways to do that:

    Through the manifest file – declaration registration

        "name": "My App",
        "description": "Doing stuff",
        "activities": {
           "view": {
                "filters": {
                    "type": "url",
                    "url": {
                        "required": true,

    Register an activity handler – dynamic registration

    var register = navigator.mozRegisterActivityHandler({
        name: "view",
        disposition: "inline",
        filters: {
            type: "image/png"

register.onerror = function () {
        console.log("Failed to register activity");}

    and then handle the activity:

    navigator.mozSetMessageHandler("activity", function (a) {var img = getImageObject();

        img.src = a.source.url;/*
          Call a.postResult() or a.postError() if 

          the activity should return a value


    Available activities

    The available activities to choose from at this time are:

    • configure
    • costcontrol/balance
    • costcontrol/data_usage
    • costcontrol/telephony
    • dial
    • new (e.g. type: “websms/sms”, “webcontacts/contact”)
    • open
    • pick (e.g. type: “image/png”)
    • record
    • save-bookmark
    • share
    • test
    • view

    A few examples:


    var call = new MozActivity({
        name: "dial",
        data: {
            number: "+46777888999"

    New SMS

    var sms = new MozActivity({
        name: "new",
        data: {
            type: "websms/sms",
            number: "+46777888999"

    New Contact

    var newContact = new MozActivity({
        name: "new",
        data: {
            type: "webcontacts/contact",
            params: { // Will possibly move to be direct properties under "data"
                giveName: "Robert",
                familyName: "Nyman",
                tel: "+44789",
                email: "",
                address: "Sweden",
                note: "This is a note",
                company: "Mozilla"

    View URL

    var openURL = new MozActivity({
        name: "view",
        data: {
            type: "url", // Possibly text/html in future versions
            url: ""

    Save bookmark

    var savingBookmark = new MozActivity({
        name: "save-bookmark",
        data: {
            type: "url",
            url: "",
            name: "Robert's talk",
            icon: ""}

    Try it out now!

    You can try this out right now, by putting together a web app and calling web activities. You can then test it in the Firefox OS Simulator!

    Work in progress

    Web Activities are a work in progress, and the activity names, data types etc are subject to change. However, currently most of the above works right now (with the exception for mozRegisterActivityHandler and mozSetMessageHandler, that haven’t been implemented yet).

    I hope you share my excitement with all the possibilities Web Activities are offering us, and can probably think of a number of use cases, making your app much more powerful through interaction with other apps!

  3. Flash-Free Clipboard for the Web

    As part of our effort to grow the Web platform and make it accessible to new devices, we are trying to reduce the Web’s dependence on Flash. As part of that effort, we are standardizing and exposing useful features which are currently only available to Flash to the entirety of the Web platform.

    One of the reasons why many sites still use Flash is because of its copy and cut clipboard APIs. Flash exposes an API for programmatically copying text to the user’s clipboard on a button press. This has been used to implement handy features, such as GitHub’s “clone URL” button. It’s also useful for things such as editor UIs, which want to expose a button for copying to the clipboard, rather than requiring users to use keyboard shortcuts or the context menu.

    Unfortunately, Web APIs haven’t provided the functionality to copy text to the clipboard through JavaScript, which is why visiting GitHub with Flash disabled shows an ugly grey box where the button is supposed to be. Fortunately, we have a solution. The editor APIs provide document.execCommand as an entry point for executing editor commands. The "copy" and cut" commands have previously been disabled for web pages, but with Firefox 41, which is currently in Beta, and slated to move to release in mid-September, it is becoming available to JavaScript within user-action initiated callbacks.

    Using execCommand("cut"/"copy")

    The execCommand("cut"/"copy") API is only available during a user-triggered callback, such as a click. If you try to call it at a different time, execCommand will return false, meaning that the command failed to execute. Running execCommand("cut") will copy the current selection to the clipboard, so let’s go about implementing a basic copy-to-clipboard button.

    // button which we are attaching the event to
    var button = ...;
    // input containing the text we want to copy 
    var input = ...;
    button.addEventListener("click", function(event) {
      // Select the input node's contents;
      // Copy it to the clipboard

    That code will trigger a copy of the text in the input to the clipboard upon the click of the button in Firefox 41 and above. However, you probably want to also handle failure situations, potentially to fallback to another Flash-based approach such as ZeroClipboard, or even just to tell the user that their browser doesn’t support the functionality.

    The execCommand method will return false if the action failed, for example, due to being called outside of a user-initiated callback, but on older versions of Firefox, we would also throw a security exception if you attempted to use the "cut" or "copy" APIs. Thus, if you want to be sure that you capture all failures, make sure to surround the call in a try-catch block, and also interpret an exception as a failure.

    // button which we are attaching the event to
    var button = ...;
    // input containing the text we want to copy
    var input = ...;
    button.addEventListener("click", function(event) {
      event.preventDefault();; // Select the input node's contents
      var succeeded;
      try {
        // Copy it to the clipboard
        succeeded = document.execCommand("copy");
      } catch (e) {
        succeeded = false;
      if (succeeded) {
        // The copy was successful!
      } else {
        // The copy failed :(

    The "cut" API is also exposed to web pages through the same mechanism, so just s/copy/cut/, and you’re all set to go!

    Feature testing

    The editor APIs provide a method document.queryCommandSupported("copy") intended to allow API consumers to determine whether a command is supported by the browser. Unfortunately, in versions of Firefox prior to 41, we returned true from document.queryCommandSupported("copy") even though the web page was unable to actually perform the copy operation. However, attempting to execute document.execCommand("copy") would throw a SecurityException. So, attempting to copy on load, and checking for this exception is probably the easiest way to feature-detect support for document.execCommand("copy") in Firefox.

    var supported = document.queryCommandSupported("copy");
    if (supported) {
      // Check that the browser isn't Firefox pre-41
      try {
      } catch (e) {
        supported = false;
    if (!supported) {
      // Fall back to an alternate approach like ZeroClipboard

    Support in other browsers

    Google Chrome and Internet Explorer both also support this API. Chrome uses the same restriction as Firefox (that it must be run in a user-initiated callback). Internet Explorer allows it to be called at any time, except it first prompts the user with a dialog, asking for permission to access the clipboard.

    For more information about the API and browser support, see MDN documentation for document.execCommand().

  4. Let’s Write a Web Extension

    You might have heard about Mozilla’s WebExtensions, our implementation of a new browser extension API for writing multiprocess-compatible add-ons. Maybe you’ve been wondering what it was about, and how you could use it. Well, I’m here to help! I think the MDN’s WebExtensions docs are a pretty great place to start:

    WebExtensions are a new way to write Firefox extensions.

    The technology is developed for cross-browser compatibility: to a large extent the API is compatible with the extension API supported by Google Chrome and Opera. Extensions written for these browsers will in most cases run in Firefox with just a few changes. The API is also fully compatible with multiprocess Firefox.

    The only thing I would add is that while Mozilla is implementing most of the API that Chrome and Opera support, we’re not restricting ourselves to only that API. Where it makes sense, we will be adding new functionality and talking with other browser makers about implementing it as well. Finally, since the WebExtension API is still under development, it’s probably best if you use Firefox Nightly for this tutorial, so that you get the most up-to-date, standards-compliant behaviour. But keep in mind, this is still experimental technology — things might break!

    Starting off

    Okay, let’s start with a reasonably simple add-on. We’ll add a button, and when you click it, it will open up one of my favourite sites in a new tab.

    The first file we’ll need is a manifest.json, to tell Firefox about our add-on.

      "manifest_version": 2,
      "name": "Cat Gifs!",
      "version": "1.0",
      "applications": {
        "gecko": {
          "id": ""
      "browser_action": {
        "default_title": "Cat Gifs!"

    Great! We’re done! Hopefully your code looks a little like this. Of course, we have no idea if it works yet, so let’s install it in Firefox (we’re using Firefox Nightly for the latest implementation). You could try to drag the manifest.json, or the whole directory, onto Firefox, but that really won’t give you what you want.

    The directory listing


    To make Firefox recognize your extension as an add-on, you need to give it a zip file which ends in .xpi, so let’s make one of those by first installing 7-Zip, and then typing 7z a catgifs.xpi manifest.json. (If you’re on Mac or Linux, the zip command should be built-in, so just type zip catgifs.xpi manifest.json.) Then you can drag the catgifs.xpi onto Firefox, and it will show you an error because our extension is unsigned.

    The first error

    We can work around this by going to about:config, typing xpinstall.signatures.required in the search box, double-clicking the entry to set it to false, and then closing that tab. After that, when we drop catgifs.xpi onto Firefox, we get the option to install our new add-on!

    It’s important to note that beginning with Firefox 44 (later this year), add-ons will require a signature to be installed on Firefox Beta or Release versions of the browser, so even if you set the preference shown below, you will soon still need to run Firefox Nightly or Developer Edition to follow this tutorial.


    Of course, our add-on doesn’t do a whole lot yet.

    I click and click, but nothing happens.

    So let’s fix that!

    Adding features

    First, we’ll add the following lines to manifest.json, above the line containing browser_action:

      "background": {
        "scripts": ["background.js"],
        "persistent": false

    now, of course, that’s pointing at a background.js file that doesn’t exist yet, so we should create that, too. Let’s paste the following javascript in it:

    'use strict';
    /*global chrome:false */
    chrome.browserAction.setBadgeText({text: '(ツ)'});
    chrome.browserAction.setBadgeBackgroundColor({color: '#eae'});
    chrome.browserAction.onClicked.addListener(function(aTab) {
      chrome.tabs.create({'url': '', 'active': true});

    And you should get something that looks like this. Re-create the add-on by typing 7z a catgifs.xpi manifest.json background.js (or zip catgifs.xpi manifest.json background.js), and drop catgifs.xpi onto Firefox again, and now, when we click the button, we should get a new tab! 😄

    Cat Gifs!

    Automating the build

    I don’t know about you, but I ended up typing 7z a catgifs.xpi manifest.json a disappointing number of times, and wondering why my background.js file wasn’t running. Since I know where this blog post is ending up, I know we’re going to be adding a bunch more files, so I think it’s time to add a build script. I hear that the go-to build tool these days is gulp, so I’ll wait here while you go install that, and c’mon back when you’re done. (I needed to install Node, and then gulp twice. I’m not sure why.)

    So now that we have gulp installed, we should make a file named gulpfile.js to tell it how to build our add-on.

    'use strict';
    var gulp = require('gulp');
    var files = ['manifest.json', 'background.js'];
    var xpiName = 'catgifs.xpi';
    gulp.task('default', function () {
      console.log(files, xpiName)

    Once you have that file looking something like this, you can type gulp, and see output that looks something like this:

    Just some command line stuff, nbd.

    Now, you may notice that we didn’t actually build the add-on. To do that, we will need to install another package to zip things up. So, type npm install gulp-zip, and then change the gulpfile.js to contain the following:

    'use strict';
    var gulp = require('gulp');
    var zip = require('gulp-zip');
    var files = ['manifest.json', 'background.js'];
    var xpiName = 'catgifs.xpi';
    gulp.task('default', function () {

    Once your gulpfile.js looks like this, when we run it, it will create the catgifs.xpi (as we can tell by looking at the timestamp, or by deleting it and seeing it get re-created).

    Fixing a bug

    Now, if you’re like me, you clicked the button a whole bunch of times, to test it out and make sure it’s working, and you might have ended up with a lot of tabs. While this will ensure you remain extra-chill, it would probably be nicer to only have one tab, either creating it, or switching to it if it exists, when we click the button. So let’s go ahead and add that.

    Lots and lots of cats.

    The first thing we want to do is see if the tab exists, so let’s edit the browserAction.onClicked listener in background.js to contain the following:

    chrome.browserAction.onClicked.addListener(function(aTab) {
      chrome.tabs.query({'url': ''}, (tabs) => {
        if (tabs.length === 0) {
          // There is no catgif tab!
          chrome.tabs.create({'url': '', 'active': true});
        } else {
          // Do something here…

    Huh, that’s weird, it’s always creating a new tab, no matter how many catgifs tabs there are already… It turns out that our add-on doesn’t have permission to see the urls for existing tabs yet which is why it can’t find them, so let’s go ahead and add that by inserting the following code above the browser_action:

      "permissions": [

    Once your code looks similar to this, re-run gulp to rebuild the add-on, and drag-and-drop to install it, and then when we test it out, ta-da! Only one catgif tab! Of course, if we’re on another tab it doesn’t do anything, so let’s fix that. We can change the else block to contain the following:

          // Do something here…
          chrome.tabs.query({'url': '', 'active': true}, (active) => {
            if (active.length === 0) {
              chrome.tabs.update(tabs[0].id, {'active': true});

    Make sure it looks like this, rebuild, re-install, and shazam, it works!

    Making it look nice

    Well, it works, but it’s not really pretty. Let’s do a couple of things to fix that a bit.

    First of all, we can add a custom icon so that our add-on doesn’t look like all the other add-ons that haven’t bothered to set their icons… To do that, we add the following to manifest.json after the manifest_version line:

      "icons": {
        "48": "icon.png",
        "128": "icon128.png"

    And, of course, we’ll need to download a pretty picture for our icon, so let’s save a copy of this picture as icon.png, and this one as icon128.png.

    We should also have a prettier icon for the button, so going back to the manifest.json, let’s add the following lines in the browser_action block before the default_title:

        "default_icon": {
          "19": "button.png",
          "38": "button38.png"

    and save this image as button.png, and this image as button38.png.

    Finally, we need to tell our build script about the new files, so change the files line of our gulpfile.js to:

    var files = ['manifest.json', 'background.js', '*.png'];

    Re-run the build, and re-install the add-on, and we’re done! 😀

    New, prettier, icons.

    One more thing…

    Well, there is another thing we could try to do. I mean, we have an add-on that works beautifully in Firefox, but one of the advantages of the new WebExtension API is that you can run the same add-on (or an add-on with minimal changes) on both Firefox and Chrome. So let’s see what it will take to get this running in both browsers!

    We’ll start by launching Chrome, and trying to load the add-on, and see what errors it gives us. To load our extension, we’ll need to go to chrome://extensions/, and check the Developer mode checkbox, as shown below:

    Now we’re hackers!

    Then we can click the “Load unpacked extension…” button, and choose our directory to load our add-on! Uh-oh, it looks like we’ve got an error.

    Close, but not quite.

    Since the applications key is required for Firefox, I think we can safely ignore this error. And anyways, the button shows up! And when we click it…


    So, I guess we’re done! (I used to have a section in here about how to load babel.js, because the version of Chrome I was using didn’t support ES6’s arrow functions, but apparently they’ve upgraded their JavaScript engine, and now everything is good. 😉)

    Finally, if you have any questions, or run into any problems following this tutorial, please feel free to leave a comment here, or get in touch with me through email, or on twitter! If you have issues or constructive feedback developing WebExtensions, the team will be listening on the Discourse forum.

  5. More details about the WebAPI effort

    As we’ve hoped, there has been a lot of interest in the newly announced WebAPI effort. So I figured that I should explain in more detail some of my thinking around what we’re hoping to do and the challenges that are ahead of us.


    The goal of this effort is to create APIs to expand what the Web can do. We don’t want people to end up choosing to develop for a proprietary platform just because the Web is lacking some capability.

    The main effort, at least initially, is to enable access to hardware connected to the device, and data which is stored or available to the device. As for hardware, we want to make the full range of hardware that people use available to the web platform. From common hardware like cameras, to more rarely used (but no less awesome) hardware like USB-driven Nerf cannons. We also want to enable communication hardware like Bluetooth and NFC.

    For data stored on the device, the most commonly discussed data today is contacts and calendar. This includes the ability to both read and write data. That is, we both want the Web platform to be able to enumerate contacts stored on the device, and read their details, as well as add and remove contacts. In short, we want it to be possible to create a Web page or Web app which lets the user manage his contact list. Same thing for calendar events and other types of data stored on devices.

    Security and Privacy

    One big reason these types of APIs haven’t been developed for the Web platform yet is because of their security and privacy implications. I would obviously not want every single Web page out there to be able to mess around with my contact list or my calendar. And being able to issue any commands to any USB device that I happen to have plugged in would likely result in everyone’s computer immediately being zombified.

    So as we are developing these APIs, we always have to develop a security model to go along with them. In some cases simply asking the user, which is how we currently do Geolocation, might work. In others, where security implications are scarier or where describing the risk to the user is harder, we’ll have to come up with better solutions.

    I really want to emphasize that we don’t yet know what the security story is going to be, but that we’re absolutely planning on having a solid security solution before we ship an API to millions of users.

    Robert O’Callahan has a really great post about permissions for Web applications.


    Mozilla has always had a strong commitment to Web standards. This is of course not something we’re changing! All of the APIs that we are developing will be developed with the goal of being standardized and implemented across both browsers and devices.

    But it’s important to ensure that standards are good standards. This takes experimenting. Especially in areas which are as new to the Web, and as security sensitive, as these are.

    Standards organizations aren’t a good place to do research. This is why we want to experiment and do research outside the standards organizations first. But always in the open, and always listening to feedback. We’re also going to clearly prefix any APIs as to indicate that they are experiments and might change once they get standardized.

    Once we have a better understanding of what we think makes a good API we will create a proposal and bring to working groups like the Device API group at W3C, WAC and WHATWG.

    Throughout this process we will of course be in contact with other interested parties, such as other browser vendors and web developers. This is part of the normal research and making sure that an API is a good API.

    Mozilla always has and always will be a good steward of the open Web. We are not interested in creating a Mozilla-specific Web platform. We are interested in moving the open Web platform forward.

    High Level vs. Low Level

    One thing that often comes up with API design is whether we should do high level or low level APIs. For example, do we provide a low-level USB API, or a high-level API for cameras?

    There are pros and cons with both. High level means that we can create more developer-friendly APIs. We can also provide a better security model since we can ensure that the page won’t issue any unexpected USB commands, and we can ensure that no privacy-sensitive access is made without user approval. But high level also means that developers can’t access a type of device until we’ve added support for it. So until we’ve added an API for Nerf cannons, there will be no way to talk to them.

    Exposing a low-level USB API on the other hand, means that web pages can talk to any USB device in existence, with no need for us to add an explicit API for them. However it also requires developers to get their hands dirty with the details of the USB protocol and differences between devices.

    The approach we’re planning on taking is to do both high-level and low-level APIs, as well as give people the proper incentives to use the one that is best for the user. But a very important point is to provide low-level APIs early to ensure that Mozilla isn’t on the critical path for innovation. Over time, we can add high-level APIs where that makes sense.

    How you can join

    As with all things Mozilla, we’re planning on doing all our work in the open. In fact, we’ll be relying on your help to make this successful! As to keep discussions focused, we’re going to use the a new discussion forum for all communication. This means that you can participate through email, newsgroups, or the web-based google group UI.

    You can subscribe to the mailing list at

    For other methods go to:

    We also use the #webapi IRC channel on

    We’ll also be tracking progress on the wiki page

    Looking forward to hearing from you to help build the next stage for the web platform!

    Hiring developers

    Edit: Forgot to mention, we are hiring several full time engineers for working on the WebAPI team! Read the job description and apply.

  6. Pointer Events now in Firefox Nightly

    This past February Pointer Events became a W3C Recommendation. In the intervening time Microsoft Open Tech and Mozilla have been working together to implement the specification. As consumers continue to expand the range of devices that are used to explore the web with different input mechanisms such as touch, pen or mouse, it is important to provide a unified API that developers can use within their applications. In this effort we have just reached a major milestone: Pointer events are now available in Firefox Nightly. We are very excited about this effort which represents a great deal of cooperation across several browser vendors in an effort to produce a high quality industry standard API with growing support.

    Be sure to download Firefox Nightly and give it a try and give us your feedback on the implementation either using the dev-platform mailing list or the group. If you have feedback on the specification please send those to

    The intent of this specification is to expand the open web to support a variety of input mechanisms beyond the mouse, while maintaining compatibility with most web-based content, which is built around mouse events. The API is designed to create one solution that will handle a variety of input devices, with a focus on pointing devices (mouse, pens, and touch). The pointer is defined in the spec as a hardware-agnostic device that can target a specific set of screen coordinates. Pointer events are intentionally similar to the current set of events associated with mouse events.

    In the current Nightly build, pointer events for mouse input are now supported. Additionally, if you’re using Windows, once you’ve set two preferences, touch events can be enabled now. The first property, Async Pan & Zoom (APZ) is enabled by setting the layers.async-pan-zoom.enabled Firefox configuration preference to true. The dom.w3c_touch_events.enabled should also be enabled by setting this value to 1 in your preferences.

    This post covers some of the basic features of the new API.

    Using the Pointer API

    Before getting started with the Pointer API, it’s important to test whether your current browser supports the API. This can be done with code similar to this example:

    if (window.PointerEvent) {
      // use mouse events

    The Pointer API provides support for pointerdown, pointerup, pointercancel, pointermove, pointerover, pointerout, gotpointercapture, and lostpointercapture events. Most of these should be familiar to you if you have coded event handling for mouse input before. For example, if you need a web app to move an image around a canvas when touched or clicked on, you can use the following code:

    function DragImage() {
        var imageGrabbed = false;
        var ctx;
        var cnv;
        var myImage;
        var x = 0;
        var y = 0;
        var rect;
        this.imgMoveEvent = function(evt) {
            if (imageGrabbed) {
                ctx.clearRect(0, 0, cnv.width, cnv.height);
                x = evt.clientX - rect.left;
                y = evt.clientY -;
                ctx.drawImage(myImage, x, y, 30, 30);
        this.imgDownEvent = function(evt) {
            //Could use canvas hit regions
            var xcl = evt.clientX - rect.left;
            var ycl = evt.clientY -;
            if (xcl > x && xcl < x + 30 && ycl > y && ycl < y + 30) {
                imageGrabbed = true;
        this.imgUpEvent = function(evt) {
            imageGrabbed = false;
        this.initDragExample = function() {
            if (window.PointerEvent) {
                cnv = document.getElementById("myCanvas");
                ctx = cnv.getContext('2d');
                rect = cnv.getBoundingClientRect();
                x = 0;
                y = 0;
                myImage = new Image();
                myImage.onload = function() {
                    ctx.drawImage(myImage, 0, 0, 30, 30);
                myImage.src = 'images/ff.jpg';
                cnv.addEventListener("pointermove", this.imgMoveEvent, false);
                cnv.addEventListener("pointerdown", this.imgDownEvent, false);
                cnv.addEventListener("pointerup", this.imgUpEvent, false);

    PointerCapture events are used when there’s the possibility that a pointer device could leave the region of an existing element while tracking the event. For example, suppose you’re using a slider and your finger slips off the actual element –you’ll want to continue to track the pointer movements. You can set PointerCapture by using code similar to this:

    var myElement = document.getElementById("myelement");
    myelement.addEventListener("pointerdown", function(e) {
        if (this.setPointerCapture) {
        //specify the id of the point to capture
    }, false);

    This code guarantees that you still get pointermove events, even if you leave the region of myelement. If you do not set the PointerCapture, the pointer move events will not be called for the containing element once your pointer leaves its area. You can also release the capture by calling releasePointerCapture. The browser does this automatically when a pointerup or pointercancel event occurs.

    The Pointer Event interface

    The PointerEvent interface extends the MouseEvent interface and provides a few additional properties. These properties include pointerId, width, height, pressure, tiltX, tiltY, pointerType and isPrimary.

    The pointerId property provides a unique id for the pointer that initiates the event. The height and width properties provide respective values in CSS pixels for the contact geometry of the pointer. When the pointer happens to be a mouse, these values are set to 0. The pressure property contains a floating point value from 0 to 1 to indicate the amount of pressure applied by the pointer, where 0 is the lowest and 1 is the highest. For pointers that do not support pressure, the value is set to 0.5.

    The tiltY property contains the angle value between the X-Z planes of the pointer and the screen and ranges between -90 and 90 degrees. This property is most useful when using a stylus pen for pointer operations. A value of 0 degrees would indicate the pointer touched the surface at an exact perpendicular angle with respect to the Y-axis. Likewise the tiltX property contains the angle between the Y-Z planes.

    The pointType property contains the device type represented by the pointer. Currently this value will be set to mouse, touch, pen, unknown or an empty string.

    var myElement = document.getElementById("myelement");
    myElement.addEventListener("pointerdown", function(e) {
        switch(e.pointerType) {
            case "mouse":
                console.log("Mouse Pointer");
            case "pen":
                console.log("Pen Pointer");
            case "touch":
                console.log("Touch Pointer");
                console.log("Unknown Pointer");
    }, false);

    The isPrimary property is either true or false and indicates whether the pointer is the primary pointer. A primary pointer property is required when supporting multiple touch points to provide multi-touch input and gesture support. Currently this property will be set to true for each specific pointer type (mouse, touch, pen) when the pointer first makes contact with an element that is tracking pointer events. If you are using one touch point and a mouse pointer simultaneously both will be set to true. The isPrimary property will be set to false for an event if a different pointer is already active with the same pointerType.

    var myElement = document.getElementById("myelement");
    myelement.addEventListener("pointerdown", function(e) {
        if( e.pointerType == "touch" ){
             if( e.isPrimary ){
                 //first touch
                 //handle multi-touch
    }, false);

    Handling multi-touch

    As stated earlier, touch pointers are currently implemented only for Firefox Nightly running on Windows with layers.async-pan-zoom.enabled and dom.w3c_touch_events.enabled preferences enabled. You can check to see whether multi-touch is supported with the following code.

    if( window.maxTouchPoints && window.maxTouchPoints > 1 ){
    //supports multi-touch

    Some browsers provide default functionality for certain touch interactions such as scrolling with a swipe gesture, or using a pinch gesture for zoom control. When these default actions are used, the events for the pointer will not be fired. To better support different applications, Firefox Nightly supports the CSS property touch-action. This property can be set to auto, none, pan-x, pan-y, and manipulation. Setting this property to auto will not change any default behaviors of the browser when using touch events. To disable all of the default behaviors and allow your content to handle all touch input using pointer events instead, you can set this value to none. Setting this value to either pan-x or pan-y invokes all pointer events when not panning/scrolling in a given direction. For instance, pan-x will invoke pointer event handlers when not panning/scrolling in the horizontal direction. When the property is set to manipulation, pointer events are fired if panning/scrolling or manipulating the zoom are not occurring.

    This element receives pointer events when not panning in the horizontal direction.
    // Very Simplistic pinch detector with little error detection,
    // using only x coordinates of a pointer event
    // Currently active pointers
    var myPointers = [];
    var lastDif = -1;
    function myPointerDown(evt) {
        console.log("current pointers down = " + myPointers.length);
    //remove touch point from array when touch is released
    function myPointerUp(evt) {
        // Remove pointer from array
        for (var i = 0; i < myPointers.length; i++) {
            if (myPointers[i].pointerId == evt.pointerId) {
                myPointers.splice(i, 1);
        console.log("current pointers down = " + myPointers.length);
        if (myPointers.length < 2) {
            lastDif = -1;
    //check for a pinch using only the first two touchpoints
    function myPointerMove(evt) {
        // Update pointer position.
        for (var i = 0; i < myPointers.length; i++) {
            if (evt.pointerId = myPointers[i].pointerId) {
                myPointers[i] = evt;
        if (myPointers.length >= 2) {
            // Detect pinch gesture.
            var curDif = Math.abs(myPointers[0].clientX - myPointers[1].clientX);
            if (lastDif > 0) {
                if (curDif > lastDif) { console.log("Zoom in"); }
                if (curDif < lastDif) { console.log("Zoom out"); }
            lastDif = curDif;

    You can test the example code here. For some great examples of the Pointer Events API in action, see Patrick H. Lauke’s collection of Touch and Pointer Events experiments on GitHub. Patrick is a member of the W3C Pointer Events Working Group, the W3C Touch Events Community Group, and Senior Accessibility Consultant for The Paciello Group.


    In this post we covered some of the basics that are currently implemented in Firefox Nightly. To track the progress of this API, check out the Gecko Touch Wiki page. You can also follow along on the main feature bug and be sure to report any issues you find while testing the new Pointer API.

  7. Using WebAPIs to make the web layer more capable

    Part of making both Firefox OS and the web as a platform a stronger layer and alternative for developers, we are working on a number of WebAPIs. I’d like to introduce you them here!

    Many things covered in this blog post are also available in a talk I’ve given on this topic.


    When you talk about new technology, ideas and solutions, people have a tendency to be wary. They might see it as the Not Invented Here syndrome, but that is not our intent (as we’ve written here before, and as mentioned by our CTO, Brendan Eich).

    Our intention is that everything we do is, or will be, standardized. Developed in the open.

    This blog post focuses on various WebAPIs, their security level and how to use them. In a later post, we will follow up specifically on standardization and progress in that area.

    Types of APIs

    There are basically three types of WebAPIs:

    Regular APIs
    APIs available from any app, hosted or packaged.
    Privileged APIs
    Only available in privileged apps. Privileged apps are apps that are:

    Certified APIs
    Certified APIs are only available to system itself (Mozilla in the case of Firefox OS), meaning they are so sensitive and need to be strictly controlled.

    Regular APIs

    The complete list of regular APIs is:

    • Vibration API
    • Screen Orientation
    • Geolocation API
    • Mouse Lock API
    • Open WebApps
    • Network Information API
    • Battery Status API
    • Alarm API
    • Web Activities
    • Push Notifications API
    • WebFM API
    • WebPayment
    • IndexedDB
    • Ambient light sensor
    • Proximity sensor
    • Notification
    • FMRadio

    Here’s how to use a number of them:

    Battery Status API

    This API is about detecting the current battery level of the computer/device, how long battery life there’s left and whether it’s being charged or not. Works in all three of desktop, Android and Firefox OS.

    var battery = navigator.battery;if (battery) {var batteryLevel = Math.round(battery.level * 100) + "%",

            charging = (battery.charging)? "" : "not ",

            chargingTime = parseInt(battery.chargingTime / 60, 10),

            dischargingTime = parseInt(battery.dischargingTime / 60, 10);
            // Set events

            battery.addEventListener("levelchange", showStatus);
            battery.addEventListener("chargingchange", showStatus);
            battery.addEventListener("chargingtimechange", showStatus);
            battery.addEventListener("dischargingtimechange", showStatus);}

    Vibration API

    Making the device vibrate, either once or with a certain pattern.

    // Vibrate for one second

    // Vibration pattern [vibrationTime, pause,…]

    navigator.vibrate([200, 100, 200, 100]);
    // Vibrate for 5 seconds

    // Turn off vibration


    Screen Orientation

    Gives you as a developer the chance to lock the orientation, or to specify what you want the primary orientation experience to be.

        Possible values:

    var portraitLock = screen.mozLockOrientation("portrait");
    if (portraitLock) {
        console.log("Orientation locked to portrait");

    Geolocation API

    Finding out where the user is at the moment – approved by the user to share this.

    navigator.geolocation.getCurrentPosition(function (position) {
            Getting latitude and longitude:

    Mouse Lock API

    Locking down the mouse movements and controlling the experience yourself. Especially good when you don’t want the mouse pointer/interaction to end when it hits the end of the web browser window, but rather to continue to scroll – like doing complete 360 degrees spin of an environment or similar.

    var docElm = document.documentElement;// Requesting Pointer Lock

    docElm.requestPointerLock = elem.requestPointerLock ||
                                elem.mozRequestPointerLock ||
    document.addEventListener("mousemove", function(e) {
        var movementX = e.movementX       ||
                        e.mozMovementX    ||
                        e.webkitMovementX ||
            movementY = e.movementY       ||
                        e.mozMovementY    ||
                        e.webkitMovementY ||
        // Get the mouse movement delta values
        console.log("movementX=" + movementX, "movementY=" + movementY);}

    Open WebApps

    In general, an APIs needed to install and handle Open Web Apps.

    var installApp = navigator.mozApps.install(manifestURL);
    // Successful install
    installApp.onsuccess = function(data) {
        console.log("Success, app installed!");
    // Install failed
    installApp.onerror = function() {
        console.log("Install failedn:" +;

    Network Information API

    Used to get information about network connectivity.

    var connection = window.navigator.mozConnection,
        online = connection.bandwidth,
        metered = connection.metered;
    // online can return:
        0 when offline
        Infinity when the bandwidth isn't known
        Estimation of MB/s
    // metered implies if the connection is being metered,
       meaning limited in some way from the ISP

    Alarm API

    Making it possible to set alarms.

    request = navigator.mozAlarms.add(
        new Date("May 15, 2012 16:20:00"),
            mydata: "my event"

    Web Activities

    Through Web Activities you can specify intents on what kind of action you want to do, or that your app can handle.

    var pick = new MozActivity({
         name: "pick",
         data: {
             type: ["image/png", "image/jpg", "image/jpeg"]}
    pick.onsuccess = function () {var img = document.createElement("img");
        img.src = window.URL.createObjectURL(this.result.blob);

    I’ve covered Web Activities in more detail in another blog post here.

    Push Notifications API

    A way for web sites to send messages to suers when aren’t on their web site. API is in a draft, not implemented yet. More can be read in the PushAPI documentation.

    function getPushURL() {
        var push = navigator.push ||
                    navigator.mozPush ||
        // Ask the user to allow notifications
        var request = push.requestURL(watoken, PbK);
        request.onsuccess = function () {
            var url = request.result.url;
            console.log('Push URL: ' + url);

    WebFM API

    Implementing a FM Radio in the web layer.

    var fmRadio = || navigator.mozFMRadio || navigator.mozFM;
    fmRadio.frequency = 106.7;


    Used to enable in-app payments, through JSON Web Token (JWT).

    var request = navigator.mozPay(JWTs);
    request.onsuccess = function () {
        // Money!


    Structured client-side storage with high performance search support. Covered in detail in Using IndexedDB and Storing images and files in IndexedDB.

    // Create/open database
    var request ="elephantFiles", 1),
         createObjectStore = function (dataBase) {
            console.log("Creating objectStore")
    request.onsuccess = function (event) {
        console.log("Success creating/accessing IndexedDB database");
        db = request.result;
        db.onerror = function (event) {
            console.log("Error creating/accessing IndexedDB database");
    // Needed for creating database/upgrading to a new version
    request.onupgradeneeded = function (event) {

    Ambient light sensor

    Detecting the level of ambient light, to be able to serve different versions depending on the environment the user currently is in.

    window.addEventListener("devicelight", function (event) {/* The level of the ambient light in lux

           A lux value for "dim" typically begin below 50,
           and a value for "bright" begin above 10000
    window.addEventListener("lightlevel", function (event) {
        // Possible values: "normal", "bright", "dim"

    Proximity sensor

    Getting an indication of how close the device is to another object.

    window.addEventListener("deviceproximity", function (event) {// Current device proximity, in centimeters



        // The maximum sensing distance the sensor is 

        // able to report, in centimeters



        // The minimum sensing distance the sensor is 

        // able to report, in centimeters



    Being able to show notifications to the user.

    var notification = navigator.mozNotification;
        "See this",
        "This is a notification"
    // You could send an optional third parameter,
    // which would be the URL to an icon

    Privileged APIs

    These APIs can only be used in a privileged app.

    The complete list of privileged APIs is:

    • Device Storage API
    • Browser API
    • TCP Socket API
    • Contacts API
    • systemXHR

    Device Storage API

    Accessing files stored on the device.

    var storage = navigator.getDeviceStorage("videos"),

        cursor = storage.enumerate();


    cursor.onerror = function() {
        console.error("Error in DeviceStorage.enumerate()",;};

cursor.onsuccess = function() {if (!cursor.result)return;}
    var file = cursor.result;
        // If this isn't a video, skip it

        if (file.type.substring(0, 6) !== "video/") {

        // If it isn't playable, skip it

        var testplayer = document.createElement("video");if (!testplayer.canPlayType(file.type)) {

        // Show file

    Browser API

    Implementing your own web browser, completely with web technologies. Described more in BrowserAPI.

    iframe.addEventListener("mozbrowserlocationchange", function(e) {
    iframe.addEventListener("mozbrowsersecuritychange", function(e) {
        // "secure", "insecure", or "broken".  "broken" indicates mixed content.
    iframe.addEventListener("mozbrowsercontextmenu", function(e) {
        // Show context menu

    TCP Socket API

    A low-level TCP socket API, that will also include SSL support.

    var TCPSocket =
            useSSL: crypto,
            binaryType: "arraybuffer"

    Contacts API

    Accessing contacts on the device – adding, reading or modifying.

    var contact = new mozContact();
contact.init({name: "Tom"});

    var request =;
request.onsuccess = function() {

    request.onerror = function() {


    Making it possible to allow cross-domain XMLHTTPRequests. Specify in the manifest file in the permissions part that you will want to access it – "systemXHR":{} – and then just do the request.

    var xhr = new XMLHttpRequest();"GET", anyURL, true);

    Certified APIs

    The certified APIs are only available to the system itself/pre-installed apps. In the fcase of Firefox OS, this means only Mozilla.

    The complete list of certified APIs is:

    • WebTelephony
    • WebSMS
    • Idle API
    • Settings API
    • Power Management API
    • Mobile Connection API
    • WiFi Information API
    • WebBluetooth
    • Permissions API
    • Network Stats API
    • Camera API
    • Time/Clock API
    • Attention screen
    • Voicemail

    I’ll list a few of them here, in case you are interested in testing or contributing to Gaia, the UI of Firefox OS.


    For placing, receiving and dealing with calls.

    // Telephony object
    var tel = navigator.mozTelephony;
    // Check if the phone is muted (read/write property)
    // Check if the speaker is enabled (read/write property)
    // Place a call
    var call = tel.dial("123456789");
    // Events for that call
    call.onstatechange = function (event) {
            Possible values for state:
            "dialing", "ringing", "busy", "connecting", "connected",
            "disconnecting", "disconnected", "incoming"
    // Above options as direct events
    call.onconnected = function () {
        // Call was connected
    call.ondisconnected = function () {
        // Call was disconnected
    // Receiving a call
    tel.onincoming = function (event) {
        var incomingCall =;
        // Get the number of the incoming call
        // Answer the call
    // Disconnect a call


    For sending and receiving SMS messages.

    // SMS object
    var sms = navigator.mozSMS;
    // Send a message
    sms.send("123456789", "Hello world!");
    // Receive a message
    sms.onreceived = function (event) {
        // Read message


    To be able to access certain APIs, in an Open Web App context, you need to specify permissions for the APIs you want to access in the manifest file.

    "permissions": {
        "contacts": {
            "description": "Required for autocompletion in the share screen",
            "access": "readcreate"
        "alarms": {
            "description": "Required to schedule notifications"

    For all APIs that are considered privileged or certified, this applies.

    For regular APIs, only geolocation and notification are affected (and for geolocation, in a regular web browser context, the user will be presented with a dialog to approve/decline).

    Additionally, the Camera API is restricted as a certified API at this time, but the long-term goal is to make it available to all apps. At the moment, if you want to access the camera, do it through Web Activities.

    Please take a look at the list of all APIs requiring permissions.

    Platform support

    As I’m sure you understand, a number of the WebAPIs are going through a process filled with progress, iterations and improvements. Some of the APIs above will work as described and intended, while others might not at this time.

    To be able to follow the current implementation state, please look at the list of APIs planned for the initial release of Firefox OS.

    The three columns imply:

    • D = Desktop support in Firefox
    • A = Android support in Firefox
    • B = Firefox OS support
    • Green = Implemented and enabled
    • Orange = Implemented, but needs to explicitly be turned on
    • Red = Not implemented
    • Blue = Only available as a Certified API
    • Grey = Not planned for this platform

    APIs planned for the future

    While not being worked on at the moment, I’d like to list APIs that are planned for the future. To show you our intent, and things we want to implement and support, and also to show in which direction we are moving.

    • Resource lock API
    • UDP Datagram Socket API
    • Peer to Peer API
    • WebNFC
    • WebUSB
    • HTTP-cache API
    • Calendar API
    • Spellcheck API
    • LogAPI
    • Keyboard/IME API
    • WebRTC
    • FileHandle API
    • Sync API

    Testing out these new APIs

    Feel free to just copy and paste code from this blog post to test the API(s) that you are interested in. I’ve also implemented support for some of them in the Firefox OS Boilerplate App, available in the webapp.js file (and I plan to add more in the future).

  8. ArchiveAPI – read out archive file contents + Introducing Bleeding Edge

    Working with files on the web has been a challenge for a long time, and when things like various File APIs have surfaced, it has made me really happy! Now on to the latest edition: ArchiveAPI, giving the ability to work with archive files.

    Introducing Bleeding Edge

    Before I start talking about the ArchiveAPI, I wanted to introduce the new Bleeding Edge category here on Mozilla Hacks. What this means is that we cover technologies/features/APIs that haven’t been released in an official version of Firefox, or any other web browser, yet. It covers things that, in most cases, have their first initial implementation in Firefox Nightly or Firefox Aurora.

    The goal is to have these features shipped, but given feedback from you, dear developers, or any other findings during this phase might result in changes to them before they are released.

    So, feel more than welcome to try them out! Either you have a headstart on knowing what’s coming, or you have the possibility of affecting the future of features for developers on the web. Win-win! :-)

    What it is

    As part of our WebAPI initiative at Mozilla to make the web an even more powerful platform, I was lucky to talk to Andrea Marchesini, the Lead Developer of the ArchiveAPI. Basically, it allows you to read the content of archive files, e.g. ZIP files, directly in web browsers.

    Basically, we have an ArchiveReader object and when it successfully manages to read the contents of an archive file, we can iterate over them, read out file data, show previews of each file’s content etc.

    var archiveFile = new ArchiveReader(archiveFileReference),
        fileNames = archiveFile.getFilenames();

    When you trigger an action/method on this file, like getFilenames, you will have two handlers: onsuccess and onerror. Like this:

    fileNames.onerror = function () {
        console.log("Error reading filenames");
    fileNames.onsuccess = function (request) {
        // Get list of files in the archive
        var result = this.result;
        // Iterate over those files
        for (var i=0, l=result.length; i&lt;l; i++) {
            file = archiveFile.getFile(result[i]);
            file.onerror = function () {
                console.log("Error accessing file");
            file.onsuccess = function () {
                // Read out data for that file, such as name, type and size
                var currentFile = this.result;


    I’ve put together an ArchiveAPI demo where you can upload an archive file and for any of the image or text files within that archive, it will directly generate a preview in the web page. The code is available on GitHub, as part of our mozhacks GitHub repositiory.

    Note: currently this demo only works in Firefox Aurora and Firefox Nightly.

    I’ve also put together a screencast of this demo at YouTube:

    (If you’ve opted in to HTML5 video on YouTube you will get that, otherwise it will fallback to Flash)


    I hope you find this interesting, and one more step forward for the web as a platform! Please let us know what you think in a comment here.

    Additionally, there’s a poll/questionnaire you can take with regards to the asynchronous nature of ArchiveAPI. It’s available in Feedback on potential ArchiveReader APIs.