BrowserSync does not inject styles on external url

Hi all I went through many articles here related to BrowserSync (BS) but non of them solved my problem so I decided to rise another topic.

Problem: When I run Yarn run start BS session is started with this output in the console:

[BS] [HTML Injector] Running...
[Browsersync] Proxying: http://productivitypuzzle.local
[Browsersync] Access URLs:
       Local: http://localhost:3000
          UI: http://localhost:3001
 UI External:
[Browsersync] Watching files...

Everything works fine on local url http://localhost:3000 When I do change some sass file, styles are automatically injected without browser page refresh (like one would expect). The issue is that on external url of BS session (no matter what browser, device or OS I have tried) simply BS does not inject styles. BS looks like its working screens are synced, you can see box saying building as well only styles are not refreshed. Styles though appear after manual page refresh. Any idea where could be a problem? Have I missed something here in the community?

Just humble question: Not sure if it is and issue but once I start yarn run start command, style changes are not being updated on devUrl from config.json. They are reflected on devUrl only after running build command. Is that a way it is meant to work?

I have basically new instance of Sage 9 with Bootstrap installed on my local environment following Sage 9 book instructions all the way. Seems like it should work but it does not. Have not tested js files…

config.json contains:

  "entry": {
    "main": [
    "customizer": [
  "publicPath": "/wp-content/themes/pp-wp-theme",
  "devUrl": "http://domain-substituted.local",
  "proxyUrl": "http://localhost:3000",
  "cacheBusting": "[name]_[hash:8]",
  "watch": [

hosts file contains:       domain-substituted.local

Thank you for your time in advance! Cheers!

I have this same issue. One of the few things that’s keeping me from switching from Sage 8->9. Style injection works fine on localhost:3000, doesn’t work on, even though BrowserSync is running and refreshing for PHP changes.

In Sage 9, Browsersync isn’t injecting the styles or scripts, Webpack’s hot module replacement (HMR) is handling that.

Can you provide us with any output from the browser console?

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:3000/app/themes/sage/dist/ (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
Error: Manifest request to http://localhost:3000/app/themes/sage/dist/ timed out.
[HMR] Update check failed: hotDownloadManifest/</request.onreadystatechange@

It seems like the HMR client is unaware of the external URL as it is still calling for localhost:3000.

Related: roots/sage#1874, #1902

This is based on @QWp6t’s advice in the closed PR above (#1902):

Create the file resources/assets/config-local.json. This file will be ignored by Git.

Replace the following address with whatever IP Browsersync is using for external URL.

  "proxyUrl": "http://192.168.x.x:3000"

This will make the Browsersync external URL work for HMR, but now localhost:3000 will not.


You might want to avoid using .local for your development TLD. If you are on a Mac, there could be a conflict with Bonjour which uses .local.


@knowler sry for later feedback, thank you for looking at it. At first I tried to change only domain from .local -> .test which did not work out. Then I followed your suggestion to create config-local.json file and problem got solved. Only one question, is there any way how one can set, that in browser will be opened proxyUrl from config-local.json (http://192.168.x.x:3000) instead of (localhost:3000) from original config.json file? Tried to change proxyUrl value in original config.json file but with no joy…
Thank you!

1 Like

You’ll need to set open: "external". Sage sets this to true by default which opens "local" (see Browsersync docs).

You can set this it in config-local.json as well:

  "proxyUrl": "http://192.168.x.x:3000",
+ "open": "external"

Perfect, thank you for explanation and yeah as one would expect, adding "open": "external", does the trick!

1 Like