Angular SEO
Angular SEO is a big deal, because SEO (Search Engine Optimization) is what will bring visitors to your website, it’s nice to use SPAs (Single Page Applications) but of course it will be bad if you use them and lose your rank in search engines.
As we were speaking in the previous post Angular Universal Applications, we need to convert our website to an Angular Universal App in order to be able to deal with SEO.
Ok what should we do?
Assuming you already have an Angular Universal App, if no, refer to Angular Universal Applications
Let’s create a new component ‘About’ and create a route for it /about, to do so:
- Create a new component using
ng g c about
- Create a new component using
ng g c
contact - Head to
app-routing.module.ts
and add the new routes in the routes array like so
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AboutComponent } from './about/about.component';
import { ContactComponent } from './contact/contact.component';
const routes: Routes = [
{ path: 'about', component: AboutComponent },
{ path: 'contact', component: ContactComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
In the app.component.html
add a router-outlet
to the html to allow us to navigate through different pages, and also we need to add some links/anchors to our new components.. like so:
<h1>
Welcome To {{title}}
</h1>
<ul>
<li>
<a [routerLink]="['/about']" routerLinkActive="router-link-active">About</a>
</li>
<li>
<a [routerLink]="['/contact']" routerLinkActive="router-link-active">Contact</a>
</li>
</ul>
<router-outlet></router-outlet>
Let’s see our resulting HTML now
PERFECT !!
Now, we have two components, About and Contact, and two links that navigate to those pages.
Let’s try to add meta tags to our pages … but first ….. what are meta tags?
From w3schools:
The
<meta>
tag defines metadata about an HTML document. Metadata is data (information) about data.
<meta>
tags always go inside the <head> element, and are typically used to specify character set, page description, keywords, author of the document, and viewport settings.Metadata will not be displayed on the page, but is machine parsable.
Metadata is used by browsers (how to display content or reload page), search engines (keywords), and other web services.
There is a method to let web designers take control over the viewport (the user’s visible area of a web page), through the
<meta>
tag (See “Setting The Viewport” example below).
So … Search Engines use Meta Tags to fetch info and data about our pages, and they use it to show rich search results for our pages as well as knowing information about our pages.
Some of the most important meta tags are:
<meta name="description" content="Dumping (maybe useful) technical 💩 in here" class="yoast-seo-meta-tag" />
<meta property="og:locale" content="en_US" class="yoast-seo-meta-tag" />
<meta property="og:type" content="website" class="yoast-seo-meta-tag" />
<meta property="og:title" content="Joseph Amirhom" class="yoast-seo-meta-tag" />
<meta property="og:description" content="Dumping (maybe useful) technical 💩 in here" class="yoast-seo-meta-tag" />
<meta property="og:url" content="https://josepham.me/" class="yoast-seo-meta-tag" />
<meta property="og:site_name" content="Joseph Amirhom" class="yoast-seo-meta-tag" />
Let’s write some code that sets the og:description and og:title tags
We will need to head to our component.ts files for the About and Contact components and add that line
this.meta.addTag({ property: 'og:title', name: 'og:title', content: 'Contact Page' });
to look like this finally:
For Contact Component
import { Component } from '@angular/core';
import { Meta } from '@angular/platform-browser';
@Component({
selector: 'app-contact',
templateUrl: './contact.component.html',
styleUrls: ['./contact.component.css']
})
export class ContactComponent {
constructor(private meta: Meta) {
this.meta.addTag({ property: 'og:title', name: 'og:title', content: 'Contact Page' });
this.meta.addTag({ property: 'og:description', name: 'og:description', content: 'This is the Contact Page' });
}
}
For About Component
import { Component } from '@angular/core';
import { Meta } from '@angular/platform-browser';
@Component({
selector: 'app-about',
templateUrl: './about.component.html',
styleUrls: ['./about.component.css']
})
export class AboutComponent {
constructor(private meta: Meta) {
this.meta.addTag({ property: 'og:title', name: 'og:title', content: 'About Page' });
this.meta.addTag({ property: 'og:description', name: 'og:description', content: 'This is the About Page' });
}
}
If you open the developer tools in your browser (ie: Chrome) you shall find your HTML looking like this
But .. Try navigating to the about page…
You will find it looking like this
We now have an issue, we have duplicate meta tags for different pages… ok, how can we overcome this?
We can create a service that helps us removing old meta tags and adding new ones.
Let’s create a service called meta.service.ts and create a method in it that removes/adds the meta tags for us.
import { Injectable } from '@angular/core';
import { Meta } from '@angular/platform-browser';
@Injectable({providedIn: 'root'})
export class MetaService {
constructor(private meta: Meta) { }
addMetaTag(key: string, value: string) {
this.meta.removeTag(`name='${key}'`);
this.meta.addTag({ name: key, content: value, property: key});
}
}
Now, let’s try to use it in our components
// About Component
import { Component } from '@angular/core';
import { MetaService } from '../mets.service';
@Component({
selector: 'app-about',
templateUrl: './about.component.html',
styleUrls: ['./about.component.css']
})
export class AboutComponent {
constructor(private metaService: MetaService) {
this.metaService.addMetaTag('og:title', 'About Page');
this.metaService.addMetaTag('og:description', 'This is the About Page');
}
}
You will find it now fixed
Let’s have a look between SSR and CSR in meta tags
CSR:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Angularseo</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="styles.css"></head>
<body>
<app-root></app-root>
<script src="runtime.js" type="module"></script><script src="polyfills.js" type="module"></script><script src="styles.js" defer></script><script src="vendor.js" type="module"></script><script src="main.js" type="module"></script></body>
</html>
SSR:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Angularseo</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="styles.css" media="print" onload="this.media='all'">
<noscript>
<link rel="stylesheet" href="styles.css">
</noscript>
<meta name="og:title" content="About Page" property="og:title">
<meta name="og:description" content="This is the About Page" property="og:description">
</head>
<body>
<app-root _nghost-sc3="" ng-version="15.2.9" ng-server-context="ssr">
<h1 _ngcontent-sc3=""> Welcome To Angular SEO</h1>
<ul _ngcontent-sc3="">
<li _ngcontent-sc3=""><a _ngcontent-sc3="" routerlinkactive="router-link-active" ng-reflect-router-link-active="router-link-active" ng-reflect-router-link="/about" href="/about" class="router-link-active">About</a></li>
<li _ngcontent-sc3=""><a _ngcontent-sc3="" routerlinkactive="router-link-active" ng-reflect-router-link-active="router-link-active" ng-reflect-router-link="/contact" href="/contact">Contact</a></li>
</ul>
<router-outlet _ngcontent-sc3=""></router-outlet>
<app-about _nghost-sc1="">
<p _ngcontent-sc1="">about works!</p>
</app-about>
<!--container-->
</app-root>
<script src="runtime.js" type="module"></script><script src="polyfills.js" type="module"></script><script src="vendor.js" type="module"></script><script src="main.js" type="module"></script>
</body>
</html>
Notice that:
<meta name=”og:title” content=”About Page” property=”og:title”>
<meta name=”og:description” content=”This is the About Page” property=”og:description”>
Are available only in SSR mode and not in CSR
Well, yea .. and that’s pretty much SEO in Angular using SSR and Angular Universal 🔮🪄🧙♂️
In the next post, we will speak more about making HTTP requests on the server and not on the client, for SEO purposes also.
I hope that was helpful, and also you can find all the code on github on this repo
And ,, if for any reason, it wasn’t so helpful for you, here’s a Magical Potato