---
title: "the redirect that broke my link preview"
url: "https://sanyam.sh/blogs/the-redirect-that-broke-my-link-preview"
date: "2026-08-04"
readTime: "4 min read"
description: "A 307 between an apex domain and www is enough to stop X rendering your og:image. What a redirect does, why 308 matters, and the one line that must agree."
---

# the redirect that broke my link preview

My link preview came out as a grey box. Title there, description there, image
missing. The image was fine. What was wrong was a three digit number I had never
once thought about.

## two names, one site

`sanyam.sh` and `www.sanyam.sh` look like the same site. They are two different
hostnames, and a hostname is just the name part of a web address, everything
before the first slash. A server treats those two as unrelated as two completely
different domains, and neither is the real site until you say so.

So you pick. I picked the bare one, meaning no `www` in front. Either is fine.
What matters is that the name you did not pick has to point at the one you did,
and that pointing is a redirect.

A redirect is the server answering "not here, try over there" instead of handing
over the page. Your browser follows it without mentioning it, which is why nobody
thinks about redirects until something that is not a browser has to deal with
one.

## why there are four numbers and not one

Every redirect carries a three digit code, and the code answers two yes or no
questions.

**Is this forever?** Permanent means the address has moved for good, stop asking.
Temporary means keep asking, it might come back.

**Should the browser keep the same kind of request?** Opening a page is a GET.
Submitting a form is a POST. That is the request method, and when a POST hits a
redirect something has to decide whether the next request is still a POST or
quietly becomes a GET. The original two codes left that to the browser, which
went badly often enough that two more were added that promise not to change it.

Two questions, two answers each, four codes.

```
301  permanent   may turn POST into GET
302  temporary   may turn POST into GET
307  temporary   keeps the method
308  permanent   keeps the method
```

## how to keep them straight

Line the four up in order and the permanence reads the same both ways.

```
301  302  307  308
 P    T    T    P
```

307 is a 302 that keeps its method. 308 is a 301 that keeps its method. For an
ordinary link with no form behind it, 301 and 308 do the same job, and so do 302
and 307. Pick by whether you will ever undo it. Never means permanent.

## what the number actually changes

Nothing, if you are a browser. All four feel identical when you click, which is
why this looks like trivia.

A search engine reads it as a sentence. Temporary means both addresses are real,
so both stay in the index, which is the list of pages a search engine knows
about. Whatever credit your pages have earned then splits between two names meant
to be one site. Permanent means the two get merged.

Vercel defaults to 307, which is sensible for a redirect you might undo. Choosing
between a bare domain and `www` is not one of those.

## why my image broke and my title did not

A link preview is built by a bot. It reads your page and looks for the Open Graph
tags, a handful of `meta` tags naming the title, description and image a preview
should use. Then it fetches that image.

My page said the image was at `sanyam.sh/opengraph-image.jpg`. That address
answered with a redirect to the `www` version.

A bot fetching a page follows a redirect without complaint, which is why my title
and description came through perfectly and convinced me the metadata was fine. A
bot fetching an image usually does not. X asked once, got told to go somewhere
else, gave up, and drew the grey box.

The image was never the problem. The address I gave for it was.

## the one line that has to agree

```ts
export const SITE_URL = "https://sanyam.sh";
```

Every absolute URL on this site is built from that one constant. Absolute means
written out in full with `https://` at the front rather than as a bare `/path`.
That covers the canonical tags, which tell a search engine which address is a
page's official one, the preview image, and every entry in the sitemap, the file
listing the pages you want found.

It has to name the same hostname your DNS actually serves. DNS is the phone book
of the internet, the part that turns a hostname into the machine answering for
it. Mine disagreed with that constant, so everything downstream was correctly
derived from a wrong premise. Every piece looks right when you check it alone.

One warning before you edit DNS. Make your chosen name serve the site first, then
point the other at it. The other order leaves the two redirecting to each other
until the browser gives up.

## check yours in one command

```bash
curl -sI -A "Twitterbot/1.0" https://yoursite.com/opengraph-image.jpg | head -1
```

`curl` makes one request and prints the raw answer, with no browser tidying it
up. `-I` asks for only the response headers rather than the file itself, and `-A`
sets the user agent, the line where a request says who it is, so the server
replies the way it would reply to X.

`200` means a bot gets your image. Anything starting with `3` means it gets a
redirect instead, and your previews are broken however good the image is. Run it
on your homepage and one URL from your sitemap too.
