MetaInspector: A Ruby Gem That Returns a Page's Metadata Instead of Its Markup
Ruby gem for web scraping purposes. It scrapes a given URL, and returns you its title, meta description, meta keywords, links, images...
At a glance
- What is it?
- MetaInspector takes a URL and hands back the title, description, keywords, author, meta tags, head links, page links and images as Ruby objects, with best_title and best_description picking a winner among the several candidates a page usually offers. It is aimed at link previews, SEO checks and content pipelines.
- Who is it for?
- MetaInspector fits a Rails application that needs a link preview, an SEO report or a content ingestion step, because it replaces a pile of per-site scraping code with one call and a consistent object, and it is a poor fit for a crawler, since the examples directory contains a spider but the library's job is the first page of a URL rather than a site.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 10 days ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One Object Per Page, With the Metadata Already Extracted
MetaInspector is a gem for web scraping purposes. You give it a URL and it lets you get the title, the links, the images, the charset, the description, the keywords and the meta tags.
The shape of the API is the important part. There is one object, created for one page, and every accessor is a method on it. The response is available for status and headers, the URL parts are broken out into scheme, host and root_url, the head links are grouped, the text candidates are exposed, the links are classified, the images carry their dimensions, and the meta tags are grouped by kind.
That consistency is the reason to use the gem rather than a regular expression. A page can express its title in the title element, in an og:title meta tag, in a twitter:title meta tag, in an h1, or in nothing at all, and a naive scraper has to know about each of those. MetaInspector knows about all of them and, for the fields where several are plausible, offers a best_ accessor that chooses.
The gem is MIT licensed, is built on CircleCI, and its repository carries a spec/ directory, a Rakefile, a CHANGELOG.md, a meta_inspector.gemspec and an MIT-LICENSE file, which is the standard Ruby gem layout.
The best_ Accessors Pick Between Competing Candidates
The best_ methods are the reason the gem is more than a title parser.
page.title returns the title of the page from the head section as a string. page.best_title returns the best title of the page, from a selection of candidates. The same pairing exists for the author, with page.author reading the meta author tag and page.best_author choosing from a selection of candidates.
The description case is the clearest, because the README spells out the candidate list. page.description returns the meta description, and page.best_description returns the first non-empty description between the standard meta description, og:description, twitter:description, and the first long paragraph.
That last candidate is the interesting one. A page with no description at all is common, and falling back to the first long paragraph of body text gives you something usable where a strict parser gives you nothing. The cost is that the fallback is a heuristic, so a page with a short paragraph near the top of the body can produce a poor description, and the standard meta description is always preferred when it exists.
The heading accessors sit alongside these, with page.h1 through page.h6 each returning an array of the text of that heading level, which is what you want when a page has several h2 sections rather than one.
Links Are Classified, and Tracking Parameters Can Be Stripped
The links accessor is a small namespace with a clear split.
page.links.raw is every link found, unprocessed. page.links.all is every link found on the page as an absolute URL, so relative links have been resolved. page.links.http is every HTTP link found, and page.links.non_http is every non-HTTP link found, which covers mailto and similar schemes. page.links.internal is every internal link found on the page as an absolute URL, and page.links.external is every external link found as an absolute URL.
Resolving to absolute URLs matters more than it sounds. A page that links to /about has told you nothing useful about the site structure, while an absolute URL tells you whether the link stays on the domain, and the internal and external split is the first thing a link audit or a crawler front end needs.
The tracking side is handled on the URL object rather than the links. page.tracked? returns true if the URL contains known tracking parameters, page.untracked_url returns the URL with those parameters removed, and page.untrack! removes them from the URL in place. So a link that has been through a campaign tracker can be reduced to the URL the visitor would have seen.
The head links are grouped separately, with page.head_links returning all of them, page.stylesheets the ones where rel is stylesheet, page.canonicals the ones where rel is canonical, and page.feeds picking up the RSS or Atom links from the meta data fields.
Images Carry Dimensions, and There Is a Best and a Favicon
The images accessor does more than list image URLs.
page.images is an enumerable collection with every img found on the page as an absolute URL. page.images.with_size is a sorted array, by descending area, of image_url, width and height pairs. page.images.best is the most relevant image, if it is defined with the og:image or twitter:image meta tags, and it falls back to the first element of the images array. page.images.favicon gives the absolute URL to the favicon.
The with_size list is the useful one for a link preview. Sorted by descending area, the first entry is the largest image on the page, which is a better thumbnail candidate than the first image in document order, and the width and height are what you need to compute a crop.
The best method applies the same logic as best_title and best_description, preferring the social preview image that the site owner chose, and falling back to something arbitrary but deterministic when they have not.
The favicon accessor completes the set, and for a preview card the icon, the title, the description and the best image are usually the four things you need, which makes this accessor set the core of a link preview implementation.
Meta Tags Are Grouped by Kind, With Arrays for Repeats
The meta_tags accessor returns all the meta tags by type, and the README is explicit about the four types: meta name, meta http-equiv, meta property and meta charset.
The structure is a hash keyed by type, and each entry is a hash of attribute to value. Because meta tags can be repeated, in the case of og:image for example, the values returned are arrays.
The README shows the shape with a name group holding keywords, description, author, robots, revisit and dc.date.issued, each as a single element array, and a http-equiv group holding content-type and content-style-type. A property group is also present in the example, which is where the Open Graph values live.
The array-for-every-value design is a choice with consequences. It is consistent, so your code never has to check whether a tag appeared once or twice, and it is what makes og:image with several sizes workable. It is also noisier for the common case, since a lookup for the description returns an array where most callers want the first element, and the best_description method exists precisely to smooth that over for the fields where it matters.
The charset is handled as its own category, which is the other thing worth noting, since encoding is the detail that breaks naive scrapers and this gem surfaces it as a first class item.
Installing It and Supplying Your Own HTML
Installation is the standard gem command:
gem install metainspectorIn a Rails application the README says to add it to the Gemfile and run bundle install, with the entry being:
gem 'metainspector'The supported Ruby versions are defined in the CircleCI configuration file, and the README points at .circleci/config.yml rather than listing them, so that file is the place to check whether your Ruby is covered.
Using it is a single constructor call, and the scheme is optional, since http:// is used by default if you leave it out:
page = MetaInspector.new('https://github.com')page = MetaInspector.new('github.com')The third option is the one that changes how you would use the gem in a pipeline. You can include the HTML that will be used as the document to scrape, which means if you already have the page, for example from a cache or from a previous request, MetaInspector parses that instead of fetching the page again:
page = MetaInspector.new("https://github.com",
:document => "<html>...</html>")The response is reachable for the transport level details, with page.response.status and page.response.headers giving the status code and the header hash, which is what you need to distinguish a 200 with no content from a redirect or an error page.
The examples Directory Is the Practical Tutorial
The repository ships an examples/ directory with five scripts, and they cover the uses the gem is actually put to.
basic_scraping.rb is the straightforward case. faraday_redirect_options.rb shows how to configure the underlying HTTP client's redirect handling, which matters because a redirect changes the final URL, and the final URL is not always the URL you asked for. redirect_web_server.rb is a small server that redirects, which is the counterpart to that option, presumably for testing it.
link_checker.rb is the one most likely to be copied directly. It is the classic use of a library like this, walking the links on a page and reporting which ones are broken, and the links.internal and links.external split plus the absolute URL resolution is what makes that possible without writing URL logic.
spider.rb is the boundary case, since a spider walks a site rather than a page, and the gem provides the per-page extraction rather than the traversal.
The other repository details follow the Ruby conventions. There is an .rspec.example and a .rubocop.yml.example, both of which are templates you copy to the real filenames, so the project does not impose its own test and lint configuration on you. There is a bin/ directory for the executables, a spec/ directory for the tests, and a Gemfile for the development dependencies.
The README also lists sponsorship tiers, which is a normal way for a widely used gem to fund its maintenance, with a Silver sponsor described as an accessibility and HTML site-wide validator.
Editorial conclusion
MetaInspector fits a Rails application that needs a link preview, an SEO report or a content ingestion step, because it replaces a pile of per-site scraping code with one call and a consistent object, and it is a poor fit for a crawler, since the examples directory contains a spider but the library's job is the first page of a URL rather than a site. Before adopting it, check the Ruby versions the CI configuration tests, since the README points there rather than listing them, and pass the :document option when you already have the HTML, so you do not fetch the page twice. The gem is MIT licensed, the repository publishes no GitHub releases, and the last push was on 2026-10-13.
Frequently asked questions
How do I install MetaInspector?
With `gem install metainspector`. In a Rails application, add `gem 'metainspector'` to the Gemfile and run bundle install. The supported Ruby versions are defined in the .circleci/config.yml file.
What is the difference between title and best_title?
page.title returns the title from the head section as a string, while page.best_title returns the best title from a selection of candidates. The same distinction applies to author and best_author, and page.best_description returns the first non-empty description among the standard meta description, og:description, twitter:description and the first long paragraph.
How do I get the links of a page?
The links accessor gives raw links unprocessed, all links as absolute URLs, only HTTP links, only non-HTTP links, internal links as absolute URLs and external links as absolute URLs. The head links are available separately, with stylesheets, canonicals and feeds as filtered groups.
Can MetaInspector parse HTML I already have?
Yes. The constructor accepts a :document option with the HTML to use as the document to scrape, so you can parse a page you have already fetched instead of downloading it again.
What is the images accessor able to return?
page.images is an enumerable collection of every img found as an absolute URL, page.images.with_size is a sorted array by descending area of image URL, width and height, page.images.best prefers the og:image or twitter:image meta tag and falls back to the first image, and page.images.favicon gives the favicon URL.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/jaimeiniesta-metainspector)Was this useful?