This informative Working Group Note defines a service discovery and light-weight RPC mechanism for web apps called Web Intents.
This document defines DOM interfaces and markup used by client and service pages to create, receive, and reply to Web Intents messages, and the procedures the User Agent carries out to facilitate that process.
Changes since the previous version include clarifications, corrections, and updates to the document (diff).
The email address provided for feedback is that of the Task Force, where all feedback is welcome.
Web Intents enable rich integration between web applications. Increasingly, services available on the web have a need to pass rich data back and forth as they do their jobs. Web Intents facilitate this interchange while maintaining the kind of loose coupling and open architecture that has proven so advantageous for the web. They exist purely client-side, mediated through the User Agent, allowing the user a great degree of control over the security and privacy of the exchanged data.
An Intent is a user-initiated action delegated to be performed by a service. It consists of an "action" string which tells the service what kind of activity the user expects to be performed (e.g. "share" or "edit"), a "type" string which specifies the data payload the service should expect, and the data payload itself.
The lifecycle of an Intent is that first, a client requests an Intent be handled. This Intent data is then passed to the User Agent, which allows the user to select which of potentially many possible services to use. Then the service is passed the Intent data and is provided a UI by the User Agent in which to perform the action specified in the Intent. Finally, the service may also return data as output back to the client.
Web Intents provides a declarative syntax that allows services to list the Intents they handle. Using this method, services mark up what actions they can handle and which data types they expect.
Suppose there is a photo hosting application. This application allows a user to select images to be shared, edit those images, and then share them with friends. The application is built around making photos available to users, but has no built-in editor or sharing interface. But beside each photo, it can place an Edit button, with this kind of accompanying code:
document.getElementById('edit-photo').addEventListener("click", function() { var intent = new Intent({"action":"http://webintents.org/edit", "type":"image/jpeg", "data":getImageDataBlob(...)}); navigator.startActivity(intent, imageEdited); }, false); function imageEdited(data) { document.getElementById('image').src = data; }
This code delegates image editing to third-party applications which can consume images prepared as blobs, and produce results in the same format. For instance, one such editor might be a meme-maker—an application allowing the user to place humorous messages on pictures they take.
Now that a picture has been edited in the selected service, and meme text added, the user undoubtedly wants to share the result with friends. Again, the photo hosting application may not have built-in sharing capabilities, but by adding a Share button near images, and with this kind of accompanying code, it can accomplish this integration:
document.getElementById('share-photo').addEventListener("click", function() { var intent = new Intent({"action":"http://webintents.org/share", "type":"text/uri-list", "data":getPublicURIForImage(...)}); navigator.startActivity(intent); }, false);
This code delegates sharing functionality to an existing services chosen
by the user which are capable of sharing urls.
(getPublicURIForImage()
is a
marker for an application-specific piece of functionality getting the URL
to be shared) So a social networking site
selected by the user might produce a status update with a thumbnail of the
image. A blogging site might provide a UI allowing the user to post the picture.
Note that with this integration, other more high-minded services can be selected by the user as well. Instead of using the service to add funny captions, the user might use a sophisticated photo editing application to adjust exposure, remove red-eye, or do any number of other transformations on the image. The user can have many such tools registered, and choose any of that set to use for any given image editing task. The photo hosting application isn't controlling which application the user chooses; it is loosely coupled with such applications by providing the data necessary for them to carry out their task, and controls allowing the user to launch these activities on the data.
In this way, an Intent is like the dual of a hyperlink. With a hyperlink, the source page specifies the exact URL to be navigated to. With an Intent, the source page specifies the nature of the task to be done, and the user can select any of a number of applications to be used to complete the task.
On the service side, the page needs to register itself as a Web Intents service, and handle the incoming intent data, possibly producing a response. That is done like this:
<html> <head> <title>Image Meme Editor</title> </head> <body> <intent action="http://webintents.org/edit" type="text/uri-list image/*"></intent> <script> window.addEventListener("load", function() { if (window.intent) { setImageContentURI(window.intent.data); } }, false); document.getElementById('save-button').addEventListener("click", function() { window.intent.postResult(getImageDataURI(...)); }, false); </script>
The assumed pieces here (on both client and service pages) are functions which deal with the application's image display, for instance putting the image into a canvas and taking it back out again as a data URI. Or producing the public URI of the image on the site.
The normative parts of this specification are the API Description and the User Agent Behavior section. All other parts are informative.
An Intent is an action with accompanying data, which is to be performed by a Service of the user's choosing.
A web page which creates an Intent and invokes the User Agent with it is a Client. The User Agent may also allow non-web-page sources invoke Intents. For instance, the User Agent may have UI which invokes Intents delivery, or may register for external OS hooks which trigger Intents.
A web page which can handle an Intent is a Service, possibly returning a piece of data to the calling Client page. (Note that the User Agent may have ways to deliver Intents to Services which are not web pages as well. These may be extension APIs, plug-in helpers, external OS handlers, etc.)
Registration is how a web page page informs the User Agent that it (or another same-origin Service page) is capable of handling Intents.
Invocation refers to the API by which a Client page dispatches an Intent for handling.
Selection is the mechanism in which the User Agent decides which Service will handle a particular Intent.
Delivery is the means by which the User Agent passes an Intent to a Service page for handling.
Response is the means in which the Service can respond to an Intent by passing data back through the User Agent to the Client page.
The steps in a particular Intent invocation are asynchronous. The Service receives the Intent delivery and prepares its Response in a separate execution context. That Response is then returned to the calling Client in an asynchronous callback.
This object can be used in the object-literal constructor of the Intent object. When using the object literal constructor, the action and type fields are required; all others are optional.
The Intent object models a particular task which can be requested to be handled by Services. A Client page may invoke multiple Intents simultaneously. Specific Intent objects are immutable once created.
transferList
of the constructor during invocation will be
delivered to the service page in the ports
attribute. See
[[!POSTMSG]]data
payload argument, as per
[[!HTML5]] [[!POSTMSG]]
Notes on the intent object: The transferList parameter is not available
post-creation. It becomes an internal implementation detail directing the
User Agent to interpret some fields of the data
argument as Transferable. The
data
and transferList
arguments MUST be implemented following the W3C
Web Messaging spec [[!POSTMSG]].
The User Agent MUST perform the structured clone algorithm on creation of the Intent object.
The client invokes an intent by constructing an Intent object as above and calling
the navigator.startActivity
function on it. The callbacks
passed to this method are invoked when the intent has been handled by the service.
The User Agent will mediate the Service selection by enumerating the list of
registered Services that match the requested Intent action and type.
The user is then able to select which Service should handle the Intent.
null
), or if
the method is invoked without being the result of an explicit user gesture.
The invocation API is implemented by the window.navigator
object.
The callbacks passed to startActivity MUST provide these signatures:
data
passed will be the payload data from the structured
cloneable object passed to the postResult method of the delivered Intent.
ports
will be any ports in the payload, as resulting from the structured
clone algorithm with Transferables, as in the Web Messaging spec.
[[!POSTMSG]]
data
passed will be the payload data passed to the postFailure
method of the delivered Intent.
When the User Agent loads a Service page to handle an Intent invocation, it
will place a window.intent
object in the scope of the page.
This object will only be made available to Service pages when they are
loaded in the context of an intent invocation. Even if the same URL is
loaded in other situations, the User Agent MUST NOT make
Window
implement IntentProvider. Similarly, if
a Service page is registered, but the User Agent loads it and it does not
contain the declarative markup marking it as expecting to handle the Intent
the User Agent is delivering, the User Agent MUST NOT make
Window
implement IntentProvider.
The window.intent
object MUST be made available across
same-origin redirects of the service page. It MUST NOT be made available if
redirects cross an origin boundary.
So the following redirect sequence
will work: http://example.com/service to http://example.com/login back to
http://example.com/service. In this case, the window.intent
data would be made available to all three page loads.
This will also work: http://example.com/service to
http://example.com/newservice. In this sequence, the window.intent
data is available to both pages.
In this sequence, the window.intent
is only available to
example.com pages: http://example.com/service to http://login.example.com
and back to http://example.com/service. The intent data is not provided to
http://login.example.com
The window.intent
object MUST be made available to a page on
the same-origin as the originally-delivered page if the user initiates a
navigation on the browsing context in which that Service page is displayed,
AND the new page has declarative syntax marking it as a handler for the
Intent type the User Agent is delivering.
In other words, in the browsing context in which the Intent is originally delivered, the intent data MUST be made available to pages in a redirect or navigation sequence when they are in the same origin as that to which it was originally delivered (and have the enabling markup), but MUST NOT be made available to any other pages. This allows Service pages to delegate handling, to redirect to login screens, and so forth, but does not make the Intent data available to any such pages encountered which are not in the same origin.
Multiple invocation by code in the service page MUST throw a Javascript exception. The User Agent MUST NOT allow a particular Intent to be replied to multiple times.
Web pages declaratively mark themselves (or other same-origin Service pages)
as providing handling functionality for particular intent actions and types
using the <intent>
tag.
A User Agent MUST NOT deliver an Intent to a web app service page which
does not include markup describing what intents it can handle which matches
the intent being delivered (See the section on Matching action and type for
delivery).
action
attribute is missing, the intent Service is
assumed to handle display of the provided type(s) in the type
attributes.href
attribute
is missing, the service URI will be set to the URI in which the tag is
found.title
attribute is missing, the User Agent SHOULD
use the title of the registered Service page as the service title.disposition
attribute allows a service to choose which
context to be opened in. The User Agent MUST NOT allow the Client page any
ability to change the disposition. The window
disposition means
that the service is opened in a new tab or window context. The
inline
disposition means that the User Agent SHOULD open the
service in a context directly related to the client page context in an
overlappable way. The User Agent MUST NOT allow this UI surface to be
under the control of the client page.
This section should not be construed as limiting the ability of the User
Agent to manage registration of non-web services. That is, the User Agent
may handle intent invocations locally, using extensions, or with
third-party system services. This section solely governs how web-app service pages
register and unregister with the User Agent with the
<intent>
tag.
The User Agent MUST NOT obey any registration markup which is not
same-origin. That is, a page may only register href
attributes
for other service handlers on its same origin. A page may register itself
as a Service handler, by leaving the href
attribute empty.
For cross-page registration, when the href
attribute points to a different
resource, the User Agent SHOULD interpret intent registrations additively.
That is, an intent descriptor from the tag would be added to the registry
if it is not present (if the user approves the addition).
The User Agent SHOULD treat any registration markup which has both
action
and type
attributes missing as if the
markup specified no intent capability on the href
page. That is, a page may
unregister itself implicitly by removing all intent tags, or explicitly
by keeping the tag present, but without action
or
type
attributes. Such explicit unregistration SHOULD
be honored for any tag with a same-origin href
attribute.
The intent tags on the service handler page itself SHOULD be interpreted by the User Agent as authoritative. That is, if the User Agent loads a service page, and sees that its intent descriptors do not match the set currently registered for that page, it would replace the currently-registered set with the set discovered on the more current load of the page.
If a registered service page is retrieved and has a non-20x error code [[!HTTP11]], the User Agent SHOULD take the following actions:
30x: redirect to the indicated page. If the page is on-domain, and has intent markup, the intent will be made available to the redirect page. If the redirect is permanent (301), the User Agent MAY update its service registration records to reflect that.
4xx: indicate to the user that the page cannot be loaded, along with any remediation capabilities (i.e. authentication for 403 or payments for 402). In the case of error 410, the User Agent SHOULD unregister the handler from its internal registry.
50x: indicate to the user that the page cannot be loaded.
If the desired registered service page cannot be loaded, the User Agent SHOULD display UI allowing the user to select another service.
When the User Agent loads a page with registration markup, it SHOULD allow the user to configure that page as a web intents service. The details of this process is left up to the User Agent. The model is that the page advises of the ability to handle intents, and the User Agent may remember that. The User Agent MUST NOT deliver an intent to a Service discovered in this way before the user has made a specific action allowing it.
The User Agent MUST NOT allow web pages the ability to discover passively which services the user has configured to handle particular intents, or any intents, whether by enumeration or exact query. There may be mechanisms for the user to actively grant this information to web pages, but it MUST NOT be made available passively.
The User Agent MAY provide additional mechanisms for web intents service registration. For example, by external applications, through a separate API, as a result of a permissions bundle in a downloaded web application, or pre-bundled. (TODO: add example of a local network service)
The User Agent MAY act as a Client or a Service. For example, the User Agent may implement particular affordances which directly launch Intents that may be handled by registered Services, or present UI allowing its own functionality to be used alongside other registered Services to handle Intents. For instance, User Agents MAY also dispatch intents directly based on data-specific controls derived from microdata in pages, or based on other User Agent-level features.
For intents invoked by client web applications, the User Agent MUST require that such invocations be in the context of a user gesture. User Agents MAY also dispatch intents invoked through other mechanisms. For example, hardware events (i.e. plugging in a USB storage device) or software events (i.e. downloading a file).
When a client page invokes an intent, the User Agent dispatches it to a chosen service. The details of this process are left up to the User Agent. The User Agent may dispatch intents to web application service pages, helper applications, proxy them through connections to other hardware, etc. In general, though, the User Agent MUST provide a way for the user to configure which intents are delivered to which services. This process SHOULD be configurable on a per-invocation basis. Defaulting rules, as long as they are configurable by the user, are expected to result in the User Agent not presenting full UI controls on every invocation.
When the User Agent delivers an intent payload to a web application, it
MUST make the window.intent
object available as the document
is loaded and parsed, so that scripts on the page may process the intent
data as they load. User agents MUST NOT make available a window.intent
object in the scope of pages which do not have registration metadata
declaring themselves as intent handlers. This means that any use of
window.intent
in pages which do not explicitly declare
themselves as web intents handlers MUST NOT be overwritten by the User
Agent. It also means that Service pages cannot access
window.intent
in scripts which occur before the page parses
the intents registration markup. If such scripts are simply declaring
functions to be called later, that will work, but scripts which run before
the registration markup is parsed won't find window.intent
made available, even though it may be made available later in the page load,
and so are likely broken.
When a new context is opened for the service page, the User Agent MUST
connect the postResult
and postFailure
methods
of the window.intent
object so that they return their
serializable payloads to the registered handlers the User Agent received
in the invoking navigator.startActivity
call. If the user
closes the service page before it has responded, the User Agent MUST
invoke the onFailure
callback in the client page invocation,
if any. If the user cancels a service selection UI control the User Agent
displays in the course of dispatching an intent, the User Agent MUST
invoke the onFailure
callback in the client page invocation,
if any.
The User Agent SHOULD allow any serializable and/or Transferable object to be passed between client to service and back from service to client. This includes Blobs [[!BLOB]], MessagePorts, etc. The User Agent MAY inspect the payload of intents and present specialized UI corresponding to well-known intent types. As an example, the User Agent may present specialized messaging to the user indicating that an intent is of the "share" type, or that the Client is asking them to pick an image.
If the user has no services registered for a particular type of intent, the User Agent MAY display options from other sources of data about services it knows can handle that intent type so that the user can complete the activity.
The User Agent MUST NOT categorically prohibit dispatch of unknown intent types. This is not meant to prohibit the User Agent from performing filtering functions on intents, such as suppressing unwanted intent invocations, intents as used as an attack vector, and other mis-use.
When handling an Intent marked as explicit (that is, constructed with the object literal constructor with a non-empty service field), the expected User Agent behavior is that if this "service" attribute is present, it SHOULD NOT display a service selection mechanism to the user. Instead, the service url SHOULD be loaded directly to handle the intent. (This is not a hard restriction. The User Agent MAY provide a way for the user to intercept even an explicit invocation.)
During delivery, all restrictions are still in place. That is, the User
Agent MUST follow the above requirements on placing the
window.intent
object in the scope of the page, and respect
any declarative metadata in that service page. If the user agent needs
information about the service (i.e. disposition, title, etc) for use
in preparing its UI, it MAY load the service URL and examine the page
for any declarative metadata.
The User Agent MAY ask the user if they wish to install this service, just like for any other visit of the page.
When an Intent is delivered, the User Agent must verify that the Service to which the intent is to be delivered (either from an explicit invocation or from the result of a user selection) has a registration record supporting the action and type of the Intent being delivered by following these steps:
If the user has no persistent information about a qualifying service for a particular intent registered with the User Agent, the User Agent SHOULD present the user with the option to select from the default services proposed by the client at invocation (from the suggestions parameter).
If the user agent needs information about the all or any of the suggested services (i.e. disposition, title, icon, etc) for use in preparing its UI, it MAY load the suggested default service URL(s) and examine the page(s) for the <intent> tag, reading off such information, or load the favicon for the site(s). The User Agent MAY ask the user if they wish to install all or any of the suggested services, just as for any other visit of those pages.
The User Agent MUST follow the matching algorithm of the "Matching action and type for delivery" section before delivering the Intent to a suggested service, just as for any Intent delivery.
Web Intents should be useful to enable users to share content as they encounter it on web pages. Whether by implicit controls made available by the User Agent or explicit controls placed in web pages, Web Intents should handle the use case of a user wishing to share a page as a whole, or particular content on the page. The user should be able to select the sharing application of choice to accomplish this task.
Local web apps should be able to invoke and handle intents.
Web Intents invocations are modeled on RPC, but there are times when a persistent connection is desired. There are a few different methods that Web Intents should support for this. One is returning URIs which can be loaded by clients in an iframe and then messaged using other web platform features. Another is returning a defaulting token which the client can then use to target other intents directly at a known target. A third is returning a MessagePort to the client which can be used for subsequent communication.
In these cases, Web Intents is acting as a way for the user to attach a particular client page to a persistently-available service. It is up to the particular types of intents to describe exactly how this should work. i.e. whether the connection is permanent or temporary, whether tokens are user-consumable or opaque.
It should be possible for intents to be routed to external helper applications. For instance, a locally available photo editing tool could be configured to interact with the browser to handle an image edit intent. Or the browser could discover home networking equipment on the local network and make it available for particular types of intents.
It should be possible to translate a few existing features to use Web Intents, thus putting web applications on the same footing as local resources. For instance, it should be possible for the User Agent to translate file selection controls to intents such that the user can choose to upload a file from a cloud storage locker as well as from local disk. In these cases, the User Agent may supply built-in intent handlers corresponding to existing functionality.
Another use case is allowing web applications to function as plug-ins. For example, a link returning a resource of a type which the user agent doesn't know how to display can be translated into an intent which allows the user to configure a web application capable of reading that resource type and viewing it. This would let web apps function as plug-ins.
It is expected that many services for Web Intents will be ones the user has an account with. The service should be able to use standard login mechanisms in the context the User Agent places them within to perform authentication. That is, the service page handling an intent should be loaded with the same cookie jar and access to localStorage, etc. with which it runs in a normal browsing context. Intent data should be persisted by the User Agent across login redirects.
The user needs to have confidence that the Service will use the data associated with the action for the purpose intended and not share or retain the data inappropriately [[WEBAPP-PRIVACY-BESTPRACTICES]]. For this reason it is important that the user have control over Intents, in particular the selection mechanism which determines which Service will handle a particular Intent. This offers the possibility of user decision and control related to the choice of Service, allowing the user to take into account expectations regarding the Service, including Service policies related to retention and secondary use. This relates to the privacy principles of control and consent [[DAP-PRIVACY-REQS]]. For this reason a user should be made aware of explicit intents and be able to view and change them; implementations should be encouraged to offer this functionality. The minimum data necessary for a Service should be included as Intent parameters, corresponding to the privacy principle of minimization [[DAP-PRIVACY-REQS]].
Many thanks to Robin Berjon for making our lives so much easier with his cool tool.
See also webintents.org for more examples and a sample Javascript implementation of Web Intents.