Enrich search engine search results with json-ld schema (structured data)

Applicable To: Website/Webpage
Updated: Wed 15 Jun, 2016 GMT

JSON-LD is a way of providing structured data to the search engines and thus potentially increase your search traffic, enrich and enhance the search results which results in prominent and beautiful rendering of search results and flexible user experience.

Preview

Though we are talking about JSON-LD, probably the most accurate technical keyword in this context would be Structured Data. Let's see what Google says about structured data:

"Structured data markup" is a standard way to annotate your content so machines can understand it. When your web pages include structured data markup, Google (and other search engines) can use that data to index your content better, present it more prominently in search results, and surface it in new experiences like voice answers, maps, and Google Now.

There are several ways of presenting structured data to the search engines:

  1. Microdata markup
  2. RDFa
  3. JSON-LD

Why I chose JSON-LD?

JSON-LD (JavaScript Object Notation Linked Data) is a cool way of presenting structured data to the search engine to make it easy for the search engines to better understand the content and context of your web pages. While other methods require you to change your HTML markup!!! JSON-LD requires you to insert all the data in a JSON format inside a <script> tag.

About using microdata, just think about the workload of modifying hundreds or thousands of HTML contents and inserting microdata markup into them. I can't even think about it.

Using microdata becomes a little easier if you are aware of this from the beginning when your are writing the content though. But still it's a huge pain. People don't really write webpages using core HTML tags. And using microdata while writing your content is not feasible at all if you think about the extra time and effort it will take, and believe me, this extra time and effort are not to be neglected.

An example microdata looks like:

<span itemscope itemtype="http://schema.org/Organization">
  <link itemprop="url" href="http://www.your-company-site.com"> 
  <a itemprop="sameAs" href="http://www.facebook.com/your-company">FB</a>
  <a itemprop="sameAs" href="http://www.twitter.com/YourCompany">Twitter</a>
</span>

Look how messed up it is, you insert HTML5 tags to form microdata markup and this type of thing will be spread over all of your content. Even after you have finished doing this, think of a situation when you need to change something, what will you do? find the data from a big chunk of html codes and then make changes?

If you think in a practical point of view, using microdata this way is not feasible at all. Though there are certain tools or plugins available which makes it automatic by scraping/investigating the content, those are different cases. If you don't have to do it yourself but some AI does it for you, then it's all good as long as you are satisfied with it's performance and correctness, that is.

RDFa is no better. It uses inline data markup too.

With JSON-LD however, you can gain certain flexibility in this aspect:

  1. Keep all things together in a definite place.
  2. Easier to construct and maintain.
  3. Making amendments is easier because all data can be kept in a definite place in the page.
  4. Automatic generation of JSON-LD is easier.
  5. Automatic BreadCrumb generation is easier with JSON-LD.
  6. Customizing how your search results are rendered is easier with JSON-LD.
Even though JSON-LD is easier, there may be certain cases where you may have no choice but to use microdata or RFDa. I am going to ignore those cases for now.

Where to insert?

You can insert a JSON-LD anywhere in your HTML wrapped around with <script> tag. Though in general case, JSON-LD goes in the head section of your page inside a script tag:

<head>
...
<script type="application/ld+json">
JSON-LD goes here
</script>
...
</head>

Let's see some examples:

Google google, it will show you how the search result for google is rendered. This is what I am seeing:
google search result image

Isn't it cool how Google is showing itself off? What if we could do the same for our own websites. Well, it's possible.

And, yeah, don't try searching my website in Google to see if I myself got this implemented for my website or not. Google doesn't just show all the data it gets from a website without justifying them in their own way according to their own privacy policies and TOS. And also the search result depends on the popularity of your site. Don't expect too much from a fairly new site like this one.

Though there are several things that can be implemented without any kind of restrictions at all. For example you can search for using git to manage a website by neurobin in Google, which may show you something like this:
using git to manage a website by neurobin search result image

Narrow down your view on this particular spot:
using git to manage a website by neurobin search result image

Instead of showing a simple URL it's showing something far more informative and also it looks kinda cool, don't you think? It's time you should know the technical keyword for this particular thing, it's known as BreadCrumb.

Wanna know how I did this? well, keep reading...

JSON-LD for Article:

The first thing in a JSON-LD is to include the context:

{
    "@context":"http://schema.org"
}

Now add the things you want. As for an article:

{
    "@context":"http://schema.org",
    "@type": "Article",
    "headline":"Headline of the article",
    "description":"Description of the article",
    "datePublished": "2016-01-01",
    "dateModified": "2016-01-01",
    "author": {
        "@type": "Person",
        "name": "Author Name"
    },
    "publisher": {
        "@type":"Organization",
        "name": "Name of the org"
    }
}

The above is a pretty minimal JSON-LD for a typical Article. Once you know how to construct JSON-LD for specific schemas, it will become much more easier. And also there are lots of informations you could add in the above JSON-LD. Just search for article schema in Google and it will guide you to the right page that will tell you what properties are available for Article schema. Note the types Person and Organization, they have lots of properties too.

To know more about schemas visit https://schema.org

Let's dive into a Person schema this time:

JSON-LD for Person:

{
    "@context":"http://schema.org",
    "@type": "Person",
    "name":"Name of the Person",
    "email": "example@example.com",
    "birthDate": "2014-01-01",
    "sameAs": [
        "https://www.facebook.com/user",
        "https://twitter.com/user"
    ],
    "address": {
        "@type": "PostalAddress",
        "addressCountry": "Bangladesh"
     }
}

There are lots of other informations that can be added. To know which properties a Person schema includes, just search for Person shcema in Google or in https://schema.org.

JSON-LD for Organization:

{
    "@context":"http://schema.org",
    "@type": "Organization",
    "name": "Name of Organization",
    "url": "Url to home page/website",
    "description": "What your organization is about",
    "logo": {
        "@type": "ImageObject",
        "url": "url to logo",
        "width": "386",
        "height": "60"
     },
    "image": "url to imgae",
    "sameAs" : [ 
        "facebook url",
        "twitter url"
    ],
    "address": {
        "@type": "PostalAddress",
        "addressCountry": "Country"
    },
    "contactPoint": {
        "@type": "ContactPoint",
        "contactType": "technical support",
        "url": "url to contact page."
    },
    "foundingDate": "2015-01-01",
}

For more property, search for Organization shcema in Google or in https://schema.org.

JSON-LD for website:

{
    "@context": "http://schema.org",
    "@type": "WebSite",
    "url":"url of you site",
    "name":"name of your site",
    "alternateName":"an alternate name",
    "dateCreated":"07/11/2015 GMT",
    "thumbnailUrl":"url of a thumbnail",
    "genre": "Technology or whatever",
    "about":{
        "@type":"Organization",
        "name": "Name of the org"
    },
    "author": {
        "@type": "Person",
        "name": "author name"
    }
}

For more property, search for WebSite shcema in Google or in https://schema.org.

JSON-LD for webpage:

{
    "@context": "http://schema.org",
    "@type":"WebPage",
    "headline": "Headline/title",
    "description": "Description of page",
    "image": {
        "@type": "ImageObject",
        "url": "image or thumbnail URL",
        "width": "600",
        "height": "600"
    },
    "datePublished": "2016-01-01",
    "dateModified": "2016-01-01",
    "license": "url to license or name of the License",
    "author": {
        "@type": "Person",
        "name": "author name"
    },
    "publisher": {
        "@type":"Organization",
        "name": "Name of the org"
    }

JSON-LD for BreadCrumb:

I have some PHP codes to auto generate the JSON-LD required to construct the BreadCrumbs for each page, but let's go through some basics first.

This is how a basic BreadCrumb JSON-LD should look like (code copied from Google):

{
    "@context": "http://schema.org",
    "@type": "BreadcrumbList",
    "itemListElement": [{
        "@type": "ListItem",
        "position": 1,
        "item": {
            "@id": "https://example.com/arts",
            "name": "Arts"
        }
      },{
        "@type": "ListItem",
        "position": 2,
        "item": {
          "@id": "https://example.com/arts/books",
          "name": "Books"
        }
      },{
        "@type": "ListItem",
        "position": 3,
        "item": {
          "@id": "https://example.com/arts/books/poetry",
          "name": "Poetry"
        }
      }
    ]
}

for a BreadCrumb structure of Arts>Books>Poetry

This is how the BreadCrumb JSON-LD looks like for that particular page of mine:

"@type":"WebPage",
"@id":"https://neurobin.org/docs/web/using-git-to-manage-a-website/",
"breadcrumb":{
"@type":"BreadcrumbList",
"itemListElement":[
    {
        "@type":"ListItem",
        "position":1,
        "item":{
            "@id":"https://neurobin.org",
            "name":"Neurobin"
        }
    },
    {
        "@type":"ListItem",
        "position":2,
        "item":{
            "@type":"WebPage",
            "url":"https://neurobin.org/docs/",
            "name":"Docs"
        }
    },
    {
        "@type":"ListItem",
        "position":3,
        "item":{
            "@type":"WebPage",
            "url":"https://neurobin.org/docs/web/",
            "name":"Web"
        }
    },
    {
        "@type":"ListItem",
        "position":4,
        "item":{
            "@type":"WebPage",
            "url":"https://neurobin.org/docs/web/using-git-to-manage-a-website",
            "name":"Using git to manage a website"
        }
    }
  ]
 }

Now, to generate this kind of code for each of the pages manually is not a practical thing at all. So let's automate this process with PHP:

The basic logic I am using to make this automated is to break the URL into parts and extract individual names and URLs from it. Of course this method won't work for WordPress sites or other sites which doesn't have this kind of simple directory wise URL structure.

$protocol = 'http' . (isset($_SERVER['HTTPS']) ? 's' : '').'://';
$full_url = $protocol . $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'].$_SERVER['QUERY_STRING'];

///Constructing breadcrumb
$p = trim($_SERVER['REQUEST_URI'],'/');
$ps = explode('/',$p);
$urp = '';
$bread_crumb_items = '{
    "@type": "ListItem",
    "position": 1,
    "item": {
      "@id": "https://neurobin.org",
      "name": "Neurobin"
    }
  },';
for($i=0;$i<count($ps);$i++){
    $psc = trim($ps[$i]);
    if($psc==''){continue;}
    $bc_name = $psc;
    $bc_name = ucfirst($bc_name);
    $bc_name = preg_replace('/[-]/', ' ', $bc_name);
    $urp = trim($urp,'/').'/'.$psc .'/';
    if($i==count($ps)-1) {$urp = rtrim($urp,'/');}
    $bread_crumb_items .= '{
    "@type": "ListItem",
    "position": '.($i+2) . ',
    "item": {
        "@type": "WebPage",
      "url": "' . $protocol . trim($_SERVER['HTTP_HOST'],'/') .'/' . ltrim($urp,'/') .'",
      "name": "'.$bc_name.'"
    }
  },';
}
//remove last comma from $bread_crumb_items
$bread_crumb_items = rtrim($bread_crumb_items,',');

if($bread_crumb_items!=''){
$bread_crumb = '  
  "breadcrumb": {
  "@type": "BreadcrumbList",
  "itemListElement": ['.$bread_crumb_items.']
  }';

}
else {$bread_crumb='';}
$webpage = '
    "@type":"WebPage",
    "@id":"'.$full_url.'"
    ';
if($bread_crumb!=''){
    $webpage .= ','.$bread_crumb;
}

The above PHP code constructs a basic JSON-LD (without @context) for a webpage with BreadCrumbs. The above JSON-LD is bare, i.e it isn't wrapped around with {} and it doesn't have @context at the beginning. The reason to keep it bare is that, we can add or insert this piece of JSON-LD to another type like Article or WebSite etc... And to form a simple webpage with BreadCrumbs, just finish the above JSON-LD with the missing bits:

$webpage = '{ "@context": "http://schema.org",' .$webpage. '}';

Now the $webpage variable contains a full fledged JSON-LD for a webpage with BreadCrumbs. You just need to echo it within a script tag in the head section of the page.

JSON-LD for softwares/apps:


{
  "@context": "http://schema.org/",
  "@type": "SoftwareApplication",
  "name": "name of you app",
  "operatingSystem": "Android",
  "applicationCategory": "GameApplication",
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.6",
    "ratingCount": "8864"
  },
  "offers": {
    "@type": "Offer",
    "price": "1.00",
    "priceCurrency": "USD"
  }
}

JSON-LD for code:

{
    "@context": "http://schema.org/",
    "@type": "Code",
    "name": "name",
    "genre": "Genre",
    "description": "description",
    "dateCreated": "2016-01-01",
    "license": "License name or URL",
    "author": {
        "@type": "Person",
        "name": "author name"
    },
    "provider": {
        "@type":"Organization",
        "name": "Name of the org"
    }
}

How to test JSON-LD for errors:

Goto Google Structured Data Testing Tool, and paste your JSON-LD in the given box or enter your URL in the Fetch URL, then click on the button that says Validate.

How do I get the same result as searching google in Google?

It's very much possible, let's take each part at a time:

Knowledge graph:

image of knowledge graph

The Organization JSON-LD is responsible for this. Your home page should contain an organization JSON-LD to get this result. Though Google will do this on their own discretion i.e you probably will not see this until you get enough attention from visitors and get enough organic traffic.

Logo:

google logo

The logo property in Organization JSON-LD is responsible for this.

Social profiles:

image of social profiles of Google

The sameAs property in Organization JSON-LD is responsible for this.

SiteLinks:

image of sitelinks of Google

Unfortunately you don't have any control on this part. Google generates these links by scraping you web content and they will only generate these sitelinks when your site meets their expectations. You can hope this sitelinks to be automatically generated when your site or page is popular enough and getting enough organic traffic.

Others:

Other information like founder, founding date etc... are all defined by their corresponding schema property. For example, the founder property in Organization JSON-LD is responsible for showing the founder info, the foundingDate will show the founding date of your Organization in knowledge graph, and so forth.

Include your site name in google search results:

image of showing site name in google search results

To get this result, you will need to include a WebSite JSON-LD in you home page. Whatever you define as the name for your site, will show up in search results.

P.S: Don't expect to get immediate results. It takes time for Google to crawl your site and get these info and cache them. You can go to Google search console and see if Google has found your structured data. It will show up in Search Appearance>Structured Data under your site if you added your site through Google Webmaster tool.