Implement SEO to Meteor app the right way

- 1 answer

Ad

I was trying to find the right way to implement SEO in your Meteor app, but can't find any good examples. I feel like what I'm doing is working, but to some extent and could be way better. This is what I'm doing for SEO in my Meteor app:

  1. Packages I use: spiderable, gadicohen:sitemaps, manuelschoebel:ms-seo
  2. Head Tag :

<head>
	<meta charset="UTF-8" />
	<meta http-equiv="Content-Language" content="en-us" />
	<meta name="google" value="notranslate" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
	<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
	<meta name="mobile-web-app-capable" content="yes" />
	<meta name="google-site-verification" content="google-verification-id" />
	<meta name="msvalidate.01" content="bing-verification-id" />
</head>

  1. This is what I'm doing using ms-seo package: In seo.js file:

SeoCollection = new Mongo.Collection('SeoCollection');

Meteor.startup(function() {
    if (Meteor.isClient) {
        return SEO.config({
            title: ’title',
            meta: {
                    'description': ’siteDescription',
                    'keywords': ‘keyword, keyword, keyword',
                    'charset': 'utf-8',
                    'site_name': ’siteName',
                    'url':'http://siteName.com',
                    'viewport': 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no',
                    'X-UA-Compatible': 'IE=edge,chrome=1',
                    'HandheldFriendly': 'true',
                    'apple-mobile-web-app-capable' : 'yes',
                    'apple-mobile-web-app-status-bar-style': 'black',
                    'referrer': 'never',
              },
              og: {
                    'title': ’siteTitle',
                    'description': ’siteDescription',
                    'image': 'image.png',
                    'type': 'website',
                    'locale': 'en_us',
                    'site_name': 'siteName',
                    'url': 'http://sitename.com'
              },
            rel_author: 'https://plus.google.com/+appPage/'
        });
    }


    SeoCollection.update(
        {
            route_name: 'homepage'
        },
        {
            $set: {
                route_name: 'homepage',
                title: ’title',
                meta: {
                    'description': ’siteDescription',
                    'keywords': ‘keyword, keyword, keyword',
                    'charset': 'utf-8',
                    'site_name': ’siteName',
                    'url':'http://siteName.com',
                    'viewport': 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no',
                    'X-UA-Compatible': 'IE=edge,chrome=1',
                    'HandheldFriendly': 'true',
                    'apple-mobile-web-app-capable' : 'yes',
                    'apple-mobile-web-app-status-bar-style': 'black',
                    'referrer': 'never',
                },
                og: {
                    'title': ’siteTitle',
                    'description': ’siteDescription',
                    'image': 'image.png',
                    'type': 'website',
                    'locale': 'en_us',
                    'site_name': 'siteName',
                    'url': 'http://sitename.com'
                },
                rel_author: 'https://plus.google.com/+appPage/'
            }
        },
        {
            upsert: true
        }
    );

});

and dynamically using Iron:router -

this.route('page:data', {
    path: '/page',
    onBeforeAction: function() {

      SEO.set({
        title: data.title,
        meta: {
          'description': 'description',
        },
        og: {
          'title': data.title,
          'description': 'description',
          'image': data.image
        }
      })
      
      this.next();
    }
  })

  1. Submitting sitemaps using gadicohen:sitemaps:

sitemaps.add('/items.xml', function() {
  var out = [], pages = Collection.find().fetch();
  _.each(pages, function(page) {
    out.push({
      page: 'page/' + page.encodedUrl,
      lastmod: page.date,
    });
  });
  return out;
});

  1. Using meteor-up to deploy the app, it installs phantomJS. It combined with spiderable package enable google to crawl your app.

Problems I encounter:

  1. Spiderable package works only in Google. It's true that it has the largest market share, but this way for 30% of SEO traffic from other search engines it works really bad.

  2. I'm not sure if I should have all that stuff in seo.js file also in head tag. I know seo.js overwrites it, but when I request title from url on Reddit, it says no title tag find. It might be similar with other search engines from my perspective. But then there'd be multiple same tags, that is not good either.

  3. What I'm doing good or wrong?

Ad

Answer

Ad

You might want to consider FlowRouter SSR, which uses server-side rendering for HTTP requests. It generates the entire DOM on the server, and sends it as an initial static HTML <body>, thereby enabling all web spiders to crawl your site, not just Google. After that, your app will just continue to function as a real-time webapp, overriding the initial DOM.

It also supports subscriptions, thus you can use Mongo collections to render crawable content, too. But unfortunately it only works with React for now.

Ad
source: stackoverflow.com
Ad