Angular DevTools
On this page ▾
Record every HttpClient call on the server and in the browser, then break them on purpose with fault rules.

Set up SSR & HTTP

The SSR & HTTP tab records every HttpClient call during server rendering and in the browser. It needs three things: an interceptor, a hydration hook, and SSR running next to the devtools.

What you set up

withNgDevtools() records each request and applies fault rules. provideNgDevtoolsHttp() captures the NG05xx hydration warnings Angular logs. SSR and the devtools hub run in the same Express process.

The flow

Register the interceptor and the hydration hook in app.config.ts. Place withNgDevtools() before your own interceptors. SSR and the devtools middleware share one Express process. Use RenderMode.Server for them in app.routes.server.ts. Add a rule in the tab and reload the page.

Step 1: Add the providers

Both functions come from @santoshyadavdev/ng-devtools/http.

// src/app/app.config.ts
import {ApplicationConfig} from '@angular/core';
import {provideHttpClient, withFetch} from '@angular/common/http';
import {provideNgDevtoolsHttp, withNgDevtools} from '@santoshyadavdev/ng-devtools/http';
import {provideClientHydration} from '@angular/platform-browser';

export const appConfig: ApplicationConfig = {
  providers: [
    provideClientHydration(),
    provideHttpClient(withFetch(), withNgDevtools()),
    provideNgDevtoolsHttp(),
  ],
};

What each provider does

  • withNgDevtools() adds the interceptor that records calls and applies fault rules.
  • provideNgDevtoolsHttp() captures the hydration warnings (NG05xx) before the overlay loads.
The interceptor checks ngDevMode. In production builds it passes every request through untouched.

Step 2: Put withNgDevtools first

Register withNgDevtools() before your own interceptors. Then it records requests as the app makes them, and fault rules apply before anything else.

// src/app/app.config.ts
import {provideHttpClient, withFetch, withInterceptors} from '@angular/common/http';
import {ApplicationConfig} from '@angular/core';
import {provideClientHydration} from '@angular/platform-browser';
import {provideNgDevtoolsHttp, withNgDevtools} from '@santoshyadavdev/ng-devtools/http';
import {authInterceptor} from './auth.interceptor';

export const appConfig: ApplicationConfig = {
  providers: [
    provideClientHydration(),
    provideHttpClient(withFetch(), withNgDevtools(), withInterceptors([authInterceptor])),
    provideNgDevtoolsHttp(),
  ],
};

How transfer cache hits are detected

A call counts as a transfer cache hit when the cached response comes back right away. It also counts when the page's TransferState holds a GET or HEAD entry for the same URL. So an async interceptor after withNgDevtools() does not hide cache hits.

Step 3: Mount the hub in server.ts

The interceptor on the server hands its calls to the devtools through the Node process. So SSR and the devtools middleware must run in the same Express process.

// src/server.ts
import {AngularNodeAppEngine, createNodeRequestHandler} from '@angular/ssr/node';
import express from 'express';
import {initNgDevtoolsHub} from '@santoshyadavdev/ng-devtools/hub';

const app = express();
const angularApp = new AngularNodeAppEngine();

const devtools = initNgDevtoolsHub({
  ws: {sidecar: true},
});
app.use(devtools.nodeMiddleware);

// ... your API routes, static files and the Angular handler

export const reqHandler = createNodeRequestHandler(app);

This is adapted from the demo app's src/server.ts. It keeps the one-time code and the origin check on, which are the defaults. See Angular CLI and Express for every option.

Step 4: Render the pages you test on the server

Routes that are prerendered at build time make no requests at runtime. SSR rules do not apply to them. Use RenderMode.Server for the pages you want to test.

// src/app/app.routes.server.ts
import {RenderMode, ServerRoute} from '@angular/ssr';

export const serverRoutes: ServerRoute[] = [
  {path: 'products', renderMode: RenderMode.Server},
  {path: '**', renderMode: RenderMode.Prerender},
];
The explain-render-mode agent tool tells you which ServerRoute and render mode a URL gets. See Tools.

Step 5: Inject a fault

Open the SSR & HTTP tab and go to Fault injection. Enter a URL pattern, for example /api/*. SSR + client, SSR only or Client only. Pick a status (for example 500 Internal Server Error), a delay, or a mock JSON body. Click Add rule. SSR rules apply from the next page load. Client rules apply right away.

How a rule answers

  • A status of 400 or more fails the request with an HttpErrorResponse.
  • A lower status returns the body as a mocked response.
SSR mocks are not written to TransferState, so the browser requests the URL again. Apply the rule on SSR + client to mock both.

Try it on the demo

The demo app has an SSR & HTTP example at /examples/http. It fetches /api/products during SSR and replays it from the transfer cache. The endpoint accepts ?delay= and ?fail= for backend errors.

pnpm build --configuration development
node dist/angular-devtools/server/server.mjs

Open http://localhost:4000/examples/http. See Demo apps for the rest.

Where to next