Server Sent Events example with laravel

Recently I have read about HTML5 Server Sent Events, and liked the concept of establishing long-lived connections to the server, instead of performing frequent Ajax calls to pull the updates. And I wanted to put it into action by implementing live currency rates widget with Laravel as backend PHP application.

Basic Introduction

What are “Server Sent Events”?
As Wikipedia defines

Server-sent events (SSE) is a technology for a browser to get automatic updates from a server via HTTP connection. The Server-Sent Events EventSource API is standardized as part of HTML5 by the W3C.

Basically, its an HTML5 technology that helps web client getting data from the server, using one connection that lives on the server for long interval and sending stream of data to the browser without closing the connection  (basically the connection will remain active until browser closes); such technique is useful for pushing news updates, automatically send updates in a social network, and populating live prices components…etc.

The older approach is called Ajax Long Polling which implemented requesting the updates from the web client by issuing frequent separate requests (by initiating Ajax request recursively with timeout), like the following example:
(function poll(){
      $.ajax({ url: "/path/to/url", success: function(data){
      }, dataType: "json"});
  }, 30000);

To make the idea more clear, I will use live currency rates widget as an example; this widget gets the rates to convert between one currency to another, with displaying up & down arrows to indicate the change of the price.

Basic Usage

The following snippet shows the basic usage of SSE with javascript:

<script type="text/javascript">
var es = new EventSource("/path/to/url");
es.addEventListener("message", function(e) {
}, false);

This piece of javascript code intialize EventSource object which listen for the specified URL, and process the data, as the server sent it back to the browser. Each time the server send new data, the event listener method will be called and will process the information according to the callback function implementation.

The code

As I said, Laravel will be used to implement this example, I will implement two actions; one for rendering the whole page, and the other will send only modified data in json format to the EventSource; as the following:

First, I defined the routes in the routes.php

// in apps/routes.php 
Route::get('/prices-page', 'HomeController@pricesPage');
Route::get('/prices-values', 'HomeController@pricesValues');

Then, I will implement a method to retrieve the rates values ( I used yahoo service as a free feed source):
     * retrieve rates of currencies from feed
     * @return array
    protected function getCurrencyRates() {
        $pair_arr = array('EURUSD', 'GBPUSD', 'USDJPY', 'XAUUSD', 'XAGUSD', 'USDJOD');
        $currencies_arr = array();

        foreach ($pair_arr as $pair) {
            try {
                $price_csv = file_get_contents("$pair=X");
                $price_data = explode(',', $price_csv);
                $currencies_arr[$pair]['price'] = $price_data[1];
                $currencies_arr[$pair]['status'] = '';
            } catch (Exception $ex) {
                $currencies_arr['error'] = $ex->getMessage();
        return $currencies_arr;

It is not efficient to get file from external source in a controller, but I use it here for the purpose of the example. Usually, I write a backend command to get the prices from external source (usually trading server) and controller methods retrieve data from the database.

Second, I will implement the the action to render the whole price block:

public function pricesPage() {
    $prices = $this->getCurrencyRates();
    return View::make('pricesPage', array('prices' => $prices));        

and here is the template:
<h1>Prices here</h1>
        <?php foreach($prices as $currency=>$price_info){?>
        <tr class="price-row">
            <td><?php echo $currency?></td>
            <td data-symbol-price="<?php echo $currency; ?>"><?php echo $price_info['price']; ?></td>
            <td data-symbol-status="<?php echo $currency; ?>"><?php echo $price_info['status']; ?></td>
        <?php }?>

<script type="text/javascript">
        var es = new EventSource("<?php echo action('HomeController@pricesValues'); ?>");
        es.addEventListener("message", function(e) {
            arr = JSON.parse(;
            for (x in arr) {    	
                $('[data-symbol-price="' + x + '"]').html(arr[x].price);
                $('[data-symbol-status="' + x + '"]').html(arr[x].status);
                //apply some effect on change, like blinking the color of modified cell...
        }, false);

And now I will implement pricesValues() action that will push the data to the server, as following:

     * action to handle streamed response from laravel
     * @return \Symfony\Component\HttpFoundation\StreamedResponse
    public function pricesValues() {

            $response = new Symfony\Component\HttpFoundation\StreamedResponse(function() {
            $old_prices = array();

            while (true) {
                $new_prices = $this->getCurrencyRates();
                $changed_data = $this->getChangedPrices($old_prices, $new_prices);

                if (count($changed_data)) {
                    echo 'data: ' . json_encode($changed_data) . "\n\n";
                $old_prices = $new_prices;

        $response->headers->set('Content-Type', 'text/event-stream');
        return $response;

     * comparing old and new prices and return only changed currency rates
     * @param array $old_prices
     * @param array $new_prices
     * @return array
    protected function getChangedPrices($old_prices, $new_prices) {
        $ret = array();
        foreach ($new_prices as $curr => $curr_info) {
            if (!isset($old_prices[$curr])) {
                $ret[$curr]['status'] = '';
                $ret[$curr]['price'] = $curr_info['price'];                
            } elseif ($old_prices[$curr]['price'] != $curr_info['price']) {
                $ret[$curr]['status'] = $old_prices[$curr]['price']>$curr_info['price']?'down':'up';
                $ret[$curr]['price'] = $curr_info['price']; 

        return $ret;

As you notice, the action that push data to the event source, have following properties:

  1. the content type of the response is text/event-stream.
  2. the response I returned here, is of type “StreamedResponse” which is part of Symfony HTTP foundation component, this type of response enables the server to return data to the client as chunks. StreamedResponse object accepts a callback function to output the transferred data chunks.
  3. The prices that have been changed since the latest push will be sent back to browser, (I have compared the old and new prices easily since they reside in the same action), so if the prices didn’t change nothing will be sent back to the browser.
  4. The data returned is prefixed with “data:” and appended “\n\n” characters to the end.
  5. flush() and ob_flush() are called to trigger sending data back to the browser.
For the browsers that don’t support HTML5 features, you can apply simple fallback as following:
<script type="text/javascript">
if(window.EventSource !== undefined){
    // supports eventsource object go a head...
} else {
    // EventSource not supported, 
    // apply ajax long poll fallback

The final output

Now the live currency rates widget is ready, the widget will auto-refresh prices every 3 seconds, and the server will send only rates that has been changed, so the operation is optimized and will not exchange unnecessary requests/response.

SSE price rate
* screenshot of the final component.

24 thoughts on “Server Sent Events example with laravel

  1. Does this work with nginx, which doesn’t support Server Sent Events? Laravel forge is hosted with nginx, how do I get around that?

      1. I am getting this error. I am very new to laravel and web development. How can I solve it?
        EventSource’s response has a MIME type (“text/html”) that is not “text/event-stream”. Aborting the connection.

        1. Hello Hassan,
          seems you forgot to set content type to event-stream on the controller,
          please add this
          $response->headers-> set(‘Content-Type: text/event-stream’);

  2. I have to implement real time private chatting and notifications just like that of facebook. Is SSE appropriate for it or should I learn Sockets?

    1. You should go with websockets, SSE have capability of pushing data to the browser, not in the other direction (like auto-updating quotes and prices as in my example),
      while websockets provide two way channel that enables both sending and receiving data which is suitable for chatting applications

  3. Hi Zaid, Thanks for reply. I am using SSE to show notification to the user. But a problem is encountering. After some time, this code/script gives below error and stops working

    Symfony\Component\Debug\Exception\FatalErrorException FatalErrorException in app\Http\Controllers\NotificationController.php line 64 Maximum execution time of 30 seconds exceeded

  4. Hello, I Like send Event::Fire return with Server-Send-Events, its possible?

    I like send notifications using Server-Send-Event without Pusher or Redis, or other similar.


    1. The key to using SSE here is to make your action return object of type StreamedResponse(),
      so you can use fire an event in your action normally by doing something like that:
      new StreamedResponse(function(){
      $ret = Event::Fire(new EventObj());
      echo ‘data: ‘ . $ret . “\n\n”;

  5. Hello Zaid.

    I apreciate much your help.

    I try do something like that:

    I’m like send notifications at one backend in laravel, for example, when one client is connected, when one product is ordered, etc. I do one Event by some actions, and I have create one controller called NotifyController, thats is accessed usen a route /notify, my template charge this url, y like receive the notifications in this way.

    Another things what I try is using one model intermediate, called notify, and save in this model the event notification and charge in the NotifyController thats, change, not or yes?

    other thing, how I can maintain alive the SSE? I configure ini_set(‘max_execution_time’, 300); but laravel send at 5 minutes, and error, how I can reset this time.

    Thanks by your time and sorry by my english.


  6. How does PHP handle the fact that the loop is infinite? At my end (locally, running WAMP) it fails after 2 min with a 500 error.

  7. Nice tutorial you got there! But i have a problem. My Eventsource keep reconnecting even though I have followed your code exactly the same. What do you guys think would be the problem?

Leave a Reply

Your email address will not be published. Required fields are marked *

Human? prove it... * Time limit is exhausted. Please reload CAPTCHA.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>