This specification defines an API for sharing text, links and other content to an arbitrary destination of the user's choice.

The available share targets are not specified here; they are provided by the user agent. They could, for example, be apps, websites or contacts.

This is an early draft of the Web Share spec.

Usage Examples

This example shows a basic share operation. In response to a button click, this JavaScript code shares the current page's URL.

        shareButton.addEventListener("click", async () => {
          try {
            await navigator.share({ title: "Example Page", url: "" });
            console.log("Data was shared successfully");
          } catch (err) {
            console.error("Share failed:", err.message);
          }
        });
      

Note that a url of '' refers to the current page URL, just as it would in a link. Any other absolute or relative URL can also be used.

In response to this call to navigator.share(), the user agent would display a picker or chooser dialog, allowing the user to select a target to share this title and the page URL to.

Sharing images is also supported, for example, from a <canvas> element.

        shareCanvasButton.addEventListener('click', () => {
          const canvas = document.querySelector('#imageCanvas');
          navigator.share({image: canvas})
              .then(console.log('Share image successful'));
        });
      

You can also share an <img> or <video> element (in the latter case, it shares an image of the current video frame), an ImageData object containing raw pixel data, or a Blob containing an encoded image file.

API definition

Navigator interface

The Navigator interface is defined in [[!HTML]].

          partial interface Navigator {
            [SecureContext] Promise<void> share(optional ShareData data);
          };
        
Need a mechanism for feature-detecting image-sharing support. There is an open discussion about how to provide feature-detection for dictionary members.
The data argument is marked as "optional", but it is effectively required; share() will return a rejected promise with a TypeError if called with no arguments. WebIDL mandates that it be optional because the dictionary members are all optional. See WebIDL Issue #130.

User agents that do not support sharing SHOULD NOT expose share() on the Navigator interface.

The above statement is designed to permit feature detection. If share() is present, there is a reasonable expectation that it will work and present the user with at least one share target. Clients can use the presence or absence of this method to determine whether to show UI that triggers its use.

share() method

When the share() method is called with argument data, run the following steps:

  1. Let p be a new promise.
  2. If none of data's members title, text, url, or image are present, reject p with TypeError, and abort these steps.
  3. Set data to a copy of data.
  4. If data's url member is present:
    1. Let base be the this value's relevant settings object's API base URL.
    2. Let url be the result of running the URL parser on data's url, with base, and no encoding override.
    3. If url is failure, reject p with TypeError, and abort these steps.
    4. Set data's url member to the result of running the URL serializer on url.
  5. If data's image member is present:
    1. If data's image is a ShareImageData, let image be data's image.source and type be data's image.type (or, if it is not present, undefined). Otherwise, let image be data's image and type be undefined.
    2. Set data's image field to the result of converting image to a Blob with type. If this throws an exception, reject p with the exception, and abort these steps.
  6. If the method call was not triggered by user activation, reject p with a "NotAllowedError" DOMException, and abort these steps.
  7. In parallel:
    1. If there are no share targets available, reject p with an "AbortError" DOMException, and abort these steps.
    2. Present the user with a choice of one or more share targets, selected at the user agent's discretion. The user MUST be given the option to cancel rather than choosing any of the share targets. Wait for the user's choice.
    3. If the user chose to cancel the share operation, reject p with an "AbortError" DOMException, and abort these steps.
    4. Activate the chosen share target, convert data to a format suitable for ingestion into the target, and transmit the converted data to the target. If an error occurs starting the target or transmitting the data, reject p with an "AbortError" DOMException, and abort these steps.
    5. Once the data has been successfully transmitted to the target, resolve p with undefined.
  8. Return p.

The user agent MUST NOT allow the website to learn which share targets are available, or the identity of the chosen target.

share() always shows some form of UI, to give the user a choice of application and get their approval to invoke and send data to a potentially native application (which carries a security risk). For this reason, user agents are prohibited from showing any kind of "always use this target in the future" option, or bypassing the UI if there is only a single share target.

ShareData dictionary

          dictionary ShareData {
            USVString title;
            USVString text;
            USVString url;
            (ImageBitmapSource or ShareImageData) image;
          };

          dictionary ShareImageData {
            required ImageBitmapSource source;
            DOMString type;
          };
        

The ShareData dictionary consists of several optional members:

title member
The title of the document being shared. May be ignored by the target.
text member
Arbitrary text that forms the body of the message being shared.
url member
A URL string referring to a resource being shared.
image member
An image file or source of pixel data, or a dictionary containing that as well as an explicit media type.

The ShareImageData dictionary allows a media type to be associated with an image:

source member
An image file or source of pixel data.
type member
The MIME type to convert the pixel data to. Not valid if source is a Blob (which already has a type).
These members are USVString (as opposed to DOMString) because they are not allowed to contain invalid UTF-16 surrogates. This means the user agent is free to re-encode them in any Unicode encoding (e.g., UTF-8).
The url member can contain a relative URL. In this case, it will be automatically resolved relative to the current page location, just like a href on an a element, before being given to the share target.
As an ImageBitmapSource, the image (or image.source) attribute can be supplied as many different types of object. A non-complete list of objects that can be passed here is:
  • HTMLImageElement, an <img> element object. This won't work if the image source is on a different origin with cross-origin restrictions.
  • HTMLVideoElement, a <video> element object. This shares the current frame of the video, not the video itself. This won't work if the video source is on a different origin with cross-origin restrictions.
  • HTMLCanvasElement, a <canvas> element object. This won't work if the canvas is not origin-clean.
  • ImageData, containing raw pixel data.
  • Blob, containing an already-encoded image file. As Blob already has a media type, this may not be used in conjunction with the image.type attribute. This is the most direct option as the user agent might directly transfer the bytes without re-encoding the image (or if it does, it will use the same file format).

Sharing images

To convert an image to a Blob with type (where image is an ImageBitmapSource and type is an optional string containing a MIME type), the user agent should behave as if the following algorithm were applied (it MAY perform a different set of actions, for example not actually creating an HTMLCanvasElement, as long as the results are the same):

  1. If image is a Blob:
    1. If type is not undefined, throw a TypeError.
    2. OPTIONAL: Return image.
    3. Set type to image's type attribute.
  2. If image is an HTMLCanvasElement, let canvas be image. Otherwise:
    1. Let canvas be a new HTMLCanvasElement with a CanvasRenderingContext2D called context.
    2. Call context's drawImage with image, 0 and 0.
  3. Return the result of calling canvas's toBlob with type.
The optional step in the above algorithm allows the user agent to decide whether to re-encode the blob's image as a new blob, or simply transmit the blob byte-for-byte as received. There are security considerations associated with this decision.
The algorithms used above require that the image source be origin-clean. If the image source is from a different origin that this site does not have permission to read, this will result in a SecurityError.
In the above algorithm creating a HTMLCanvasElement requires knowing the image size.
Converting HTMLCanvasElement to a Blob is asynchronous (requires queueing a task, callbacks, etc). Sort this out.
You should be able to specify a "quality" attribute in ShareImageData to control the serialization of the image to a file, as you can with HTMLCanvasElement.toBlob().

Share targets

A share target is the abstract concept of a destination that the user agent will transmit the share data to. What constitutes a share target is at the discretion of the user agent.

A share target might not be directly able to accept a ShareData (due to not having been written with this API in mind). However, it MUST have the ability to receive data that matches some or all of the concepts exposed in ShareData. To convert data to a format suitable for ingestion into the target, the user agent SHOULD map the members of ShareData onto equivalent concepts in the target. It MAY discard members if necessary. The meaning of each member of the payload is at the discretion of the share target.

Each share target MAY be made conditionally available depending on the ShareData payload delivered to the share() method.

Once a share target has been given the payload, the share is considered successful. If the target considers the data unacceptable or an error occurs, it can either recover gracefully, or show an error message to the end-user; it cannot rely on the sender to handle errors. In other words, the share() method is "fire and forget"; it does not wait for the target to approve or reject the payload.

Examples of share targets

The list of share targets can be populated from a variety of sources, depending on the user agent and host operating system. For example:

There is an attempt to standardize the registration of websites to receive share data for that final use case; see Web Share Target.

In some cases, the host operating system will provide a sharing or intent system similar to Web Share. In these cases, the user agent can simply forward the share data to the operating system and not talk directly to native applications.

Mapping the ShareData to the share target (or operating system)'s native format can be tricky as some platforms will not have an equivalent set of members. For example, if the target has a "text" member but not a "URL" member, one solution is to concatenate both the text and url members of ShareData and pass the result in the "text" member of the target.

Dependencies

The following are defined in [[!WEBIDL]]:

TypeError is defined by [[!ECMASCRIPT]].

Security and privacy considerations

Web Share enables data to be sent from websites to native applications. While this ability is not unique to Web Share, it does come with a number of potential security issues that can vary in severity (depending on the underlying platform).

Extensibility of this API

The Web Share API is designed to be extended in the future by way of new members added to the ShareData dictionary, to allow both sharing of new types of data and strings with new semantics (e.g. author).

This doesn't mean user agents can add whatever members they like. It means that new members can be added to the standard in the future.

The three members title, text, and url, are part of the base feature set, and implementations that provide navigator.share() need to accept all three. Any new members that are added in the future will be individually feature-detectable, to allow for backwards-compatibility with older implementations that don't recognize those members. These new members might also be added as optional "MAY" requirements.

The share() method returns a rejected promise with a TypeError if none of the specified members are present. The intention is that when a new member is added, it will also be added to this list of recognized members. This is for future-proofing implementations: if a web site written against a future version of this spec uses only new members (e.g., navigator.share({author: x})), it will be valid in future user agents, but a TypeError on user agents implementing an older version of the spec. Developers will be asked to feature-detect any new members they rely on, to avoid having errors surface in their program.

Editors of this spec will want to carefully consider the genericity of any new members being added, avoiding members that are closely associated with a particular service, user agent or operating system, in favour of members that can potentially be applied to a wide range of platforms and targets.

Acknowledgments

Thanks to the Web Intents team, who laid the groundwork for the web app interoperability use cases. In particular, Paul Kinlan, who did a lot of early advocacy for Web Share.