I really like the things that the Yoast SEO plugin does for WordPress for search engine optimization (SEO). With it you can check your posts on various things in your post that a search engine keeps into consideration.

I was missing this functionality in Jekyll, until I came across the Jekyll SEO tool from Brett Hardin. The script itself was last updated in 2013, but still does its thing.

The script itself isn’t a gem that you can easily install. Since my workflow is built around tasks in a Rakefile I converted the script to it. In the gist below you find the complete task to do a test with:

rake seo['Jekyll SEO','_site/jekyll-seo/index.html']

The Rakefile, just as the original script, gives you the following results:

Is your keyword/are your keywords part of the

  • Article heading
  • Page title
  • Content
  • Meta description

Like Brett I want to enhance the task so that it will do the following:

  • Identify SEO terms in the URL
  • You have not used your keyword / keyphrase in any subheading (such as an H2) in your copy.
  • No images appear in this page, consider adding some as appropriate.
  • The meta description is under 120 characters, however up to 156 characters are available. The available space is shorter than the usual 155 characters because Google will also include the publication date in the snippet.
  • The page title contains keyword / phrase, but it does not appear at the beginning; try and move it to the beginning.
  • The keyword / phrase does not appear in the URL for this page. If you decide to rename the URL be sure to check the old URL 301 redirects to the new one!
  • This page has 14 outbound link(s).
  • The keyword density is 1.74%, which is great, the keyword was found 15 times.
  • The meta description contains the primary keyword / phrase.
  • There are 890 words contained in the body copy, this is greater than the 300 word recommended minimum.
  • The page title is more than 40 characters and less than the recommended 70 character limit.
  • The keyword appears in the first paragraph of the copy.



If you manually installed every component you can use

rake seo['<keywords>','_site/<page>']

The tasks generates your site before it checks it, because the task runs against the generated HTML instead of the markdown file.

For the post you’re reading right now the command was:

rake seo['Jekyll SEO','_site/jekyll-seo/index.html']

If you use bundle just precede the command with ‘bundle exec’.


The output the rake task will give looks like this when testing for the keyword seo:

Analyzing page '_site/jekyll-seo/index.html' for keywords 'seo'
Article Heading: true (3)
Page title: true (1)
Content: true (20)
Meta description: true (1)

The task

# SEO test
desc 'Check SEO values for post'
task :seo, [:keywords, :post] do |t, args|
  require 'nokogiri'
  heading = [];
  title = [];
  url = [];
  content = [];
  meta_description = [];
  temp = [];
  puts "Analyzing page '#{args.post}' for keywords '#{args.keywords}'"
  sh "bundle exec jekyll build _config.yml"
  post = Nokogiri::HTML(open(args.post))
  post.css('h1').each do |this|
    heading = this.to_s.scan(/#{args.keywords}/i)
  post.css('title').each do |this|
    title = this.to_s.scan(/#{args.keywords}/i)
  post.css('body').each do |this|
    content = this.to_s.scan(/#{args.keywords}/i)
  post.css('meta').each do |this|
    if this.attribute("name").to_s == "description"
      meta_description = this.attribute("content").to_s.scan(/#{args.keywords}/i)
  puts ""
  puts "Article Heading: #{not heading.empty?} (#{heading.count})"
  puts "Page title: #{not title.empty?} (#{title.count})"
  # puts "Page URL: Yes (1)"
  puts "Content: #{not content.empty?} (#{content.count})"
  puts "Meta description: #{not meta_description.empty?} (#{meta_description.count})"