When you’re rendering your Angular Universal application on the server, it will actually make the  requests which your application triggers on load, on the server.
This causes your   requests to be triggered twice. Once on the server and once on the client side.
Making the request on the client side will delay the visibility of the content (because the data is just not there), and most search engines doesn’t like that at all.

Now this is a problem, so how can we fix it?

There’s probably a couple solutions out there, but the simplest solution in my opinion would be to introduce an interceptor.
As this might not be the best solution for complex applications, it can definitely work well in most cases.


Let’s have a look at the required steps to introduce a simple server-to-client state transfer in your Angular Universal application:

Add BrowserTransferStateModule to the imports array of app.module.ts

Add ServerTransferStateModule to the imports array of app.server.module.ts

Create a browser-state.interceptor.ts and provide it to app.module.ts

Create a server-state.interceptor.ts and provide it to app.server.module.ts


Including BrowserTransferStateModule in app.module.ts


Including ServerTransferStateModule in app.server.module.ts


Creating browser-state.interceptor.ts

Implement the   interface to get some strong typing. As it is optional to implement lifecycle hooks on your classes, it’s quite useful for in-editor debugging.

  is triggered on every  request when you’re using the  module.

Because of the fact we only get data to store on   requests, we will make an if statement checking the type of request method:  .
If it’s not a   request we will simply let the   take care of business.

When it is indeed a   request, then we want to look for data in the . If there’s something for us there, then we will return the result as an  , because this is what   normally would give us. That way we dont need to change anything in our Effects, Components, etc.

Use the requested URL as the identifying key:

If for some reason there should not be anything for us in the   , then we will let the  take care of business once again.

We also have to provide this new interceptor in our app.module.ts.
Import our BrowserStateInterceptor and then provide it as follows:


Creating server-state.interceptor.ts

The serverside interceptor does share alot of the same concepts, but obviously we want it do operate a little different.
This interceptor should always store data for the client side, if the event is an instance of .

Because we used the requested url as the identifying key on the client, it’s easy for us to have the same key generated on the serverside. Simply do the same!

And of course we also have to provide this new interceptor, but in the app.server.module.ts instead.
Import our ServerStateInterceptor and provide it as follows:


Celebration 🎉

By now your application should not make any   request in your browser, on the initial load.
You can test this by running your local nodejs server and have that serve the Angular Universal application for you!

Sometimes fixing a rather complex issue is just that simple.

Have fun and good luck with the state transfering. See you next time!