Web Share Target API: Receive Files in JavaScript PWAs

The Web Share Target API allows installed Progressive Web Apps (PWAs) to register with the host operating system as share targets, enabling them to receive content—including text, links, and files—shared from other native apps or web pages. This article explains what the Web Share Target API is, how to configure the Web App Manifest to accept shared files, and how to handle incoming file payloads using a JavaScript Service Worker.

What is the Web Share Target API?

The Web Share Target API is the receiving counterpart to the Web Share API. While the Web Share API allows a web app to trigger the native operating system’s share sheet to send data, the Web Share Target API allows an installed PWA to appear in that share sheet as a destination.

Once an app is installed, the operating system recognizes it as a potential handler for specific MIME types and file extensions. When a user shares a file from another application (such as a photo gallery, file manager, or native browser), the OS launches the PWA and routes the shared data to it.

Step 1: Registering File Types in the Web App Manifest

To enable a PWA to receive files, you must define the share_target member inside the manifest.json file.

Because files require binary data transfer, the share target configuration must use the POST method and the multipart/form-data encoding type.

{
  "name": "File Receiver PWA",
  "short_name": "FileReceiver",
  "start_url": "/",
  "display": "standalone",
  "share_target": {
    "action": "/handle-shared-file",
    "method": "POST",
    "enctype": "multipart/form-data",
    "params": {
      "title": "share_title",
      "text": "share_text",
      "url": "share_url",
      "files": [
        {
          "name": "shared_files",
          "accept": ["image/*", "application/pdf"]
        }
      ]
    }
  }
}

Key Configuration Fields:

Step 2: Intercepting Shared Files in the Service Worker

When the user selects your PWA from the share sheet, the browser issues a POST request to the URL specified in action. Because this request is not processed by a traditional web backend on a static/client-only PWA, a Service Worker must intercept the fetch event, extract the file data, and transfer it to the client application.

// service-worker.js
self.addEventListener('fetch', (event) => {
  const url = new URL(event.request.url);

  if (url.pathname === '/handle-shared-file' && event.request.method === 'POST') {
    event.respondWith(
      (async () => {
        const formData = await event.request.formData();
        const files = formData.getAll('shared_files');

        // Store the files temporarily (e.g., in IndexedDB or Cache API)
        await storeSharedFiles(files);

        // Redirect the user to the processing page in the PWA
        return Response.redirect('/view-files', 303);
      })()
    );
  }
});

async function storeSharedFiles(files) {
  // Example: Persist files using IndexedDB or Cache Storage
  const cache = await caches.open('shared-files-cache');
  for (const file of files) {
    await cache.put(`/shared/${file.name}`, new Response(file));
  }
}

Step 3: Accessing the Shared File in the UI

Once the Service Worker redirects to the destination page (/view-files), the application’s client-side JavaScript can retrieve the cached files and render them to the user.

// app.js (running on /view-files)
window.addEventListener('DOMContentLoaded', async () => {
  const cache = await caches.open('shared-files-cache');
  const requests = await cache.keys();

  for (const request of requests) {
    if (request.url.includes('/shared/')) {
      const response = await cache.match(request);
      const fileBlob = await response.blob();
      
      // Process or display the file (e.g., create an Object URL)
      const fileUrl = URL.createObjectURL(fileBlob);
      const img = document.createElement('img');
      img.src = fileUrl;
      document.body.appendChild(img);

      // Clean up cache entry after retrieval
      await cache.delete(request);
    }
  }
});

Requirements and Considerations