# Web push (https://www.getfounderhq.com/docs/sequences/web-push)

Use this to send notifications to a browser: Chrome, Edge, Firefox, and
Safari. It is standard Web Push. You do not need a Firebase project or an
Apple certificate.

There is no key to type. Add the connection, and FounderHQ makes the key
pair. The private key stays in FounderHQ.

## Connect

1. Open [Sequences → Settings](https://app.getfounderhq.com/sequences/settings), press **Connect channel**,
   then choose **Push**.
2. Select **Web push**. Give the connection a name and a contact email.
   Browser makers use the email if there is a problem with your
   notifications. Your visitors never see it.
3. Click **Connect web push**. FounderHQ shows the public key of the
   connection.

You can copy the key again later: open the menu of the connection in
Sequences settings and select **Copy public key**.

## Set up your site

Your site must have the FounderHQ Web SDK first: see
[Web SDK](/analytics/sdks/web). Web push works only on a site with HTTPS.
`http://localhost` also works, for a test on your own computer.

Do four things on your site:

1. **Copy the public key.** It is on the connection in Sequences settings.
   It is safe to put in your site's code.
2. **Add the service worker file.** Make a file with the one line below
   and serve it from your own site at `/founderhq-push-sw.js`. A browser
   accepts a push service worker only from the origin of the page, so this
   small file must be on your site. The line loads the FounderHQ code, and
   you get each update with no work.

   ```js
   // /founderhq-push-sw.js
   importScripts("https://i.getfounderhq.com/founderhq-push-sw.js");
   ```
3. **Ask for the permission.** Call `requestWebPushPermission` when the
   person clicks your own button. Browsers refuse a prompt that no click
   started. You decide where the button is and when it shows; the SDK shows
   no interface of its own.
4. **Register the browser.** Call `registerWebPush` after `identify`, on
   every page load.

```ts
founderhq.identify("user_42");

// On every page load. It does nothing until the permission is granted.
founderhq.registerWebPush({ applicationServerKey: "YOUR_PUBLIC_KEY" });

// On your "Turn on notifications" button.
button.addEventListener("click", async () => {
  const { status } = await founderhq.requestWebPushPermission({
    applicationServerKey: "YOUR_PUBLIC_KEY",
  });
  if (status === "registered") hideTheButton();
});
```

`requestWebPushPermission` shows the browser's prompt and then registers the
browser. It does not ask again when the person already allowed or blocked
notifications. Both functions return a promise with a `status`:

| Status | Meaning |
| --- | --- |
| `registered` | The browser is subscribed and belongs to the identified contact |
| `not_identified` | The browser is subscribed. FounderHQ gets it on the next `identify` |
| `permission_not_granted` | The person has not allowed notifications yet |
| `unsupported` | The browser has no web push |
| `consent_required` | The SDK is in cookieless mode, or analytics consent is not granted. Nothing is stored or sent |
| `failed` | The subscription did not work. `reason` says why |

The promise never rejects. The SDK only ends a push subscription that it
made. A subscription from another push product on your site always stays.

**iPhone and iPad** have web push only for a site that the person added to
the Home Screen. Three things are necessary:

- iOS or iPadOS 16.4 or later.
- Your site has a web app manifest with `"display": "standalone"`.
- The person added your site to the Home Screen and opens it from there.

In a normal Safari tab the status is `unsupported`.

## If your site already has a service worker

A site can have only one service worker for a scope. The SDK does not
replace yours. When it finds another worker and you gave no
`serviceWorkerPath`, `registerWebPush` returns `failed` with the reason
`service_worker_exists`, and nothing changes.

Do two things:

1. Load the FounderHQ code from the **first line** of your own worker. You
   then do not need the `/founderhq-push-sw.js` file.
2. Give the SDK the path of your worker.

```js
// sw.js: this must be the first line.
importScripts("https://i.getfounderhq.com/founderhq-push-sw.js");
```

```ts
founderhq.registerWebPush({
  applicationServerKey: "YOUR_PUBLIC_KEY",
  serviceWorkerPath: "/sw.js",
});
```

The line must be first, so that the FounderHQ code runs before yours. Your
own `push` and `notificationclick` code then does not get a FounderHQ
notification, and you do not show it a second time. Every other push still
goes to your code.

Does your framework register the worker, or is your worker a module? A
module worker cannot use `importScripts`. Save a copy of
[the FounderHQ code](https://i.getfounderhq.com/founderhq-push-sw.js) on your site as `/founderhq-push-sw.js`, and use
`import "/founderhq-push-sw.js"` as the first line of your worker. Then give the SDK the registration, and the SDK
registers nothing:

```ts
founderhq.registerWebPush({
  applicationServerKey: "YOUR_PUBLIC_KEY",
  serviceWorkerRegistration: await navigator.serviceWorker.ready,
});
```

Did your site use `/founderhq-push-sw.js` as its worker before, and now has
its own worker on the same scope? Add the `importScripts` line. Without it
no worker shows a FounderHQ notification, so on the next visit the SDK ends
that browser's FounderHQ subscription and removes the browser from the
contact.

The FounderHQ file only shows FounderHQ notifications and opens their
links. It does not cache pages. It has no fetch handler, so it does not
change how your pages load.

**One connection keeps its key pair.** A browser subscription works only
with the key it was made with. If you add a new web push connection and use
its key, the SDK subscribes each browser again on its next visit. A browser
that does not come back gets no more pushes.

A browser belongs to one site: the subscription of `app.example.com` is not
the subscription of `www.example.com`.

## Send

A browser is one more device of the person. A push step in a sequence and a
push broadcast reach it with no other change. To send to browsers only, open
**Devices** on the push step or the broadcast and turn off **iPhone** and
**Android**.

## Show a push in your page while the person is there

A notification from the browser is for a person who is away. For a person
who has your site in view, you can show the push in your own page.

Put `fhq_when_visible` with the value `page` in the **data** of the push
template. When that push arrives and a tab of your site is in view, no
browser notification shows. The tab gets a message, and your page shows it:

```ts
navigator.serviceWorker.addEventListener("message", (event) => {
  if (event.data?.type !== "founderhq:push") return;
  const { title, body, link, data } = event.data;
  showInMyPage({ title, body, link, data });
});
```

With no tab in view, the browser notification shows as usual. A push with
no `fhq_when_visible` always shows the browser notification.

## Replace or remove a notification

A push can carry a **notification key**: any text you choose, such as
`order-1042`, set as `notificationKey` when you
[send from your server](/sequences/send-api). A push with no key of its own
is named by its message ID.

**Replace.** Send another push with the same key. The browser shows one
notification with the new text, not two.

**Remove.** Call the SDK from your page when the person has seen what the
notification is about. Pass the notification key, or the message ID for a
push with no key:

```ts
// The person opened order 1042.
await founderhq.dismissPushNotification("order-1042");
```

It closes the notifications your site's FounderHQ pushes showed with that
key, in this browser, and resolves with how many it closed. It sends nothing,
so it works with or without consent.

A browser's notification is removed by your page only. A browser expects
every push to show something, so
[a removal from your server](/sequences/push#remove-from-your-server)
reaches phones and tablets and leaves browsers alone.

## What a browser shows

A push template is the same for phones and browsers. A browser uses its
fields as follows:

| Field | In a browser |
| --- | --- |
| **Title**, **Body** | The text of the notification |
| **Opens** | The page a click opens. Use a link on your site or an `https` link. With no link, or with an app link such as `myapp://orders/42`, a click opens your home page |
| **Image** | A large picture below the text. Chrome and Edge on Windows and Android show it. Browsers on a Mac, Firefox, and Safari do not |
| **Icon** | A small logo beside the text. Only browsers use it. Safari shows the icon of your site in its place |
| **Data** | Your page gets it with the `founderhq:push` message |

The image and the icon must be `https` links.

## Verify


1. Open your site in a browser, sign in, and allow notifications.
2. In FounderHQ, open the person in **People**. The browser shows in the
   list of the person's devices.
3. Open a push broadcast and send a test to that person. The notification
   shows in the browser in some seconds.

If the browser does not show on the person, read the `status` and `reason`
that `registerWebPush` returns.

For opens, message content, and troubleshooting, see [Push](/sequences/push).
