Web Share API

W3C Working Draft

More details about this document
This version:
https://www.w3.org/TR/2022/WD-web-share-20220701/
Latest published version:
https://www.w3.org/TR/web-share/
Latest editor's draft:
https://w3c.github.io/web-share/
History:
https://www.w3.org/standards/history/web-share
Commit history
Test suite:
https://wpt.live/web-share/
Editors:
Matt Giuca (Google Inc.)
Eric Willigers (Google Inc.)
Marcos Cáceres (Apple Inc.)
Feedback:
GitHub w3c/web-share (pull requests, new issue, open issues)
Browser support:
caniuse.com

Abstract

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.

Status of This Document

This section describes the status of this document at the time of its publication. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.

This is a work in progress. Wide review and feedback welcome.

This document was published by the Web Applications Working Group as a Working Draft using the Recommendation track.

Publication as a Working Draft does not imply endorsement by W3C and its Members.

This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

This document was produced by a group operating under the W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

This document is governed by the 2 November 2021 W3C Process Document.

1. Usage Examples

This section is non-normative.

1.2 Sharing a file

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

Example 2: Sharing a file
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);
  }
});

1.3 Validating a share

Calling canShare() method with a ShareData dictionary validates the shared data. Unlike share(), it can be called without transient activation.

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

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

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

1.4 Checking if members are supported

Because of how WebIDL dictionaries work, members passed to 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 canShare() individually to check if they are supported.

Example 4: Future-proofing shares
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.

Example 5: Filtering out 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 });
});

2. API definition

2.1 Extensions to the Navigator interface

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

2.1.1 Internal Slots

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

Promise? [[sharePromise]]
The this.[[sharePromise]] is a promise that represents a user's current intent to share some data with a share target. It is initialized to null.

2.1.2 share() method

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

  1. Let document be the current settings object's relevant global object's associated Document.
  2. If document is not fully active, return a promise rejected with an "InvalidStateError" DOMException.
  3. If document is not allowed to use "web-share", return a promise rejected with a "NotAllowedError" DOMException.
  4. If this.[[sharePromise]] is not null, return a promise rejected with an "InvalidStateError" DOMException.
  5. Let global be this's relevant global object.
  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 be this's relevant settings object's 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 url member is present:
    1. Let url be the result of running the URL parser on data's url with base.
    2. Assert: url is URL.
    3. Set data to a copy of data, with its 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.[[sharePromise]] to be a new promise.
  13. Return this.[[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.[[sharePromise]] with an "AbortError" DOMException.
      2. Set this.[[sharePromise]] to null.
      3. 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, queue a global task on the user interaction task source using global to:
      1. Reject this.[[sharePromise]] with an "AbortError" DOMException,
      2. Set this.[[sharePromise]] to null.
      3. 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.
    5. 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.[[sharePromise]] with an "DataError" DOMException.
      2. Set this.[[sharePromise]] to null.
      3. Abort these steps.
    6. 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:
      Note
      1. Resolve this.[[sharePromise]] with undefined.
      2. Set this.[[sharePromise]] to null.

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

Note
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.

2.1.3 canShare(data) method

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

  1. Let document be the current settings object's relevant global object's associated Document.
  2. If document is not 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 API base URL.

2.1.4 Validate share data

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

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

      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 url member is present:
    1. Let url be the result of running the URL parser on data's url member, with base, and no encoding override.
    2. If url is failure, return false.
    3. If url is a URL the user agent deems potentially hostile (e.g., "file:") or wouldn't make sense to outside the scope of the document (e.g., "blob:"), return false.

      Issue 178: Limiting to http/https is limiting

      #173 was a bit of a learning experience. The fix for that in #174 limits URLs to http or https. That was the most conservative reaction to that issue.

      This means that a number of URI schemes with no known exposure to this vulnerability can no longer be shared. From standard protocols mailto, sip[s], and tel are all examples of schemes that do not invoke actions and should be safe to share. (Why you might use those rather than share a vCard resource is not relevant; these seem valid to me.) Then there are the quasi-standard things like: ipfs, magnet. And a whole bunch of proprietary schemes: acrobat, zoommtg, steam, microsoft-edge (ok, maybe we don't want that...), and so forth.

      Now that the dust has settled, it might be worth examining principles a little closer to determine whether a looser set of constraints can be made to work. @dveditz suggested that we block URLs if we might not permit both navigation or redirection. I think that is a reasonable starting point here. We don't allow navigation or redirects to file:// and so sharing that seems to be primarily a means of circumventing that policy.

      We can't expect that share targets will respect the same policies that a browser does in case it follows an HTTP URL that redirects to file:///, but we are explicitly accepting that risk already by allowing use of HTTP schemes.

  5. Return true.

2.2 ShareData dictionary

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

The ShareData dictionary consists of several optional members:

files member
Files to be shared.
text member
Arbitrary text that forms the body of the message being shared.
title member
The title of the document being shared. May be ignored by the target.
url member
A URL string referring to a resource being shared.
Note

3. 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.

Note
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 text and 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 share() method.

3.1 Examples of share targets

This section is non-normative.

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

Note
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.

4. Permissions Policy integration

This specification defines a policy-controlled permission identified by the string "web-share". Its default allowlist is 'self'.

Note

A document’s permission policy determines whether a share() call immediately rejects with a "NotAllowedError" DOMException.

5. Accessibility considerations

This section is non-normative.

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.

6. Security and privacy considerations

This section is non-normative.

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).

A. Extensibility of this API

This section is non-normative.

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 (e.g., images) and strings with new semantics (e.g. author).

Warning
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 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.

Note
There is an open discussion about how to provide feature-detection for dictionary members. Web Share will use the mechanism produced by that discussion.

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({image: 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.

B. Conformance

As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.

The key words MAY, MUST, MUST NOT, and SHOULD in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

C. IDL Index

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

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

D. Changlog

This section is non-normative.

E. 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.

F. References

F.1 Normative references

[fileapi]
File API. Marijn Kruisselbrink; Arun Ranganathan. W3C. 4 June 2021. W3C Working Draft. URL: https://www.w3.org/TR/FileAPI/
[html]
HTML Standard. Anne van Kesteren; Domenic Denicola; Ian Hickson; Philip Jägenstedt; Simon Pieters. WHATWG. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[permissions-policy]
Permissions Policy. Ian Clelland. W3C. 16 July 2020. W3C Working Draft. URL: https://www.w3.org/TR/permissions-policy-1/
[RFC2119]
Key words for use in RFCs to Indicate Requirement Levels. S. Bradner. IETF. March 1997. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc2119
[RFC8174]
Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words. B. Leiba. IETF. May 2017. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc8174
[url]
URL Standard. Anne van Kesteren. WHATWG. Living Standard. URL: https://url.spec.whatwg.org/
[WEBIDL]
Web IDL Standard. Edgar Chen; Timothy Gu. WHATWG. Living Standard. URL: https://webidl.spec.whatwg.org/

F.2 Informative references

[dom]
DOM Standard. Anne van Kesteren. WHATWG. Living Standard. URL: https://dom.spec.whatwg.org/
[encoding]
Encoding Standard. Anne van Kesteren. WHATWG. Living Standard. URL: https://encoding.spec.whatwg.org/