Understanding X-Robots-Tag HTTP Headers

No Comments
Understanding x-robots-tag http headers

AI Summary

The X-Robots-Tag is an HTTP response header that carries the same indexing directives as the meta robots tag, but because it lives in the header it can control non-HTML files such as PDFs, images, and video that have no place for a meta tag. Set it at the server level with Apache, Nginx, or your application, keep the URL crawlable so the directive is seen, and verify it with a live header fetch.

  • Works on any file type because it sits in the response header, not the document body.
  • Supports noindex, nofollow, none, noarchive, nosnippet, and unavailable_after.
  • The URL must stay crawlable: a robots.txt block hides the header and defeats a noindex.
  • Target specific bots with a user agent token, for example googlebot: noindex.
Diagram showing an http response with an x-robots-tag noindex directive and how a crawler reads it before indexing a pdf file.
How the X-Robots-Tag header controls indexing for HTML and non-HTML files.

What the X-Robots-Tag header actually does

The X-Robots-Tag is a directive returned in the HTTP response header of a URL. It accepts the same instruction vocabulary as the familiar meta robots tag, but it applies at the transport layer rather than inside the HTML body. That single difference is the whole reason the header exists: a PDF, a JPEG, an XML sitemap, or a video file has no head element where a meta tag could live, so the header becomes the only reliable way to tell search engines how to treat that resource.

A typical response for a document you want kept out of search looks like this:

HTTP/1.1 200 OK
Content-Type: application/pdf
X-Robots-Tag: noindex, nofollow

You can also scope a directive to one crawler by adding a user agent token, and you can stack several lines in the same response so different bots get different rules:

X-Robots-Tag: googlebot: noindex
X-Robots-Tag: bingbot: noindex, nofollow
X-Robots-Tag: unavailable_after: 25 Dec 2026 15:00:00 GMT

Supported directives and what each one controls

The header understands the full set of indexing rules. Knowing exactly which one to reach for keeps you from over blocking a resource you actually want crawled.

DirectiveEffectTypical use
noindexKeeps the URL out of the index while still allowing a crawlGated PDFs, thank you pages, internal documents
nofollowStops link signals passing from that resourceUser generated files, untrusted uploads
noneShorthand for noindex plus nofollowFully suppress a file in one token
noarchivePrevents a cached copy in resultsPrice lists and time sensitive documents
nosnippetBlocks text and rich snippetsPaywalled or licensed content
unavailable_afterDrops the URL after a set date and timeEvent pages, expiring promotions

Setting the header on Apache

On Apache you emit the header with mod_headers, usually scoped by file type through a FilesMatch block so you only touch the documents you mean to. Placing this in the .htaccess file at the site root applies it site wide:

<FilesMatch "\.(pdf|docx|xlsx)$">
  Header set X-Robots-Tag "noindex, nofollow"
</FilesMatch>

To restrict the rule to a single bot, add the user agent token inside the quoted value exactly as it appears in the header itself.

Setting the header on Nginx

On Nginx you add the directive inside a location block. The always keyword makes sure the header is sent even on responses that are not a plain 200, which matters for redirects and error pages you also want to suppress:

location ~* \.(pdf|docx|xlsx)$ {
    add_header X-Robots-Tag "noindex, nofollow" always;
}

Application frameworks can set the same header per response. In most stacks that is a single line, for example a response header assignment in PHP, Node, or your CDN edge worker.

The crawlability trap that breaks noindex

The single most common failure with X-Robots-Tag has nothing to do with syntax. If the URL is disallowed in robots.txt, the crawler never fetches the resource, so it never receives the header and never learns about the noindex. The page can then linger in the index with a stub listing. The rule is simple: to remove a URL with a header directive, leave it crawlable and let the bot read the response. Block it in robots.txt only after it has already been dropped, or if you never wanted it crawled in the first place.

Verifying the header in production

Never assume the rule shipped. Fetch the live URL and read the response headers directly:

curl -I https://example.com/whitepaper.pdf

Look for the X-Robots-Tag line in the output. In Google Search Console, the URL Inspection tool reports the same directive under the crawl section, and it tells you whether Google currently treats the URL as indexable. Test the production hostname, because staging servers frequently carry blanket noindex headers that must never leak to the live site. For the reverse case, a page that should be indexed but is not, confirm the header is absent and cross check the meta robots tag and canonical target as well.

Frequently asked questions

Do I need X-Robots-Tag if I already use the meta robots tag?

Not for standard HTML pages, where a meta robots tag in the head is enough. You need X-Robots-Tag when the resource has no HTML head to hold a meta tag, such as a PDF, an image, a video, or a plain text file. The header also lets you apply directives to thousands of URLs from one server rule instead of editing each document.

Why is my noindex header being ignored?

The most common cause is that the URL is blocked in robots.txt. A crawler that is disallowed never requests the file, so it never sees the X-Robots-Tag line and cannot honour the noindex. Keep the URL crawlable, confirm the header with a live fetch, and only then expect the page to drop out of the index.

Can I target a single crawler with X-Robots-Tag?

Yes. Prefix the directive with a user agent token, for example X-Robots-Tag: googlebot: noindex. A bare X-Robots-Tag with no token applies to every crawler that supports the standard. You can send more than one X-Robots-Tag line in the same response to give different bots different rules.

What is the difference between noindex and nofollow in the header?

noindex tells search engines to keep the URL out of their index while still allowing them to read it. nofollow tells them not to pass ranking signals through links found on that resource. They are independent, so you can combine them or use either one on its own depending on the goal.

How do I check that the header is actually being sent?

Run a fetch that prints response headers, such as curl -I on the exact URL, and look for the X-Robots-Tag line. In Google Search Console the URL Inspection tool shows the same information under the crawl details. Test the production URL, not a staging copy, because header rules often differ between environments.

Does unavailable_after remove content immediately?

No. unavailable_after schedules the URL to drop from search results after the date and time you specify, which is useful for expiring promotions or event pages. Before that moment the URL stays indexable. After it passes, the effect is the same as a noindex on the next crawl.

Related reading

Claude Vincent is a technical SEO consultant focused on crawlability, rendering, and AI-search visibility. He writes the field guides and case studies at SEO ProCheck, with a bias toward the durable, unglamorous work that decides whether search engines and AI answer engines can actually read and cite a site.

About SEO ProCheck

Technical SEO consulting and GEO strategy with 20 years of enterprise experience. Case studies, resources, and tools for search and AI visibility.

Work With Me

Technical SEO audits, GEO strategy, site migrations, and international SEO. Hourly consulting for teams who need hands-on support, not just reports.

Subscribe to our newsletter!

More from our blog