---
description: >-
  https://medium.com/@sagarmaheshwary31/push-notifications-with-laravel-and-webpush-446884265aaa
---

# Push Notifications with Laravel and Webpush phần 2 (ok)



## Push Notifications with Laravel and Webpush <a href="#id-8c0d" id="id-8c0d"></a>

[![Sagar Maheshwary](https://miro.medium.com/fit/c/96/96/0*lXwyeMHugT1FI1Xi)](https://medium.com/@sagarmaheshwary31?source=post_page-----446884265aaa----------------------)[Sagar Maheshwary](https://medium.com/@sagarmaheshwary31?source=post_page-----446884265aaa----------------------)Follow[Dec 3, 2018](https://medium.com/@sagarmaheshwary31/push-notifications-with-laravel-and-webpush-446884265aaa?source=post_page-----446884265aaa----------------------) · 8 min read![Image for post](https://miro.medium.com/max/60/1*uIPxiM4f79eZG2ONDAvlaA.png?q=20)![Image for post](https://miro.medium.com/max/938/1*uIPxiM4f79eZG2ONDAvlaA.png)

In this tutorial, we will implement Push Notifications feature in our Laravel app using WebPush. We will use Vanilla Javascript with no frameworks or libraries. Push Notification is a feature of [Service Workers](https://developers.google.com/web/fundamentals/primers/service-workers/). A Service Worker is a script inside the web browser that runs in the background. There are a lot of features like caching , background syncing but this tutorial is only about Push Notifications. We will also implement push notifications for guest users.

> _Note: Service Workers use HTTPS unless you are using localhost._

## Getting Started <a href="#id-34ac" id="id-34ac"></a>

Let’s create a new laravel project with composer:

```
composer create-project laravel/laravel webpush
```

Before migrating table add this line in the **boot()** method of your **AppServiceProvider.php** located in **app\Providers** :

Above code will set the default length of a string column to 191. Since Laravel comes with **utf8mb4** charset as default and it’s max length of a unique key is **191**. If it exceeds the limit then Laravel will generate an error and won’t run migrations. If you want to specify a different charset then you can set it in **database.php** config file located in config directory. Now setup the database and add the database credentials to **.env** file and run **migrate** command which will create all the necessary tables used for authentication:

```
php artisan migrate
```

and generate authentication scaffolding:

```
php artisan make:auth
```

Instead of using a virtual host with apache, we will use Laravel dev server with (for localhost):

```
php artisan serve
```

Open your chrome and paste the url you see in your terminal. (I don’t suggest using browsers other than chrome or firefox).![Image for post](https://miro.medium.com/max/60/1*nQlUrSeEaT1csRlTpnqkuQ.png?q=20)

![Image for post](https://miro.medium.com/max/1626/1*nQlUrSeEaT1csRlTpnqkuQ.png)

## Subscribing a User <a href="#f778" id="f778"></a>

To start with our notifications, we will need to subscribe a user from the browser and we can do that with javascript. There will be two steps involved in subscribing a user which are,

* Getting the permission from the user.
* Getting the PushSubscription from that browser and sending it to server.

Before subscribing a user, we will need to generate application server keys known as **VAPID Keys**. VAPID Keys are public and private keys used for recognizing a user and these keys ensure that it’s the same server triggering the push messages to users. There are a couple of ways to generate these keys, you can visit this site [web-push-codelab.glitch.me](https://web-push-codelab.glitch.me/) to generate these keys or install **web-push** cli with npm to generate them from your command line:

```
$ npm install -g web-push
$ web-push generate-vapid-keys
```

Since we are using a Laravel package called **Webpush**, we can generate these keys with an artisan command. Webpush libraries are also available for other languages, see this [link](https://github.com/web-push-libs/) for a list all libraries. Let’s install the package:

```
composer require laravel-notification-channels/webpush
```

Laravel 5.6 or above uses package discovery feature, so we don’t need to add the package provider. Let’s add the **HasPushSubscription** trait to the **User** model:

After adding the trait we will need to publish the migration that will create the **push\_subscriptions** table:

```
php artisan vendor:publish --provider="NotificationChannels\WebPush\WebPushServiceProvider" --tag="migrations"
```

When you will run the migrate command it will generate an error because of charset saying **the specified key is too long**, so we will add a different charset for this table and add a different length for endpoint column. Let’s update the **up()** method:

You can also publish the **config** file (Which we won’t use):

```
php artisan vendor:publish --provider="NotificationChannels\WebPush\WebPushServiceProvider" --tag="config"
```

Now we can generate the **VAPID Keys**:

```
php artisan webpush:vapid
```

This command will generate VAPID public and private keys and store them to **.env** file.

Let’s create a Service Worker file in public directory named **sw.js** and a javascript file named **enable-push.js** in **public/js** directory. Add the script right before the \</body> ending tag in **app.blade.php** layout file located in **resources/views/layouts** :

It will include the script only if we are autheticated.

Let’s start working on the client side by opening the **enable-push.js** file. We will register our service worker by defining a function named **initSW()** :

In above function, we are first checking if service workers and push are supported, after that we are registering our service worker which is outside one directory (you don’t have to check for push here, this will stop the registration of service worker but we are using service worker for the sole purpose of push, so we will keep it there.). Inside **then()** we are calling **initPush()** which will be responsible for subscribing a user. Don’t forget to call the initSW() in our enable-push.js. Just push this line at the top of the script:

```
initSW();
```

Let’s define **initPush()** after **initSW()** :

Inside **initPush()** we are requesting user permission and if the user clicks allow then we will be able to get **PushSubscription**. After we are granted permission, we are calling **subscribeUser()** which will subscribe the user and send the **PushSubscrption** to our server. Let’s define **subscribeUser()** :

**navigator.serviceWorker.ready** is used to check if a service worker is registered and active. Inside **then()** we are first creating an object **subscriptionOptions** which will have our **VAPID public key** and **userVisibleOnly** option. Use the public key that you have generated from the above command. Setting **userVisibleOnly** to true will not allow silent push that happen in background without letting users know (if not defined then you will get an error, read [more](https://developers.google.com/web/fundamentals/push-notifications/subscribing-a-user#uservisibleonly_options)). **urlBase64ToUint8Array()** function will convert our public key to appropriate format. After subscribing. it will return a **PushSubscription** which we can send it to the server. Inside the second **then()**, we are sending the **PushSubscription** to our server with **storePushSubscription()** function. Before defining it we should define **urlBase64ToUint8Array()** :

Our **storePushSubscription()** looks like this:

Above function is making a POST request to **/push** route. We are getting the [CSRF Token](https://laravel.com/docs/5.7/csrf#csrf-x-csrf-token) from a meta tag which is important for our ajax request. That meta tag was added when we had created authentication scaffolding.

## Storing PushSubscription to the database <a href="#id-9422" id="id-9422"></a>

Let’s start with our routes (add it in your **web.php** not **api.php** because we need to access the authenticated user):

Let’s create our PushController :

```
php artisan make:controller PushController
```

Now open the **PushController** and add the **store** method:

We can use **updatePushSubscription()** to create or update a **PushSubscriber** (because we added that trait to our **User** model). If it was successful, we will get a success message on console. Note that whenever you visit / route you will not see a “service worker installed” message because we have added the script in app layout file which is not used by welcome view. Now refresh the page and you will see a permission box:![Image for post](https://miro.medium.com/max/60/1*oFP85pWujLvqOF_PmSgYZg.png?q=20)![Image for post](https://miro.medium.com/max/444/1*oFP85pWujLvqOF_PmSgYZg.png)

When you click **Allow**, you will see the **PushSubscription** and the success message in console:![Image for post](https://miro.medium.com/max/60/1*fzX85MuHbpG0l8KwCwpLzg.png?q=20)![Image for post](https://miro.medium.com/max/1626/1*fzX85MuHbpG0l8KwCwpLzg.png)

Now we need to create a [Notification](https://laravel.com/docs/5.7/notifications) in Laravel to send Push Notifications :

```
php artisan make:notification PushDemo
```

Open the notification class which is located in **app/Notifcations** directory and add this code:

Inside **toWebPush()** method, we have a notification title for the title of our notification, body will be the extra text, icon is the image displayed on a notification and action will display a button with notification (you can add more [options](https://github.com/laravel-notification-channels/webpush#usage) and learn more about these [options](https://developers.google.com/web/fundamentals/push-notifications/display-a-notification)). Now we can send notifications using **Notification::send()** from our controller. Let’s define a **push** method inside our controller:

add a new route in **web.php**:

We will need a button to send notifications so let’s add it in our **home.blade.php** view. Place it inside the **div** with a class of **card-body** :

Now the final step is to add an event listener that will listen to the **push event** in our service worker file **sw.js** located in public directory:

Inside the **push event** listener, we are first checking if Notifications are allowed and supported, after that we are accessing the notification data from **e** object with **e.data** and converting it to json with **json()** method. In service workers, **waitUntil()** is used to tell the browser that a task is running and should not be terminated. we can display a notification with **serviceWorkerRegistration.showNotification(title,options)**. Make sure you check the update on reload option inside the application tab in dev tools.![Image for post](https://miro.medium.com/max/60/1*P1OAatLHpGwQPNeRpTO_ag.png?q=20)![Image for post](https://miro.medium.com/max/1628/1*P1OAatLHpGwQPNeRpTO_ag.png)

Now we can test it by click that button.![Image for post](https://miro.medium.com/max/60/1*fLREU_EBIfD5iLaB6XeBQg.png?q=20)![Image for post](https://miro.medium.com/max/1628/1*fLREU_EBIfD5iLaB6XeBQg.png)

Ever browser and operating system has it’s own way of displaying a notification. I’m using chrome on ubuntu. Chrome does not show the icon while Firefox does.![Image for post](https://miro.medium.com/max/60/1*8XLGspC_zEboXfm8BBiQHQ.png?q=20)![Image for post](https://miro.medium.com/max/653/1*8XLGspC_zEboXfm8BBiQHQ.png)

and when you hover over it it will look like this:![Image for post](https://miro.medium.com/max/60/1*3--S5z4hQtrEIsmzjTZ6HA.png?q=20)![Image for post](https://miro.medium.com/max/655/1*3--S5z4hQtrEIsmzjTZ6HA.png)

Here’s how it looks on Firefox (It does not show notification actions):![Image for post](https://miro.medium.com/max/60/1*4UvWOFXvmtZ4Tz2SedgnTg.png?q=20)![Image for post](https://miro.medium.com/max/653/1*4UvWOFXvmtZ4Tz2SedgnTg.png)

## Notifications For Guest Users (New) <a href="#id-0e0e" id="id-0e0e"></a>

> _Please read the above tutorial before implementing guest notifications_

Most of the times we want all the visitors of our website to receive push notifications so let’s work on that. First we need to update the migrations and create some new migrations. Open **push\_subscriptions** migration and update **user\_id** to **guest\_id:**

Remove the foreign key constraint:

Let's create a **Guest** Model and it's migration that will relate to the push subscription:

```
php artisan make:model Guest -m
```

Inside the **guests** table migration we have a unique column **endpoint** that will be used to identify each push subscription:

We need another migration that will create a foreign key constraint between these tables:

```
php artisan make:migration add_foreign_to_guest_id_in_push_subscriptions_table --table=push_subscriptions
```

Open the migration and add the following foreign constraint inside the **up()** method:

Create all the tables with migrations command. Now open **Guest** model and add the following:

We are importing **Notifiable** trait so we can use Laravel notifications (it’s already imported in **User** model). Overriding **pushSubscriptionBelongsToUser()** method is important since we are not using authenticated user.

Last step will be to modify our **PushController** so open the controller and first replace all the **User** model usages with **Guest** model. After that replace the below line inside the **store()** method:

With:

Of course you to need to remove the **@auth** directive that blocks the inclusion of our **enable-push.js** script and we are done.

You might want to deploy it to heroku which has a free version with https ( if you want to test it on mobile devices). As far as the UX goes, it might be a good idea to create something like a button which will trigger the initPush(). It’s just not a good idea to ask for notification permission right from the start when our users don’t know what kind of notifications they are receiving.

Above was just a basic example of using Push notifications. You can dig deeper if you want at google developers [docs](https://developers.google.com/web/fundamentals/push-notifications/).

Thank you for reading this tutorial and feel free to comment if you get stuck. You can find the Source Code / Github repo [HERE](https://github.com/SagarMaheshwary/webpush-example). Branch for guest notifications can be found be [HERE](https://github.com/SagarMaheshwary/webpush-example/tree/guest-notifications).

> Please note that **\<?php** in code samples is only used for syntax highlighting
