One of SPA’s (single page application) issues is poor indexing in search engines and search optimization in general. Specifically, because Сlient-side rendering typical for JavaScript SPAs isn’t optimal for SEO. Indexing crawlers may not always run the JavaScript code so the content may remain ignored. That is why you should implement SSR (server-side rendering) to render the content on the server rather than on the client side, thus, help the crawlers index it.

Another part of SEO activities for web application development that can be managed by the programmer is improving the site info appearance in Google earch results so it catches the eye. Structured info blocks draw the user’s attention better than an unordered piece of text. Google provides a set of rules on creating neat text snippets - this is what we’ll talk about in this article.

As you might notice, we at Valor Software love Angular ), not to mention that it’s one of the three most popular JavaScript frameworks. In this article, we’re going to mimic building an Angular app template, so be ready to dive into some code examples.

What is Structured data?

Structured data is a format for presenting data suggested by schema.org standards. When you create app components using a Structured data format, you’ll be able to customize the search results view. The search robots parse the structured data and show your site in a more detailed and organized view, as rich snippets (also known as rich results). Also, the more organized the data structure is (in this context, according to the Structured data principles), the better your chances are to improve your rankings.

Note: Using Structured data is an additional instrument to create an SEO-friendly app, while applying standard SEO features like meta descriptions or title tags is still crucial.

Examples of rich snippets in Google search results
Examples of rich snippets - you’ll find the one to present your specific content.

Google Search supports three formats of Structured data (JSON-LD, Microdata, RDFa), but recommends using JSON-LD. Moreover, this format suits SPA development the best since Google can read JSON-LD data when it’s dynamically injected into the page’s contents, particularly by JavaScript. While Microdata and RDFa make use of characteristic HTML tag attributes.

How to use Structured data?

Preliminary work

While the crawlers are unfriendly to dynamic content and SPAs are dynamically generated by JavaScript on the fly, SEO for SPAs seems to be an issue. However, we have an SSR to assist us. With the help of SSR, web crawlers get not only an index.html file with the app-root component but a pre-generated HTML page with the entire component delivered by the SSR mechanism.

Note: The solution (specifically, code examples) we describe in this article won’t work if SSR isn’t going to be set up for your project. In the case of Angular applications as a topic of this article, we recommend that you build the server-side rendering part using the most popular SSR technology for Angular - Universal.

Adding JSON-LD format

To use JSON-LD format in your code, you’ll usually add a &lt script&gt tag in the page head or body. However, since Angular removes any &lt script&gt tags from templates, you’ll need to utilize DOMSanitizer service. You’ll notice how &lt script type="application/ld+json"&gt is interpreted via getSafeHTML in our example of injecting JSON-LD as a component:

import { Component, OnInit } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { productLD } from '../product';
@Component({
    selector: 'app-my-json-ld',
    template: '<div [innerHTML]="html"></div>',
    styles: []
})
export class MyJsonLdComponent implements OnInit {
    itemLD = productLD;
    html: SafeHtml;
    constructor(private sanitizer: DomSanitizer) { }
    ngOnInit() {
        this.html = this.getSafeHTML(this.itemLD);
    }
    getSafeHTML(jsonLD: {[key: string]: any}): SafeHtml {
        const json = jsonLD ? JSON.stringify(jsonLD, null, 2).replace(/</script>/g, '<\/script>') : '';
        // escape / to prevent script tag in JSON
        const html = `<script type="application/ld+json">${json}</script>`;
        return this.sanitizer.bypassSecurityTrustHtml(html);
    }
}

Another option of implementing JSON-LD format in your project is to insert @ngx-lite/json-ld component created by Cory Rylan, Google Developer Expert for Angular and Web.

Building Structured data

So, applying Structure data format is all about achieving a user-friendly data view in search results - less but well-structured info is better than presenting all the available details.

Here’s an example of the well-structured snippet for product details:

export const productLD = {
    "@context": "http://schema.org/",
    "@type": "Product",
    "name": "Some tech product",
    "image": "http://lorempixel.com/output/technics-q-c-640-480-3.jpg",
    "description": "Descriprion for tech product.",
    "mpn": "123450",
    "brand": {
        "@type": "Thing",  "name": "Brand Name"
    },
    "aggregateRating": {
        "@type": "AggregateRating",
        "ratingValue": 5,
        "reviewCount": 50
    },
    "offers": [
        {
            "@type": "Offer",
            "availability": "InStock",
            "priceCurrency": "USD",
            "price": 9.99,
            "url": "http://lorempixel.com/output/technics-q-c-640-480-0.jpg",
            "sku": 9999,
            "mpn": "123456",
            "priceValidUntil": "2020-07-05T00:00:00.000Z"
        },
        {
            "@type": "Offer",
            "availability": "InStock",
            "priceCurrency": "USD",
            "price": 9.99,
            "url": "http://lorempixel.com/output/technics-q-c-640-480-1.jpg",
            "sku": 9998,
            "mpn": "123457",
            "priceValidUntil": "2020-07-05T00:00:00.000Z"
        },
        {
            "@type": "Offer",
            "availability": "InStock",
            "priceCurrency": "USD",
            "price": 9.99,
            "url": "http://lorempixel.com/output/technics-q-c-640-480-2.jpg",
            "sku": 9997,
            "mpn": "123458",
            "priceValidUntil": "2020-07-05T00:00:00.000Z"
        }
    ],
    "sku": 1234,"review": {
        "@type": "Review",
        "author": "John S.",
        "reviewBody": "Really good product, can't wait to order one more."
    }
}

Check the entire structure of the product component files posted on StackBlitz.com

Testing the result

You might wonder how your website would look like in search results. Google developers covered that as well.

Structured Data Testing Tool allows you to upload either a URL or a code snippet and check a search result preview even before deployment.

Preview of our product snippet in Google search results
The preview of our product snippet in Google search results.

After deployment, Rich result status reports tool will help you to check up on the flawless site operation. If the report shows any issues, you can request a recrawl after fixing them. Remember that recrawl can take up to several days.

Conclusion

SEO and SPAs aren’t good friends. Web applications built on JavaScript platforms perform worse in Google search results than websites delivering plain HTML to the crawler.

So if you’re building a JavaScript app, you’ll need to help Google on ranking your site. Be sure to consider SSR and Structured data formatting to adapt the result view of the site for different types of projects. Also, Structured data formatting influences the search engine’s understanding of content, therefore, it can help with relevance signals. Besides, Google provides tools to test your results.

We showed the example of building an Angular product description template according to Structured data principles. Go ahead and try more rich snippets to represent features like articles or job postings.

We hope this helps you build SEO-friendly Angular apps! :) If you have already implemented structured data, we’d love to hear your feedback.