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.

Implementation status

The ability to share content is often dependent on the underlying operating system providing a "share" capability and also on OS UI conventions. For example, some OSs present a "share sheet", while others rely on an pop-up menu. Due to these aforementioned dependencies, there is ongoing work by implementers to bring the Web Share API to all OSs. This ongoing effort is reflected as failures in the implementation report, which is generated by running tests on a limited set of OSs. However, the Working Group is optimistic that the Web Share API will become more available across all OSs over time, and is already widely available on popular OSs across a range of devices.

Usage Examples

Sharing text and links

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 {{ShareData/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 a file

This example shows how to share a file. Note that the {{ShareData/files}} member is an array, allowing for multiple files to be shared.

        shareButton.addEventListener("click", async () => {
          const file = new File(data, "some.png", { type: "image/png" });
          try {
            await navigator.share({
              title: "Example File",
              files: [file]
            });
          } catch (err) {
            console.error("Share failed:", err.message);
          }
        });
      

Validating a share

Calling {{Navigator/canShare()}} method with a {{ShareData}} dictionary [=validate share data|validates=] the shared data. Unlike {{Navigator/share()}}, it can be called without [=transient activation=].

        const file = new File([], "some.png", { type: "image/png" });

        // Check if files are supported
        if (navigator.canShare({files: [file]})) {
          // Sharing a png file would probably be ok...
        }

        // Check if a URL is ok to share...
        if (navigator.canShare({ url: someURL })) {
          // The URL is valid and can probably be shared...
        }
      

Checking if members are supported

Because of how WebIDL dictionaries work, members passed to {{Navigator/share()}} that are unknown to the user agent are ignored. This can be a problem when sharing multiple members, but the user agent doesn't support sharing one of those members. To be sure that every member being passed is supported by the user agent, you can pass them to {{Navigator/canShare()}} individually to check if they are supported.

        const data = {
          title: "Example Page",
          url: "https://example.com",
          text: "This is a text to share",
          someFutureThing: "some future thing",
        };
        const allSupported = Object.entries(data).every(([key, value]) => {
          return navigator.canShare({ [key]: value });
        });
        if (allSupported) {
          await navigator.share(data);
        }
      

Alternatively, you can adjust application's UI to not show UI components for unsupported members.

        const data = {
          title: "Example Page",
          url: "https://example.com",
          text: "This is a text to share",
          someFutureThing: "some future thing",
        };

        // Things that are not supported...
        const unsupported = Object.entries(data).filter(([key, value]) => {
          return !navigator.canShare({ [key]: value });
        });
      

Enabling the API in third-party contexts

The [=policy-controlled feature/default allowlist=] of [=default allowlist/'self'=] makes Web Share API available by default only in first-party contexts.

Third-party can be allowed to use this API via an [^iframe^]'s [^iframe/allow^] attribute:

Alternatively, the API can be disabled in a first-party context by specifying an HTTP response header:

See the [[[permissions-policy]]] specification for more details and for how to control the permission policies on a per-origin basis.

API definition

Extensions to the `Navigator` interface

          partial interface Navigator {
            [SecureContext] Promise<undefined> share(optional ShareData data = {});
            [SecureContext] boolean canShare(optional ShareData data = {});
          };
        

Internal Slots

This API adds the following internal slot to the {{Navigator}} interface.

{{Promise}}? [[\sharePromise]]
The [=this=].{{Navigator/[[sharePromise]]}} is a promise that represents a user's current intent to share some data with a share target. It is initialized to `null`.

share() method

When the {{Navigator/share()}} method is called with argument |data:ShareData|, run the listed steps listed below while taking into consideration the following security implications.

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

The data passed to {{Navigator/share()}} might be used to exploit buffer overflow or other remote code execution vulnerabilities in the [=share target=] that receive shares. There is no general way to guard against this, but implementors will want to be aware that it is a possibility (particularly when sharing files).

[=Share targets=] that dereference a shared URL and forward that information on might inadvertently forward information that might be otherwise confidential. This can lead to unexpected information leakage if shares reference content that is only accessible by that application, the host on which it runs, or its network location.

Malicious sites might exploit share targets that leak information by providing URLs that ultimately resolve to local resources, including, but not limited to, "file:" URLs or local services that might otherwise be inaccessible. Even though this API limits shared URLS to a restricted set of [=sharable schemes=], use of redirects to other URLs or tweaks to DNS records for hosts in those URLs might be used to cause applications to acquire content.

To avoid being used in these attacks, share targets can consume the URL, retrieve the content, and process that information without sharing it. For instance, a photo editing application might retrieve an image that is "shared" with it. A share target can also share the URL without fetching any of the referenced content.

Share targets that fetch content for the purposes of offering a preview or for sharing content risk information leakage. Content that is previewed and authorized by a user might be safe to forward, however it is not always possible for a person to identify when information should be confidential, so forwarding any content presents a risk. In particular, the {{ShareData/title}} might be used by an attacker to trick a user into misinterpreting the nature of the content (see also [[[#a11y]]]).

As with any user of {{DOMException}}, implementors need to carefully consider what information is revealed in the error message when {{Navigator/share()}} is rejected. Even distinguishing between the case where no [=share targets=] are available and user cancellation could reveal information about which share targets are installed on the user's device.

  1. Let |global:Window| be [=this=]'s [=relevant global object=].
  2. Let |document:Document| be |global|'s [=associated `Document`=].
  3. If |document| is not [=Document/fully active=], return [=a promise rejected with=] an {{"InvalidStateError"}} {{DOMException}}.
  4. If |document| is not allowed to use "web-share", return [=a promise rejected with=] a {{"NotAllowedError"}} {{DOMException}}.
  5. If [=this=].{{Navigator/[[sharePromise]]}} is not `null`, return [=a promise rejected with=] an {{"InvalidStateError"}} {{DOMException}}.
  6. If |global| does not have [=transient activation=], return [=a promise rejected with=] a {{"NotAllowedError"}} {{DOMException}}.
  7. [=Consume user activation=] of |global|.
  8. Let |base:URL| be [=this=]'s relevant settings object's [=environment settings object/API base URL=].
  9. If [=validate share data=] with |data| and |base| returns false, then return [=a promise rejected with=] a {{TypeError}}.
  10. If |data|'s {{ShareData/url}} member is present:
    1. Let |url:URL| be the result of running the URL parser on |data|'s {{ShareData/url}} with |base|.
    2. Assert: |url| is {{URL}}.
    3. Set |data| to a copy of |data|, with its {{ShareData/url}} member set to the result of running the URL serializer on |url|.
  11. If a file type is being blocked due to security considerations, return [=a promise rejected with=] a {{"NotAllowedError"}} {{DOMException}}.
  12. Set [=this=].{{Navigator/[[sharePromise]]}} to be a new promise.
  13. Return [=this=].{{Navigator/[[sharePromise]]}} and in parallel:
    1. If there are no share targets available, [=queue a global task=] on the [=user interaction task source=] using |global| to:
      1. [=Reject=] [=this=].{{Navigator/[[sharePromise]]}} with an {{"AbortError"}} {{DOMException}}.
      2. Set [=this=].{{Navigator/[[sharePromise]]}} to `null`.
      3. Terminate this algorithm.
    2. Present the user with a choice of one more share targets and the ability abort the operation. This UI surface serves as a security confirmation, ensuring that websites cannot silently send data to native applications. The user agent SHOULD show intermediary UI through which the user can verify the shared content (if the OS-level UI does not provide this functionality).
    3. Wait for the user's choice.
    4. If the user chose to abort the share operation, [=queue a global task=] on the [=user interaction task source=] using |global| to:
      1. [=Reject=] [=this=].{{Navigator/[[sharePromise]]}} with an {{"AbortError"}} {{DOMException}},
      2. Set [=this=].{{Navigator/[[sharePromise]]}} to `null`.
      3. Terminate this algorithm.
    5. Activate the chosen share target, convert |data| to a format suitable for ingestion into the target, and transmit the converted data to the target.
    6. If an error occurs starting the target or transmitting the data, [=queue a global task=] on the [=user interaction task source=] using |global| to:
      1. [=Reject=] [=this=].{{Navigator/[[sharePromise]]}} with an {{"DataError"}} {{DOMException}}.
      2. Set [=this=].{{Navigator/[[sharePromise]]}} to `null`.
      3. Terminate this algorithm.
    7. Once the data has either been successfully transmitted to the [=share target=], or successfully transmitted to the OS (if the transmission to the [=share target=] cannot be confirmed), [=queue a global task=] on the [=user interaction task source=] using |global| to:
      1. [=Resolve=] [=this=].{{Navigator/[[sharePromise]]}} with `undefined`.
      2. Set [=this=].{{Navigator/[[sharePromise]]}} to `null`.

`canShare(data)` method

When the canShare() method is called with argument {{ShareData}} |data:ShareData|, run the following steps:

  1. Let |document:Document| be the [=this=]'s [=relevant global object=]'s [=associated `Document`=].
  2. If |document| is not [=Document/fully active=], return false.
  3. If |document| is not allowed to use "web-share", return false.
  4. Return the result of [=validate share data=] with |data| and [=this=]'s [=relevant settings object=]'s [=environment settings object/API base URL=].

Validate share data

A sharable scheme is any of the following [=URL=] [=URL/schemes=]:

  • `http`
  • `https`
  • Any [=safelisted scheme=] that the user agent supports for the purpose of sharing.

To validate share data with |data:ShareData| and |base:URL|, run the following steps:

  1. If none of |data|'s members {{ShareData/title}}, {{ShareData/text}}, or {{ShareData/url}} or {{ShareData/files}} are present, return false.
  2. Let |titleTextOrUrl:boolean| be true if any of {{ShareData/title}}, or {{ShareData/text}}, or {{ShareData/url}} is present.
  3. If |data|'s {{ShareData/files}} member is present:
    1. If |titleTextOrUrl| is false and |data|'s {{ShareData/files}} member is empty, return false.

      This causes a `{ files: [] }` dictionary to be treated as an empty dictionary. However, passing a dictionary like `{text: "text", files: []}` is fine, as `files` is just ignored.

    2. If the implementation does not support file sharing, return false.
    3. If the user agent believes sharing any of the files in `files` would result in a potentially hostile share (i.e., the user agent determines a file is malicious in some way, because of its contents, size, or other characteristic), return false.
  4. If |data|'s {{ShareData/url}} member is present:
    1. Let |url:URL| be the result of running the [=URL parser=] on |data|'s {{ShareData/url}} member, with |base|, and no encoding override.
    2. If |url| is failure, return false.
    3. If the |url|'s [=URL/scheme=] is a [=local scheme=], or `file`, or `javascript`, or `ws`, or `wss`, return false.
    4. If |url|'s [=URL/scheme=] is not a [=sharable scheme=], return false.
  5. Return true.

`ShareData` dictionary

          dictionary ShareData {
            sequence<File> files;
            USVString title;
            USVString text;
            USVString url;
          };
        

The ShareData dictionary consists of several optional members:

files member
Files to be shared.
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.

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 or combine members if necessary. The meaning of each member of the payload is at the discretion of the share target.

Mapping the {{ShareData}} to the share target's (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 (as is the case on Android), one solution is to concatenate both the {{ShareData/text}} and {{ShareData/url}} members of {{ShareData}} and pass the result in the "text" member of the target.

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

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.

Permissions Policy integration

This specification defines a policy-controlled permission identified by the string "web-share". Its [=policy-controlled feature/default allowlist=] is [=default allowlist/'self'=], which means third-party contexts are not [=allowed to use=] the API by default.

It is OPTIONAL for user agents to support [[[PERMISSIONS-POLICY]]]'s `Permissions-Policy` HTTP header.

Developers can use the means afforded by the [[[permissions-policy]]] specification to control if and when a third-party context is [=allowed to use=] this API.

Accessibility considerations

When this specification is used to present information in the user interface, implementors will want to follow the OS level accessibility guidelines for the platform. Further, as sharing can have potential security implications for end-users, as outlined as part of the {{Navigator/share()}} method, the share UI needs to be presented in an accessible manner, while also taking into consideration a platform's security guidelines for user interfaces. Some key considerations are to:

Together, these elements can help users with a range of visual, motor or cognitive disabilities to better understand the nature of the content being shared by a web page.

Privacy considerations

Changelog

The following normative changes were made to the specification during the Proposed Recommendation phase. Please see the commit log for a complete list of changes.

The following normative changes were made to the specification since it was published as a First Public Working Draft to Candidate Recommendation. Please see the commit log for a complete list of changes.

Acknowledgments

The editors would like to thank the following W3C groups for their invaluable feedback, which greatly improved this specification: Accessible Platform Architectures Working Group, the Internationalization Working Group, the Privacy Interest Group, and the Technical Architecture Group.

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.