Open-source project
livereload/livereload-js avatar
livereload/livereload-js

livereload.js is the client half of a protocol whose website is offline

LiveReload JavaScript code that communicates with the server and implements reloading

854 stars186 forksCSSMIT

At a glance

What is it?
livereload-js implements the browser side of the LiveReload protocol, connecting over WebSocket to a server that watches your files and swapping CSS and images in place while other changes reload the page. It is MIT licensed, the newest tag is v4.0.3 from 2026-10-14, and the README tells you to prefer the copy bundled with your server.
Who is it for?
livereload.js is worth using only if a LiveReload server is already driving your workflow, because the script is useless without one and the project itself says you should load the copy your server bundles rather than pin this one. It is the wrong tool for a modern bundler setup that ships its own dev server and reload channel, and it cannot help with live JavaScript reloading, which the README lists as not possible.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 9 days ago.
What is it written in?
Mainly CSS, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A client that needs a server to do anything

LiveReload is a tool for web developers and designers, and it needs two pieces. The first is a client in the browser, which is what this repository provides, and the second is a server running on the development machine. The server watches files and sends change notifications over WebSocket, and the client applies them.

What the client does with a notification depends on the file. When a CSS file or an image is modified, the change is applied live without reloading the page. When any other file is modified, the page is reloaded. The repository description says the same thing in one line, that this is the LiveReload JavaScript code that communicates with the server and implements reloading.

The listed features cover live CSS reloading, full page reloading, the protocol and WebSocket communication, CSS @import support, live image reloading for img src as well as background-image and border-image properties in both inline styles and stylesheets, and live in-browser LESS.js reloading. Under the same heading the README lists what the project would love but cannot do, and the single entry is live JS reloading. That omission is by design rather than a gap in the roadmap.

The primary language listed for the repository is CSS, which is a quirk of how the sources are organised rather than a hint about what the tool does.

The client locates its server from the script tag, or from LiveReloadOptions

The discovery mechanism is the interesting part of the design. livereload.js finds a script tag whose URL includes livereload.js and uses that URL to work out the hostname and port to connect to. That is why the script has to be served from the LiveReload server rather than from a CDN, at least by default.

The simplest inclusion is a plain script tag pointing at the server.

html
    <script src="http://localhost:35729/livereload.js"></script>

LiveReload 2 serves the script over HTTP on port 35729 and speaks the WebSocket protocol on the same port. Most server vendors serve livereload.js on that port, and the README states you can typically access it at http://0.0.0.0:35729/livereload.js.

The smarter variant derives the host from the current page, so that LiveReload keeps working when you open the page on a phone or another machine on the same network. The README provides the snippet for that, and then a second one that falls back to localhost because location.host is empty for file URLs.

html
    <script>document.write('<script src="http://'
    + (location.host || 'localhost').split(':')[0]
    + ':35729/livereload.js"></'
    + 'script>')</script>

If you would rather load the script from elsewhere, a host query parameter overrides the detected host, which is how you point the client at a server on a different machine.

Query parameters and the LiveReloadOptions global

Options can be set in two ways, and the README is explicit that the supported set is identical for both. They can be query parameters on the script source URL, or they can be a global window.LiveReloadOptions dictionary. If the dictionary is set, the script does not even try to find its script tag.

The host option is required when you use the dictionary, because there is no tag to infer it from. The port option overrides the server port, and if it is left blank it inherits the port of the hosting page, which is what lets the script sit behind a proxy.

Three more options are specific to the connection itself. The snipver parameter specifies a version of the snippet, which lets the client warn that the snippet needs updating, and the currently recommended value is version 1.

html
    <script>document.write('<script src="http://'
    + (location.host || 'localhost').split(':')[0]
    + ':35729/livereload.js?snipver=1"></'
    + 'script>')</script>

The mindelay and maxdelay options control the minimum and maximum reconnection delay in milliseconds, defaulting to 1000 and 60000. That range matters in practice. A server restart makes the client reconnect, and the delay bounds how long the browser sits without live reload while it waits.

The npm route sets the dictionary instead of the query string, which is why the README explains that the script would otherwise bail out with an error message about not finding its script tag.

Install it from npm or bower, or take the copy your server ships

The README's primary advice is about not installing this at all. It says web developers who want to use LiveReload should refer to their server, app or tool documentation rather than to this repository, and should use the copy of livereload.js bundled with their server because it is guaranteed to be compatible and may be customised for that server.

If you do install it yourself, two paths are documented. The bower route installs a single script file, dist/livereload.js.

bash
    bower install livereload-js --save-dev

The npm route exists, and the README says including livereload.js in a Browserify bundle probably makes no sense because it is not something you would ship to production.

bash
    npm install livereload-js --save

With npm you then set the options dictionary and require the package, which is what replaces the script tag lookup.

js
    window.LiveReloadOptions = { host: 'localhost' };
    require('livereload-js');

The package uses the window and document globals, so it will not run under Node.js. That is fine for a browser bundle, and it is one more reason not to pull it into a server side build.

The package metadata points main at dist/livereload.js and module at src/startup.js, so a bundler that resolves the module field will pull in the unbuilt sources instead of the distributed file.

Building dist/livereload.js from src with browserify and babel

The package scripts show the build pipeline in full. The build step runs browserify over src/startup.js with the envify and babelify transforms and writes the result to dist/livereload.js.

bash
    NODE_ENV=production browserify -t envify -t babelify src/startup.js > dist/livereload.js

A separate minify step pipes that file through terser with compression and mangling to produce dist/livereload.min.js. The version script ties them together by running version-bower, then the build, then the minify, and staging dist and bower.json before the tag is pushed, which is how the distributed file and the bower metadata stay in step with the version.

Testing runs under mocha with @babel/register, and the test directory includes a jsdom based setup along with a manual browser test that bundles test/html/browserified/main.js with watchify. Linting is eslint with the standard config, run over src, the test files and version-bower.js, and the preversion hook runs lint and the tests before any release.

The browserslist target is deliberately wide, covering browsers with at least 0.2 percent usage, Firefox ESR, and not dead. That is the compatibility contract the client is built against.

A mature protocol, an offline website, and one recent release

The project's ecosystem has aged in a specific way. The livereload.com site is marked as currently offline, and so are the links to the LiveReload app for Mac and to the LiveReload protocol documentation. The list of available servers points at projects in other languages, including rack-livereload, guard-livereload, grunt-contrib-watch and python-livereload, and ends with the invitation to write your own.

The release history tells the same story. Version 4.0.3 was published on 2026-10-14, a long gap after 4.0.2 on 2023-10-21 and 4.0.1 on 2023-03-10. The last push to the repository was on 2026-10-14, the same day as the release, so the recent tag represents real work rather than a version bump, but it does not tell you what changed, since the README has no changelog and the repository root has no CHANGELOG file.

There is also a compatibility note worth knowing. An old version of the script is bundled with the LiveReload browser extensions, and the README says it is not being updated and only serves compatibility with very old clients.

Licensing is MIT, with the LICENSE file at the repository root and the same value declared in package.json. For a development-only script that never ships, that matters little, but the same terms apply if you redistribute it inside a project.

When a bundler dev server makes this redundant

The realistic alternative is the development server that already comes with your build tool. A modern bundler typically ships its own dev server that watches your source tree and pushes updates to the browser over its own channel, which means no extra client script, no separate LiveReload server process and no port 35729 to remember.

The difference in approach is what decides between them. The bundler dev server reloads as part of one pipeline, so it knows about module boundaries and can replace a module without touching the page. LiveReload is protocol level and file type aware: it swaps a stylesheet in place and reloads for everything else, which is a simpler rule that works with any server, any language and any file type, including the CSS and image cases that a bundler dev server would treat differently.

The cost of the LiveReload route is that you now run two things, a server to serve your pages and a LiveReload server to watch them, plus a client script in every page you want monitored. The benefit is that it is independent of your stack: rack-livereload, guard-livereload and python-livereload all speak the protocol, so a Rails app and a Flask app and a static site can share the same client.

If you already have a bundler with a dev server, adding livereload.js solves nothing new. If you do not, and you want live CSS refresh without a full page reload, this client and any server that speaks the protocol are a workable pair.

Editorial conclusion

livereload.js is worth using only if a LiveReload server is already driving your workflow, because the script is useless without one and the project itself says you should load the copy your server bundles rather than pin this one. It is the wrong tool for a modern bundler setup that ships its own dev server and reload channel, and it cannot help with live JavaScript reloading, which the README lists as not possible. Before adopting it, check that your server serves livereload.js on port 35729, add snipver=1 to the script URL so the snippet can warn when it needs updating, and confirm the browserslist targets in package.json still cover the browsers you test.

Frequently asked questions

How do I install livereload-js?

The README says to prefer the copy bundled with your LiveReload server. If you install it yourself, use bower install livereload-js --save-dev for a single script file, or npm install livereload-js --save and set window.LiveReloadOptions before requiring the package.

How do I include livereload.js in my page?

The README gives a plain script tag pointing at http://localhost:35729/livereload.js, and a variant that derives the host from location.host so that LiveReload also works on other devices on the network, falling back to localhost for file URLs.

What does livereload.js do with CSS and image changes?

When a CSS file or an image is modified, it is applied live without reloading the page, including CSS @import, img src, and background-image and border-image properties. When any other file is modified, the page is reloaded instead.

Which options can I pass to livereload.js?

Options can be given as query parameters on the script URL or as a window.LiveReloadOptions dictionary. The set includes host, port and path, plus snipver for snippet versioning, and mindelay and maxdelay, the reconnection delay bounds in milliseconds, which default to 1000 and 60000.

When was the latest livereload-js release?

Version 4.0.3 was published on 2026-10-14, and the last push to the repository was on the same day. Before that, 4.0.2 dates from 2023-10-21 and 4.0.1 from 2023-03-10.

Official sources

  1. Issues
  2. License: MIT
  3. livereload/livereload-js on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/livereload-livereload-js.svg)](https://hysenlabs.com/projects/livereload-livereload-js)

Was this useful?