Open Graph Preview and Rails Meta Tag Generator

Paste a URL. We read its Open Graph, Twitter card and standard meta tags from our server, draw the card each platform builds out of them, and write the Slim or ERB block that would emit the set your layout is missing.

All tools
Read the Open Graph tags of a URL

The page to read

Leave the scheme off and we assume https.

We make a real request to that host, so give it a second.

Give it any public URL. Nothing is stored and nothing is cached.

The Rails block that emits these tags

app/views/layouts/application.html.slim

meta property="og:title" content=@post.title
meta property="og:description" content=@post.summary
meta property="og:image" content=image_url("social-card.png")
meta property="og:url" content=post_url(@post)
meta property="og:type" content="article"
meta property="og:site_name" content="My Rails App"
meta name="twitter:card" content="summary_large_image"
meta name="twitter:title" content=@post.title
meta name="twitter:description" content=@post.summary
meta name="twitter:image" content=image_url("social-card.png")
meta name="twitter:site" content="@my_handle"

app/views/layouts/application.html.erb

<meta property="og:title" content="<%= @post.title %>">
<meta property="og:description" content="<%= @post.summary %>">
<meta property="og:image" content="<%= image_url("social-card.png") %>">
<meta property="og:url" content="<%= post_url(@post) %>">
<meta property="og:type" content="article">
<meta property="og:site_name" content="My Rails App">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="<%= @post.title %>">
<meta name="twitter:description" content="<%= @post.summary %>">
<meta name="twitter:image" content="<%= image_url("social-card.png") %>">
<meta name="twitter:site" content="@my_handle">

An example, until you read a URL above.

Put it in the layout head and feed the values from the page, not from literals - og:url wants the absolute URL of the canonical page, and og:image wants an absolute URL too, which is why the host belongs in default_url_options.

The page is fetched by our server. Only the preview image is loaded by your browser, straight from the site being checked.

Where the tags belong in a Rails layout

The og: set describes one page, so it belongs in the layout head with the values coming from that page. Rails renders the template before the layout, so a content_for set in a view reaches a yield in the head and the ordering works. What does not work is emitting the tags from the view body: a crawler takes the head and stops reading. Keep one block in app/views/layouts/application.html.slim, have it read helper methods that carry sensible defaults, and let each view override only the two or three values that actually differ.

og:image, image_url and default_url_options

og:image is the tag that works in development and breaks in production, and nearly always for one reason. A crawler fetches the image from its own machine, with no page to resolve a relative path against, so image_path is wrong here and image_url is right. image_url needs a host, and that host comes from Rails.application.routes.default_url_options - setting it only for Action Mailer is the usual miss. Active Storage follows the same rule: rails_blob_url, not rails_blob_path. Set the host in every environment file and the tag is absolute everywhere.

og:url is not link rel=canonical

They answer different questions and a page wants both. A canonical link tells a search engine which of several addresses to index. og:url tells a platform which address a share belongs to, and it is the key the share and like counts are kept against. Point them at the same URL and a share of the newsletter variant is counted with the clean one instead of beside it. In Rails that means one URL helper used twice - once for the canonical tag, once for og:url - and never request.original_url, which carries whatever query string the visitor arrived with.

Questions

In the layout, with the values coming from each view. Rails renders the template before the layout, so a content_for set in a view is available to the matching yield in the layout head. Put the block in app/views/layouts/application.html.slim once, read the values through helpers that have defaults, and override only what a given page needs. Tags emitted from the view body are never read, because a crawler takes the head and stops.

Almost always a relative path or a missing host. Use image_url rather than image_path, and set Rails.application.routes.default_url_options[:host] in each environment file so the helper has a host to build from. For an Active Storage attachment use rails_blob_url. Then check the image is reachable without a session: a crawler carries no cookies, so an image behind an authenticated route or a redirect chain comes back as nothing at all.

Yes. The canonical link is for search engines choosing what to index; og:url is what a platform keys a share against, including the share and like counts it shows. Emit both from the same URL helper so a share of an address carrying tracking parameters is counted with the clean one. Do not build either from request.original_url.

The platform cached it, and a deploy does not reach that copy. Facebook's Sharing Debugger and LinkedIn's Post Inspector both have a re-scrape button; X refreshes on its own schedule. So verify the tags first against the live page - that is what this tool does - and only then ask the platform to read them again. Changing the og:image URL, a version query string is enough, changes the image key as well, which is the one part you can force.

set_meta_tags og: { title: ..., description: ..., url: ..., type: 'website', image: ... } renders one meta property line per key, and twitter: { card: 'summary_large_image', ... } renders meta name lines. A symbol reuses an earlier value, so og: { title: :title } picks up the page title you already set. The gem does not make URLs absolute for you, so image: still has to be built with image_url, and display_meta_tags has to be in the layout head for any of it to appear.

Start creating your next app now