Web Page title, description, and other meta tags are very important for the Search Engine Optimization of any web application.
Meta tags provide information about the webpage. These tags are not visible to user but this information is used by web crawlers.
Search Engines like google and bing use web crawlers to index web pages.
Social Media Platforms like Facebook, Twitter, and LinkedIn web crawlers crawl the web page to show the card when we share the page link.
In the traditional web applications, we can add meta tags on each page, However in a single page application (SPA), we have only one page where other routes are dynamically rendered.
In Angular, if you want to set common meta information for all routes in the application, it is easy, you just need to write meta tags in index.html
.
But many times we required to set different meta information for different routes. So that it is indexed properly in search engines and when users share it on social media it shows meta-information for that page only.
This feature we can implement by manually changing meta information on route change.
In this article, we will see, Dynamically Add Title and Meta Tags on Route Change in Angular.
Angular SEO Series Articles
- Integrate Google Analytics in Angular Application
- Dynamically Add Title and Meta Tags On Route Change in Angular
I have built angular-got-universal web app to demonstrate this use case. In this application, I want to have a separate meta information for each primary route.
To implement this, We will add a dynamic title and meta tags on route change in this angular application so that it can be properly indexed by search engines and can be crawled by the social media crawlers.
So our final application output will look like as below,
This application has the following primary routes :
- /home
- /books
- /characters
We will also add open graph meta tags and twitter card meta tags for Facebook, Twitter, and LinkedIn sharing which improves the SEO.
As you can see in above video, Social media crawlers are able to crawl the web page.
Now to dynamically set Title and Meta Tags on route change We will follow the below steps :
- Create
SeoService
- Provide meta information in route
data
property - Update title and meta information on route change
Create SeoService
Create one angular service called SeoService
. We will create two methods in this service to set webpage title and meta tags.
Angular provides Title
and Meta
service in @angular/platform-browser
to set Page Title and Meta Tags. Inject these services in SeoService
.
Title service provides the following important methods :
getTitle()
: Get the title of the current HTML document.setTitle(newTitle: string)
: Set the title of the current HTML document.
Meta Service provides the following important methods :
addTag(tagDefinition : MetaDefinition, forceCreation?: boolean)
: Retrieves or creates a specific `< meta >
` tag element in the current HTML document.addTags(tags: MetaDefinition[], forceCreation?: boolean)
: Retrieves or creates a set of `< meta >
` tag elements in the current HTML document.getTag(attrSelector: string)
: Retrieves a `< meta >
` tag element in the current HTML document.getTags(attrSelector: string)
: Retrieves a set of `< meta >
` tag elements in the current HTML document.updateTag(tag: MetaDefinition, selector?: string)
: Modifies an existing `< meta >
` tag element in the current HTML document.removeTag(attrSelector: string)
: Removes an existing `< meta >
` tag element from the current HTML document.
We will use Title.updateTitle()
and Meta.updateMetatags()
in SeoService
.
So our final SeoService
will be :
import { Injectable } from '@angular/core'; import { Title, Meta, MetaDefinition } from '@angular/platform-browser'; @Injectable({ providedIn: 'root' }) export class SeoService { constructor(private title: Title, private meta: Meta) { } updateTitle(title: string){ this.title.setTitle(title); } updateMetaTags(metaTags: MetaDefinition[]){ metaTags.forEach(m=> this.meta.updateTag(m)); } }
Provide Meta Information In Route Data Property
We will provide the following meta information in the data
property of the route.
- Title
- Description
- Open Graph Tags:
- title
- description
- url
- image
- Twitter Card Tag
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { environment } from 'src/environments/environment'; const routes: Routes = [ { path: '', redirectTo: 'home', pathMatch: 'full' }, { path: 'home', loadChildren: () => import('./home/home.module').then(m => m.HomeModule), data: { seo: { title: 'Home Page | Dynamic Title and Meta Tags Demo', metaTags: [ { name: 'description', content: 'Game of Thrones Quotes : Winter is Coming, You know nothing Jon Snow, Never forget what you are. The rest of the world will not. Wear it like armour, and it can never be used to hurt you' }, { property: 'og:title', content: 'GOT Home Page ⚔' }, { proprety: 'og:description', content: 'Game of Thrones Quotes : Winter is Coming, You know nothing Jon Snow, Never forget what you are. The rest of the world will not. Wear it like armour, and it can never be used to hurt you' }, { property: 'og:image', content: environment.appUrl + 'assets/image/homepage.png' }, { property: 'og:url', content: environment.appUrl + 'home' }, { name: "twitter:card", content: "summary_large_image" }, ] } } }, { path: 'characters', loadChildren: () => import('./characters/characters.module').then(m => m.CharactersModule), data: { seo: { title: 'GOT Characters 🧔', metaTags: [ { name: 'description', content: 'List of all the characters from game of thrones' }, { property: 'og:title', content: 'GOT Characters 🧔' }, { proprety: 'og:description', content: 'List of all the characters from game of thrones' }, { property: 'og:image', content: environment.appUrl + 'assets/image/characters.png' }, { property: 'og:url', content: environment.appUrl + 'characters' }, { name: "twitter:card", content: "summary_large_image" }, ] } } }, { path: 'books', loadChildren: () => import('./books/books.module').then(m => m.BooksModule), data: { seo: { title: 'GOT Books 📚', metaTags: [ { name: 'description', content: 'List of all Game of Thrones books. A Game of Thrones, Clash of Kings, A Storm of Swords...' }, { property: 'og:title', content: 'Game of Thrones Books 📕' }, { proprety: 'og:description', content: 'List of all Game of Thrones books. A Game of Thrones, Clash of Kings, A Storm of Swords, The Hedge Knight, A Feast for Crows' }, { property: 'og:image', content: environment.appUrl + 'assets/image/books.png' }, { property: 'og:url', content: environment.appUrl + 'books' }, { name: "twitter:card", content: "summary_large_image" }, ] } } }]; @NgModule({ imports: [RouterModule.forRoot(routes, { initialNavigation: 'enabled' })], exports: [RouterModule] }) export class AppRoutingModule { }
Update Title and Meta Information On Route Change
Now in app.component.ts
, we will subscribe to the Router.events
observable. On NavigationEnd
event we will get the route data
using ActivatedRoute
and update the meta information by calling SeoService
methods. As below
import { Component } from '@angular/core'; import { SeoService } from './services/seo.service'; import { Router, NavigationEnd, ActivatedRoute } from '@angular/router'; import { filter, map, mergeMap, tap } from 'rxjs/operators'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'got-prerender-demo'; constructor(private router: Router, private activatedRoute: ActivatedRoute, private seoService: SeoService) { } ngOnInit(): void { this.router.events.pipe( filter(e => e instanceof NavigationEnd), map(e => this.activatedRoute), map((route) => { while (route.firstChild) route = route.firstChild; return route; }), filter((route) => route.outlet === 'primary'), mergeMap((route) => route.data), ).subscribe(data => { let seoData = data['seo']; this.seoService.updateTitle(seoData['title']); this.seoService.updateMetaTags(seoData['metaTags']); }); } }
Great ✨✨✨ We are done with the implementation of dynamically adding title and meta tags. Now serve your application and test it.
Though some of the search engines like google can compile the JavaScript and can get the dynamically added meta-information
But most of the other search engine and social media web crawlers like Facebook debugger, Linkedin Post Inspector, and Twitter Card Validator doesn’t crawl these dynamically added meta information.
So to add support for these crawlers we need to implement angular server-side rendering or prerendering.
👉 Checkout Angular Universal Series Articles
- Implement Angular Server Side Rendering
- Prerender Angular Application using Angular Universal Prerenderer
Once Angular SSR or Prerendering is implemented, We will deploy our application. I have deployed my application on heroku.
🚀 Checkout Live Web Application With Dynamic Title and MetaTags on Route Change and Angular SSR: 🌐 https://angular-got-universal.herokuapp.com
👉 Facebook Sharing Debugger Result: Checkout debugger result here
👉 LinkedIn Post Inspector Result: Checkout post inspector result here
👉 Twitter Card Validator Result: Checkout Live Result Here
👉 PageSpeed Insights Result
In this article, We have seen :
Steps to do Search Engine Optimization by Dynamically Adding Title and Meta Tags on Route Change in Angular Application.
We have also added Open Graph Meta Tags and Twitter Card Tags for Social Media Sharing.
I hope you like this article, please provide your valuable feedback and suggestions in below comment section🙂.
For more updates, Follow us 👍 on NgDevelop Facebook page.