Teaching the Web new Tricks

Web Tasks

When we introduced our support for Web Tiles we explained that they are automatically subject to a restrictive CSP in order to prevent data leaks to 3rd parties. That make Web Tiles safe to use what are considered "dangerous" APIs, eg. those accessing hardware APIs or other privacy sensitive data sets on your devices like your address book.

That makes Web Tiles an ideal build block for composable, self contained components that can fulfill tasks for a regular page even if they require evelated privileges.

What we are aiming at is in fact a generalization of what is already done by some Web features: when you use an <input type="file"> element, the page won't have access to the full filesystem: this is delegated to the browser to allow the user to pick the data to return.

On the Shoulders...

The principles of Web Tasks are not really a new thing. Several projects have explored the space already, including:

They all share similar requirements:

The details are not that important. In our task implementation, we mostly used the MozActivity model with a few tweaks, as it seems to be flexible enough.

Web Task registration

We support two ways to register tasks:

Calling and responding to tasks requests

Triggering a task is simple. We'll show a demo of an image editor and all it takes for the caller is:

const result = await navigator.requestTask("edit-image", {
  image: currentBlob,
  type: "image/png",
});

This will match the task registered by the image editor:

{
  "name": "edit-image",
  "title": "Image Editor",
  "description": "Annotate and edit images",
  "href": "beaver://imageeditor/index.html",
  "filters": {
    "type": ["image/png", "image/jpeg", "image/webp"]
  },
  "display": "window",
  "icon": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0i...+PC9zdmc+"
}

Once the user has chosen a task provider, the page is opened and the provider can access the data and send a response with:

const task = await window.acceptTask();
console.log(`Will process task ${task.name}`);
const blob = task.data.image;
...
task.port.postMessage(editedBlob);

The provider receives an object with the task name and data as set in requestTask, and a message port. The result can be sent back by a regular call to postMessage on the message port.

The system itself takes care of rejecting the acceptTask() promise in various situations like the provider being closed before sending a response, or if the user doesn't pick a provider at all.

Cross-devices Web Tasks

Building on the existing support for communication among paired devices, we can enable cross device tasks. This is achieved by sending to other peers local registrations and bridging message ports between the devices. That makes it user friendly to leverage multiple devices and use the one with the most appropriate capabilities.

Web Tasks in action

Here's a screencast showing how we can use our image editing provider. In this case, we pick a provider on the laptop since it's a better experience than editing on the smaller phone screen!

Updated Apr 11 2026