Angular HTTP Interceptors: What They Are and How to Use Them

Angular HTTP interceptors allow developers to handle request and response actions centrally, making it easier to manage headers, logging, and error handling across an application.

Accelerate Your Software Development

Hire Skilled Developers from eSparkBiz to build scalable and secure solutions.

  • Agile Methodology
  • 400+ Skilled Engineers
  • Flexible Models
  • Time Zone Aligned
  • Fully Signed NDA
  • Easy Exit Policy

Quick Summary :- This blog gives a clear insight into the Angular HTTP Interceptors and the ways of using them. It starts with introducing HTTP Interceptors and some common use cases of them. It discusses creating basic HTTP interceptors and ways to create them on Angular. In the latter stage, it discusses the ways to use them to manage HTTP requests.

Angular supports modern Single Page Applications by enabling dynamic content updates without full page reloads. Within the AngularJS framework, HTTP interceptors help manage request behavior consistently, improving application reliability and control at the network layer.

frontend framework tools

Industry usage data shows over 105,798 companies rely on frontend framework tools. Angular leads with 48.11% market share and 50,900 customers, followed by Materialize at 25.61% with 27,092 users, and CreateJS at 7.39% with 7,820 customers.

What is an Angular HTTP Interceptor

This mechanism gives applications a consistent way to manage common request-related actions, helping streamline communication between the browser and external services.

HttpInterceptor came along with Angular 4.3. It gives us a way to intercept HTTP requests and responses to transform or handle them before passing them along.

As per Angular Docs, “Although Angular HTTP Interceptors are capable of mutating requests and responses, the HttpRequest and HttpResponse instance properties are read-only, rendering them largely immutable.”

This may be due to the fact that we should try to retry a request, in case it is unsuccessful at first.

Angular Docs goes on to say “Angular applies interceptors in the order that you provide them. If you provide interceptors A, then B, then C, requests will flow in A->B->C and responses will flow out C->B->A.

You cannot change the order or remove Angular Interceptors later. If you need to enable and disable an interceptor dynamically, you’ll have to build that capability into the interceptor itself. “

You must keep this in mind when using multiple Angular HTTP Interceptors.

Common Use Cases of Interceptors

Interceptors are methods to do some work for every HTTP request. Here are a few examples of common use cases for interceptors:

  • Add a token or some custom HTTP header for all outgoing HTTP requests
  • Catch HTTP responses to do custom formatting (i.e. convert CSV to JSON) before transferring the data to your service/component
  • Log all HTTP activity in the console
Implementing HTTP Interceptors in Angular Applications?

eSparkBiz helps design and integrate interceptors for security, logging, and error handling.

Talk to Our Experts

How to Create a Basic HTTP Interceptor in Angular

This section explains the steps involved in setting up a simple HTTP interceptor, covering registration, request handling, and response flow without introducing unnecessary complexity or advanced configurations.

Creating A Service

To start things off, you must create a service that implements HttpInterceptor.

import { HttpInterceptor} from '@angular/common/http';
import { Injectable } from '@angular/core';@Injectable()
export class TokenInterceptorService implements HttpInterceptor {   intercept(req: HttpRequest<any>, next: HttpHandler):   Observable<HttpEvent<any>> {
       // All HTTP requests are going to go through this method
   }
}

To call that interceptor, it has to be added to the list of all HTTP_INTERCEPTORS:

@NgModule({
  ...
  providers: [ {provide: HTTP_INTERCEPTORS, useClass: TokenInterceptorService, multi: true}]})
export class AppModule { }

Since there could be a varied number of interceptors, we give our interceptor service with “multi:true”

Intercepting a Request

Once we have set-up our interceptor, we need to implement the intercept method to handle a token. An HTTP header is added, If our LoginService has a auth token:

export class TokenInterceptorService implements HttpInterceptor {
      // We inject a LoginService
   constructor(private loginService: LoginService) {}   intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {      console.log('INTERCEPTOR');
      // We retrieve the token, if any
      const token = this.loginService.getAuthToken();
      let newHeaders = req.headers;
      if (token) {
         // If we have a token, we append it to our new headers
         newHeaders = newHeaders.append('authtoken', token);
      }
      // Finally we have to clone our request with our new headers
      // This is required because HttpRequests are immutable
      const authReq = req.clone({headers: newHeaders});      // Then we return an Observable that will run the request
      // or pass it to the next interceptor if any
      return next.handle(authReq);
   }
}

Thus, every time you make an HTTP request, the code will automatically add that header.

Intercepting a Response

This is done through the same intercept method in our Angular HTTP Interceptors. The difference is that the work we want to do with the response has to be registered as a side-effect on the Observable we return from the intercept method.

In simple terms, this means that when we work with an HTTP response, we have to use RxJs operators and the Pipe Method, to simplify the process hire angularjs developer for enhanced results.

return next.handle(authReq).pipe(
// Do custom work here
);

Further to this, we have shown how this can be done by replacing the HTTP response with some fake data for testing purposes only:

return next.handle(authReq).pipe(
// We use the map operator to change the data from the response
map(resp => {
// Several HTTP events go through that Observable
// so we make sure that this is an HTTP response
if (resp instanceof HttpResponse) {
// Just like for request, we create a clone of the response
// and make changes to it, then return that clone
return resp.clone({ body: [{title: 'Replaced data in interceptor'}] });
}
})
);

How Are HTTP Interceptors Used in Angular Applications

This approach provides a centralized way to influence how application requests behave, helping teams maintain consistency and control as projects grow in size and complexity.

Authentication

Having a well-established authentication system in place is essential for Angular Interceptors. It can be used for:

  • Adding bearer tokens
  • Adding refresh tokens
  • Redirecting to the login page

When sending the bearer token, some filtering is required. In case we don’t have a token, then it’s possible that we’re logging in, and do not have a token.

Caching

Caching

It i important to note that there are some interceptors that can handle requests by themselves. They do not need forwarding to next.handle() and we can use them for caching requests.

We do this by using the URL to key in our cache. We can then return an observable if we find a response in the map, by-passing the “next” handler.

You can also improve your performance by doing so, as you don’t have to access the backend when you already have the response cached for Interceptor Angular.

import { Injectable } from '@angular/core';
  import { HttpEvent, HttpRequest, HttpHandler, HttpInterceptor, HttpResponse } from '@angular/common/http';
  import { Observable, of } from 'rxjs';
  import { tap, shareReplay } from 'rxjs/operators';
  
  @Injectable()
  export class CacheInterceptor implements HttpInterceptor {
    private cache = new Map<string, any>();
  

      intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
      if (request.method !== 'GET') {
        return next.handle(request);
      }
  
        const cachedResponse = this.cache.get(request.url);
      if (cachedResponse) {
        return of(cachedResponse);
      }
  
        return next.handle(request).pipe(
        tap(event => {
          if (event instanceof HttpResponse) {
            this.cache.set(request.url, event);
          }
        })
      );
    }
  }

If you run the request, then click clear response, and then run again, you will use the cache.

Fake Backend

In case you don’t have a backend ready, a fake one can be utilised for development. All you have to do is mock the Response depending on the request, and then return an Observable to HttpResponse.

const body = {
  firstName: "Mock",
  lastName: "Faker"
};return of(new HttpResponse(
  { status: 200, body: body }
));

Profiling

Angular HTTP Interceptors can log an entire HTTP operation due to the fact that they can process the request and respond together.

We can then get the timing of the request and the response and log the outcome with the time taken.

const started = Date.now();
  let ok: string;
  
    return next.handle(req).pipe(
    tap(
      (event: HttpEvent<any>) => ok = event instanceof HttpResponse ? 'succeeded' : '',
      (error: HttpErrorResponse) => ok = "failed"
    ),
    // Log when response observable either completes or errors
    finalize(() => {
      const elapsed = Date.now() - started;
      const msg = `${req.method} "${req.urlWithParams}" ${ok} in ${elapsed} ms.`;
      console.log(msg);
    })
  );

Errors

The use of errors can be implemented in two instances in the Angular HTTP Interceptors. For instance, network interferences are many in mobile situations, and attempting again may finally be victorious. This is important for Interceptor Angular.

Interesting points here are how frequently to retry before surrendering. Also, would it be advisable for us to hold up before retrying or do it right away?

One way is to retry the HTTP call. To get this done, we can use the retry operator from RxJS which can help us re-subscribe to the observable. This will reissue the request.

Otherwise, you can use the status of the exception. What you do, will depend on this.

return next.handle(req).pipe(
    retry(2),
    catchError((error: HttpErrorResponse) => {
      if (error.status !== 401) {
        // 401 handled in auth.interceptor
        this.toastr.error(error.message);      
      }
      return throwError(error);
    })
  );

Before checking the error status in the example below, we retry twice. In the case of no 401 error, we show the error as a popup. All the other errors are then re-thrown for handling.

Notifications

Here, we have a wide range of situations where we could show messages. In the example below, “OBJECT CREATED” is shown each time we get a 201 status over from the server.

return next.handle(req).pipe(
    tap((event: HttpEvent<any>) => {
      if (event instanceof HttpResponse && event.status === 201) {
        this.toastr.success("Object created.");
      }
    })
  );

To check the type of object, we can show “TYPE CREATED”. We can also show more precise messages, by wrapping our data in an object together with a message.

Headers

Here are a few things that can be accomplished by manipulating headers:

  • Authentication/authorization
  • Caching behavior; for example, If-Modified-Since
  • XSRF protection

Here is how you can add a header to the request in the interceptor:

const modified = req.clone({
  setHeaders: { "X-Man": "Wolverine" }
});return next.handle(modified);

Angular uses interceptors for insurance against Cross-Site Request Forgery (XSRF). It does this by perusing the XSRF-TOKEN from a cookie and setting it as the X-XSRF-TOKEN HTTP header.

Since the cookie can be read-only by the code that runs on your domain, the backend can be certain that the HTTP demand originated from your customer application and not an assailant.

Converting

At the point when the API restores an arrangement we don’t concur with, we can utilize an interceptor to design it the manner in which we like it.

This could be changing over from XML to JSON or like in this model property names from PascalCase to camelCase. We can also utilize an interceptor to rename all the property names to camelCase.

Check if there is an npm bundle that can do the truly difficult work for you. In the example below, we are utilizing mapKeys and camelCase from lodash.

return next.handle(req).pipe(
    map((event: HttpEvent<any>) => {
      if (event instanceof HttpResponse) {
        let camelCaseObject = mapKeys(event.body, (v, k) => camelCase(k));
        const modEvent = event.clone({ body: camelCaseObject });
        
        return modEvent;
      }
    })
  );

Loader

You could set up a loader centrally in an interceptor so that it shows up whenever there are active requests. You can use a “loader service” for this, and make sure that it has a show and hide function.

const loaderService = this.injector.get(LoaderService);
  loaderService.show();
    return next.handle(req).pipe(
    delay(5000),
    finalize(() => loaderService.hide())
  );

We should consider that there could be numerous HTTP calls intercepted. This could be worked through, by having a counter for requests (+1) and responses (- 1).

URL

Below, let’s see how easy or difficult it is to manipulate the URL. Let us take for instance if you want to change HTTP to HTTPS. You can use cloning and replacing, and send the cloned request to the next handler.

// clone request and replace 'http://' with 'https://' at the same time
  const httpsReq = req.clone({
    url: req.url.replace("http://", "https://")
  });
  return next.handle(httpsReq);

Using Angular Interceptors to Manage HTTP Requests

The Angular Interceptor was introduced in version 4.3. It is used to handle HTTP responses and requests.

Prerequisites

Before you begin, however, make sure you have Node.JS installed locally. Check  this link to see how you can do that. You must also be well-versed with Angular CLI to create Angular apps.

Creating the Angular App

Use the Angular CLI to generate a new project. Run the following command to create an application named Angular-Interceptor:

npx @angular/cli new Angular-Interceptor

Output

Would you like to add Angular routing? Yes

Which stylesheet format would you like to use? SCSS   [ http://sass-lang.com   ]

Now, you must go to your new project directory and serve the project:

  • cd Angular-Interceptor
  • npx ng serve –open

To view the app, view http://localhost:4200  in your browser. This is now, your basic Angular app.

Styling the Angular App

Once you’ve done the basics, styling will help you make the user experience better.

From the get-go, you will require an Angular Material component. You can find detailed instructions for the Angular Material , which will guide you through the process step by step.

ng add @angular/material

The next step will be to add animations. To do this, you must open the src/app/app.module.ts file in your code editor and add the code given below to import BrowserAnimationsModule:

src/app/app.module.ts

...

import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

@NgModule({

  ...

  imports: [

    ...

    BrowserAnimationsModule

  ],

  ...

})

export class AppModule { }

Once this is done, add the following code to import the MatDialogModule in your src/app/app.module.ts file:

src/app/app.module.ts

...

import { MatDialogModule } from '@angular/material';

@NgModule({

  ...

  imports: [

    ...

    MatDialogModule

  ],

  ...

})

export class AppModule { }

To make the UI even better, you can add a theme to it. Add indigo-pink.css to your styles.scss file:

src/styles.scss

@import "~@angular/material/prebuilt-themes/indigo-pink.css";

Creating an Angular Interceptor

Creating an Angular Interceptor

Now that the app is stylized, you must create the Angular HTTP Interceptors. To do this, begin with making a new folder for the interceptor, under the app folder.

You can then make a new file – httpconfig.interceptor.ts under the Angular Interceptors folder. Then you must import the dependence given below into this file:

src/app/intreceptor/httpconfig.interceptor.ts

import { Injectable } from '@angular/core';

import {

    HttpInterceptor,

    HttpRequest,

    HttpResponse,

    HttpHandler,

    HttpEvent,

    HttpErrorResponse

} from '@angular/common/http';

import { Observable, throwError } from 'rxjs';

import { map, catchError } from 'rxjs/operators';

Now, you must create a class and implement the interface. For instance,

@Injectable()

export class HttpConfigInterceptor implements HttpInterceptor {

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

      // ...

    }

}

Next, set-up a token, Content-Type, Accept type for an API request. You will find an example below:

const token: string = localStorage.getItem('token');

request = request.clone({ headers: request.headers.set('Authorization', 'Bearer ' + token) });

request = request.clone({ headers: request.headers.set('Content-Type', 'application/json') });

request = request.clone({ headers: request.headers.set('Accept', 'application/json') });

Here is how you can handle the API response:

map((event: HttpEvent<any>) => {

    if (event instanceof HttpResponse) {

        console.log('event--->>>', event);

    }

    return event;

}),

The next move would be to import the httpconfig.interceptor.ts in your AppModule.

src/app/app.module.ts

...

import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';

...

import { HttpConfigInterceptor } from './interceptor/httpconfig.interceptor';

@NgModule({

  ...

  imports: [

    ...

    HttpClientModule

  ],

  ...

})

Once done, add HttpConfigInterceptor to providers.

Creating a Service for Error Handling Presently, you will make the errorDialogService to deal with errors and show the error message for the user.

Make another error dialog under the application folder. Here, you can make your errorDialogService files.

To deal with the error response, make another errordialog.service.ts record and include the code beneath:

src/error-dialog/errordialog.service.ts

import { Injectable } from '@angular/core';

import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';

import { ErrorDialogComponent } from './errordialog.component';

@Injectable()

export class ErrorDialogService {

    public isDialogOpen: Boolean = false;

    constructor(public dialog: MatDialog) { }

    openDialog(data): any {

        if (this.isDialogOpen) {

            return false;

        }

        this.isDialogOpen = true;

        const dialogRef = this.dialog.open(ErrorDialogComponent, {

            width: '300px',

            data: data

        }); 

        dialogRef.afterClosed().subscribe(result => {

            console.log('The dialog was closed');

            this.isDialogOpen = false;

            let animal;

            animal = result;

        });

    }

}

Next, we need to display the dialog for the users. To this end, create errordialog.component.ts

src/error-dialog/errordialog.component.ts

import { Component, Inject } from '@angular/core';

import { MAT_DIALOG_DATA } from '@angular/material';

@Component({

  selector: 'app-root',

  templateUrl: './errordialog.component'

})

export class ErrorDialogComponent {

  title = 'Angular-Interceptor';

  constructor(@Inject(MAT_DIALOG_DATA) public data: string) {}

}

The next step is to create the errordialog.component template

src/error-dialog/errordialog.component

<div>

    <div>

        <p>

            Reason: {{data.reason}}

        </p>

        <p>

            Status: {{data.status}}

        </p>

    </div>

</div>

Another visit to httpconfig.interceptor.ts is required to handle the error response. You can begin by importing errordialog.service:

import { ErrorDialogService } from '../error-dialog/errordialog.service';

Add a constructor for errorDialogService:

constructor(public errorDialogService: ErrorDialogService) { }

Use this code handle the error response with catchError and throwError:

catchError((error: HttpErrorResponse) => {

    let data = {};

    data = {

        reason: error && error.error && error.error.reason ? error.error.reason : '',

        status: error.status

    };

    this.errorDialogService.openDialog(data);

    return throwError(error);

})

Now you can import errordialog.service and errordialog.component into the AppModule:

src/app/app.module.ts

...

import { ErrorDialogComponent } from './error-dialog/errordialog.component';

...

import { ErrorDialogService } from './error-dialog/errordialog.service';

...

@NgModule({

  ...

  declarations: [

    ...

    ErrorDialogComponent

  ],

  ...

  providers: [

    ...

    ErrorDialogService

  ],

  entryComponents: [ErrorDialogComponent],

})

Creating a Service File for HTTP Requests

For this, you will need two things – a login API and a Customer Detail API.

You must first create a new “services” folder under the “src” folder. Then, under the “services” folder, make a new login.service.ts file. Add the functions below for the two APIs:

src/services/login.service.ts

import { Injectable } from '@angular/core';

import { HttpClient } from '@angular/common/http'; 

@Injectable()

export class LoginService {

    constructor(private http: HttpClient) { }

    login(data) {

        data = { email: 'admin', password: 'admin' };

        return this.http.post('http://localhost:3070/api/login', data);

    } 

    getCustomerDetails() {

        return this.http.get('http://localhost:3070/customers/details');

    } 

}

Also Read: Popular Angular Frameworks Developers Should Know in 2026

Invoking HTTP Client Service

To invoke the HTTP client service in the app component, you must add the two “LoginService” functions to it.  Call the login API with onload and the customers/details with onclick.

src/app/app.component.ts

import { Component } from '@angular/core';

import { LoginService } from './services/login.service';

@Component({

  selector: 'app-root',

  templateUrl: './app.component',

  styleUrls: ['./app.component.scss']

})

export class AppComponent {

  title = 'Angular-Interceptor';

  constructor(public loginService: LoginService) {

    this.loginService.login({}).subscribe(data => {

      console.log(data);

    });

  }

  getCustomerDetails() {

    this.loginService.getCustomerDetails().subscribe((data) => {

      console.log('----->>>', data);

    });

  }

}

Remember to include the element for the user to click on in app.component:

src/app/app.component

...

<h2 (click)="getCustomerDetails()">Get customer details</h2>

Now you can add LoginService to providers in your AppModule:

src/app/app.module.ts

...

import { LoginService } from './services/login.service';

...

@NgModule({

  ...

  providers: [

    ...

    LoginService

  ]

  ...

})

Conclusion

Angular HTTP interceptors remain a core feature in Angular version 21, providing a reliable way to manage request behavior and maintain consistency across applications as codebases scale and evolve.

For any angular development company, staying aligned with Angular practices ensures better maintainability, predictable application behavior, and long-term compatibility with ongoing framework updates.

Want More Control Over Angular HTTP Requests?

Standardize API behavior across your Angular application.

Improve Request Flow

Frequently Asked Questions

What does multi: true mean in HTTP interceptor?

The multi: true option allows multiple HTTP interceptors to be registered simultaneously. This ensures that each interceptor, such as logging, authentication or error handling, executes sequentially without overwriting others in enterprise Angular applications.

What is a token interceptor in Angular?

A token interceptor automatically attaches authentication tokens to outgoing API requests. It ensures secure, consistent access control across multiple services, reducing manual header management and supporting session validation in enterprise web applications.

What is the difference between Http and HttpClient in Angular?

HttpClient replaces the older Http module, offering simpler methods, typed responses and built-in support for interceptors, headers and error handling. It improves efficiency and reliability for performing HTTP requests in modern Angular applications.

When should developers use HTTP interceptors in enterprise applications?

Use interceptors to attach authentication tokens, handle session expiration, log API errors or enforce consistent request headers. They reduce code duplication and centralize request handling in enterprise web apps or microservices architectures.

What are common pitfalls when using Angular HTTP interceptors?

Avoid intercepting unnecessary requests, creating infinite loops or performing heavy synchronous tasks inside intercept. Use careful error handling, async operations and selective request targeting to maintain application performance and stability.