# How to make your web app accept sharing

I am building a web app that helps people manage frequently used links and notes (called [easyy.click](https://easyy.click)), I have added several ways to make collecting links/notes easyy, for example:

* People can add multiple links on the creation page;
    
* People can import their browser bookmarks (it still works if you have thousands of links, takes some time though);
    
* Created a browser extension, so people can save the current tab, or any link / selected text by right clicking it, this makes collecting really easyy on laptop;
    

The next step is, is it possible to accept shared link / text from other apps on the phone? So it’s also easyy to collect things on the phone.

I have the question, GPT has the answer, and the answer is Yes (partially). You may guessed it, it works with Android, but not iOS, details [here](https://developer.mozilla.org/en-US/docs/Web/Manifest/share_target).

I will show you how I made it work, to accept sharing for my web app on Android.

### 1). Add share\_target to manifest.json

Your web app needs to be a PWA, so you have to have a valid manifest.json, and it needs to have a `share_target` field, like this:

```json
{
  "share_target": {
    "action": "/easyy-share",
    "method": "POST",
    "enctype": "multipart/form-data",
    "params": {
      "title": "title",
      "text": "text",
      "url": "url"
    }
  }
}
```

This tell Android, if people share a link/text to your web app, it will make a `POST` request to `${appDomain}/easyy-share` (in my case `https://app.easyy.click/easyy-share`), with the payload defined by `enctype` and `params`.

(If your web app is a SPA, you don’t need to prepare a `/easyy-share` route, this request will handled by service worker, see below)

This is my full manifest.json file: [https://github.com/penghuili/easyy.click/blob/master/public/manifest.json](https://github.com/penghuili/easyy.click/blob/master/public/manifest.json)

### 2). Register a service worker

You can process the request with a real backend endpoint (see the MDN doc), or, you can process it within service worker.

My web app is a SPA, and I need to end-to-end encrypt the link/note before sending it to backend, so I process the request in service worker.

When my SPA starts, I register a service worker:

```javascript
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js').catch(registrationError => {
    console.log('SW registration failed: ', registrationError);
  });
}
```

The sw.js file has the logic to process the request.

### 3). Process request in sw.js

The sw.js needs to have a listener for the `fetch` event, like this

```javascript
self.addEventListener('fetch', event => {
  if (event.request.method === 'POST' && event.request.url.includes('/easyy-share')) {
    event.respondWith(handleShare(event.request));
  }
});
```

We only process it if the request method is POST and the path is /easyy-share. All other fetch requests will behave normally.

Now let’s see how the `handleShare()` looks:

```javascript
async function handleShare(request) {
  const formData = await request.formData();
  const title = formData.get('title');
  const content = formData.get('url') || formData.get('text');

  if (!content) {
    return Response.redirect('/shared', 303);
  }

  saveContent(title, content);

  return Response.redirect(`/shared?shared=${isValidUrl(content) ? 'link' : 'text'}`, 303);
}
```

Very straightforward, we get the payload from request, save it, and redirect to a `/shared` page with some query params. Some notes:

1. `saveContent()` is an async function, but here we don’t need to `await` it, the requests will finish in the background, and users will see the success page quickly;
    
2. In 1) we said we don’t need a `/easyy-share` route, but here we need a `/shared` route, because `Response.redirect('/shared', 303)` will open our app, and open the `/shared` page. This is our good chance to tell users, that the share is done;
    
3. service worker doesn’t have access to localStorage, but it has access to indexDB, so if your `saveContent()` needs to read something from the localStorage (access token maybe?), you need to save that thing also in indexDB in your main app, so service worker can get the value;
    

Check the full code of my sw.js: [https://github.com/penghuili/easyy.click/blob/master/src/sw.js](https://github.com/penghuili/easyy.click/blob/master/src/sw.js)

This is the end result:

%[https://x.com/easyydotclick/status/1854192613655560196] 

Let me know if you have any feedback or question.
