ScreenshotNeo

BlogHow-to

How to Add Open Graph Images to a Remix App

Add route-specific Open Graph images in Remix with loader data, complete metadata, and a clear approach to nested routes and debugging.

By the ScreenshotNeo team4 October 20267 min read

To add an Open Graph image to a Remix app, export a route-level meta function and return an og:image descriptor whose content is the image’s absolute URL. For an image that varies by page, return its URL from the route loader and read it in meta. Include the other Open Graph basics and image alt text, and account for Remix’s nested-route metadata behavior: the last matching route that exports meta supplies the metadata descriptors.

Remix documents the route meta export as the way to add metadata HTML tags for a route. The Open Graph Protocol defines og:title, og:type, og:image, and og:url as its four basic properties. Remix route metadata documentation · Open Graph Protocol

1. Put a public image URL in the route metadata

The value of og:image should be an absolute URL that identifies the image representing the page. A relative path such as /social/article.png is not the clearest choice for external consumers; use a complete URL such as https://example.com/social/article.png. Make sure the URL points to the intended image and can be fetched by the services that create previews.

This example uses a fixed image URL. Replace the example domain and path with an image hosted for your site.

import type { MetaFunction } from "@remix-run/node";

export const meta: MetaFunction = () => [
  { title: "Pricing | Acme" },
  { property: "og:title", content: "Pricing | Acme" },
  { property: "og:type", content: "website" },
  { property: "og:url", content: "https://example.com/pricing" },
  { property: "og:image", content: "https://example.com/social/pricing.png" },
  {
    property: "og:image:alt",
    content: "Acme pricing plans displayed on a clean background",
  },
];

The og:url value should be the canonical URL that identifies the page. Choose an appropriate og:type for the object. For a content article, the protocol’s example uses article; for a general site page, use the type that fits your page.

2. Use loader data for a route-specific image

For articles, products, or other records with individual social images, load the image URL with the page data and use that loader result in meta. The code below shows the shape; adapt the data access, types, and URL fields to your application. It is illustrative code, not a tested application fixture.

import type { LoaderFunctionArgs, MetaFunction } from "@remix-run/node";
import { json } from "@remix-run/node";

export async function loader({ params }: LoaderFunctionArgs) {
  const article = await getArticleBySlug(params.slug);
  if (!article) {
    throw new Response("Not Found", { status: 404 });
  }

  return json({
    article: {
      title: article.title,
      canonicalUrl: `https://example.com/articles/${article.slug}`,
      socialImageUrl: article.socialImageUrl,
      socialImageAlt: article.socialImageAlt,
    },
  });
}

export const meta: MetaFunction<typeof loader> = ({ data }) => {
  if (!data) {
    return [{ title: "Article not found | Acme" }];
  }

  const { article } = data;
  return [
    { title: `${article.title} | Acme` },
    { property: "og:title", content: article.title },
    { property: "og:type", content: "article" },
    { property: "og:url", content: article.canonicalUrl },
    { property: "og:image", content: article.socialImageUrl },
    { property: "og:image:alt", content: article.socialImageAlt },
  ];
};

// Supply this from your app's data layer.
declare function getArticleBySlug(slug: string | undefined): Promise<{
  slug: string;
  title: string;
  socialImageUrl: string;
  socialImageAlt: string;
} | null>;

The important relationship is that loader returns the fields needed by the page metadata, and meta constructs descriptors from that data. Validate the record’s image URL before publishing content; missing data should not silently produce a broken preview image.

3. Return the fields that describe the page and image

Use these Open Graph properties deliberately:

Property What to put there
og:title The page or object’s title.
og:type The kind of object, such as article for an article.
og:url The canonical URL that serves as the object’s permanent identifier.
og:image The absolute URL of the image representing the object.
og:image:alt A description of the image, not a caption. The protocol recommends specifying it when using og:image.
og:image:type The image media type, if you have a reason to provide it.
og:image:width and og:image:height The image dimensions, if you have reliable values for the actual asset.
og:image:secure_url An HTTPS image URL, where you need to provide the secure URL field.

Do not guess dimensions, media type, or platform-specific size limits. If you provide structured image fields, keep them associated with the image they describe. If you emit multiple og:image values, the protocol says the first value takes preference when there is a conflict; place each image’s structured fields after that image declaration. See the Open Graph Protocol specification.

4. Handle nested routes explicitly

Remix’s route metadata behavior is easy to overlook: when multiple nested routes match, Remix uses the last matching route that exports meta. A child route’s descriptors should therefore include the metadata you want for that page; do not assume a child’s og:image will automatically merge with a parent route’s descriptors.

Decide which route owns the metadata for each page. If a child route exports metadata, return its title, Open Graph properties, and any other route-level descriptors that should appear. Put global tags such as viewport and charset in ordinary <meta> tags in the root document as Remix recommends, rather than depending on nested route metadata merging. Consult Remix’s metadata documentation when changing route structure.

5. Verify the rendered metadata

  1. Open the target route and inspect the rendered document head.
  2. Confirm there is one intended og:image value and that it is an absolute URL for the correct page.
  3. Check that og:title, og:type, and og:url describe the same page, and that the image alt text describes the image.
  4. Open the image URL directly and confirm it resolves to the intended asset.
  5. Check a route with a parent and child match to confirm the child’s meta export includes every descriptor it needs.

These checks verify the HTML your app emits and the asset URL. The sources here do not establish current image dimensions, file size limits, crawler rules, or preview cache refresh behavior for individual social platforms. Check the relevant platform’s current primary documentation before applying platform-specific constraints.

6. Troubleshoot common problems

Symptom Likely cause Fix
No image metadata in the page head The route does not export meta, or a different matching route supplies the metadata. Inspect the matched route hierarchy and export the desired descriptors from the last matching route that defines meta.
The title appears but the image does not The og:image descriptor is missing, its content is empty, or it points to the wrong asset. Inspect the rendered tag and loader data. Return the intended absolute image URL.
Every article displays the same image The route uses a fixed URL, or the loader returns a default image for each record. Store or derive the social image URL per record and use that loader value in meta.
The URL contains an unexpected page address The metadata uses a request-dependent or incorrect URL for og:url. Return the record’s canonical URL and ensure it identifies the page consistently.
Image description is absent or misleading og:image:alt is omitted or does not describe the asset. Supply concise descriptive alt text from the same record or image configuration.
Preview still looks old after a change The page being inspected may be cached by a service or the inspected URL may differ from the route you changed. First verify the current HTML and asset URL at the exact page URL. Cache refresh procedures vary by service; consult that service’s current documentation.

7. Performance, reliability, and cost

Route metadata itself is a small descriptor list. The practical reliability concern is keeping the metadata values aligned with the content record and making sure the image URL remains valid. Store the canonical URL and social image with the record, or generate them from a single trusted source, and validate required fields when content is published.

There is no universal platform image dimension or cache behavior established by the sources used for this guide. Avoid hard-coding assumptions as universal rules; verify the current requirements of each destination where previews matter. If you need to inspect a rendered route visually while developing, a screenshot can help confirm what the page looks like, while the document head still needs a direct metadata check.

Or skip the browser setup

To capture a rendered page as an image without configuring browser automation, make one request to ScreenshotNeo, a website screenshot API and MCP server by Yorker Media. Its screenshot API can return PNG, JPEG, or WebP, and its documented parameters include viewport and full-page capture controls. This captures the page’s visual output; it does not replace checking that your Remix route emits the right Open Graph tags.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/articles/remix-open-graph -o shot.webp

See the ScreenshotNeo API documentation for request options. Cookie banners, newsletter popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents use screenshot tools. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000 screenshots. Sign up for 1,000 free screenshots a month, with no card required.

FAQ

Can I use one image for the whole Remix site?

Yes. Return a fixed image URL for routes that should share a site-wide preview. Use loader-derived URLs when pages need distinct images.

Is og:image:alt the same as a caption?

No. The Open Graph Protocol describes it as an image description rather than a caption.

Will Remix merge a child route’s image with the parent route’s tags?

Do not rely on that. Remix uses the last matching route with a meta export, so return the descriptors required by that page from the relevant route.

Does adding these tags guarantee every platform will show the preview immediately?

The metadata describes the page, but platform-specific crawler behavior and cache refresh timing are outside the guarantees established by the sources here. Check each platform’s current documentation.