---
title: "How to publish an RSS/Atom/JSON feed and declare it in the head on Lovable"
slug: rss-feed-lovable
published: 2026-09-26T13:25:12.922962+00:00
updated: 2026-09-26T13:25:12.922962+00:00
author: "Asif Rahman"
author_url: https://masifrahman.com
category: "AI Readiness"
tags: check:E5, platform:lovable, Lovable, RSS, JSON Feed, Atom, TanStack Start, content signals
description: "Lovable splits into two templates for this fix: TanStack Start builds the feed live from a server route, React + Vite needs a static file in public/ instead."
url: https://aiscan.site/blog/rss-feed-lovable
---

A sitemap tells a crawler what exists. It does not tell an agent what changed since last week, and that gap is what check E5 grades: whether the site publishes a dated content feed at all. Run [AIScan](https://aiscan.site/) against a Lovable app today and E5 fails for one of two reasons: no feed file exists, or one exists but nothing in `<head>` points at it. Both are fixable in under half an hour, and which fix applies depends on which of Lovable's two site templates the project runs.

## Quick summary

| If your Lovable project is on... | Feed method | Where it lives | Time |
|---|---|---|---|
| TanStack Start (default since 13 May 2026) | A file-based server route returns real XML on every request | Same domain, e.g. `/feed.xml` | 20 to 30 minutes |
| React + Vite (older projects, not migrated) | A static file dropped in `public/` | Same domain, frozen at whatever was last published | 10 minutes, plus a republish every time content changes |
| Either template, published only to a preview URL | Neither helps yet | Preview responses carry `x-robots-tag: noindex, nofollow`, so no crawler reads the feed regardless | Connect a custom domain first |

**Check first:** run `npx aiscan-cli yoursite.com`, or paste the URL at [AIScan](https://aiscan.site/). It names E5 directly, alongside the rest of the content dimension: C1 Markdown negotiation, C3 structured HTML, E3 server rendering. The [content checks page](https://aiscan.site/docs/checks/content) covers what each one grades.

## Why a feed earns its own file

An RSS, Atom or JSON feed is a cheap, dated changelog. Verified on AIScan's own check guidance for E5, the two specs it cites are [RFC 4287 for Atom](https://www.rfc-editor.org/rfc/rfc4287.html) and [JSON Feed 1.1](https://www.jsonfeed.org/version/1.1/); RSS also satisfies the check even though it predates both. A sitemap lists URLs and rarely carries a `lastmod` value anyone bothers updating. A feed's whole job is dates, which is the one thing a crawler can't infer from a page it hasn't fetched yet.

| What the feed needs | What AIScan checks for it | What AIScan cannot see |
|---|---|---|
| A parseable RSS, Atom or JSON Feed document | The file exists, validates, and is declared in `<head>` | Whether the dates inside it are true |
| A publish date per item | Present, in the format the spec expects | Whether it matches when the content actually went live |

That second column is on you. A feed with stale or fabricated dates is worse than no feed, because it hands an agent a false freshness signal instead of an honest absence of one.

## Why the fix forks on your template

According to [Lovable's own measurement writeup](https://aiscan.site/blog/ai-readiness-setup-lovable), fifteen published Lovable apps were fetched with both a browser user agent and GPTBot on 1 September 2026. Data fetched from apps on TanStack Start returned full body copy to both. Apps still on the older React + Vite template returned near-empty pages to anything that wasn't a verified crawler.

| Template | Runs code per request? | How you ship the feed |
|---|---|---|
| TanStack Start (new default) | Yes, a real server | A file-based route builds XML from your data on every request |
| React + Vite (legacy) | No, static files only | A hand-written file in `public/`, rebuilt and republished manually |

According to [Lovable's SEO and AI search page](https://docs.lovable.dev/features/seo-aeo), older projects use "on-request pre-rendering on deployed public URLs, served only to verified search and AI crawlers," while unverified requests get "the regular single-page app." In its own words, [Lovable's upgrade guide](https://docs.lovable.dev/features/upgrade-to-tanstack-start) says TanStack Start "renders each page into finished HTML on the server before sending it. Everyone receives the same complete page, every time," and dates the switch to the platform default at 13 May 2026.

The same split decides how you ship a feed. React + Vite has no server to run code on request, so anything at a URL has to already exist as a file. TanStack Start has real server routes, so it can build the feed from your actual data on every request.

## Path A: TanStack Start, a server route

Ask Lovable's AI to add a route file at `src/routes/feed[.]xml.ts`. The brackets around the dot are required; TanStack Router treats `[.]` as a literal period rather than a route-segment separator, verified on [TanStack's own routing docs](https://tanstack.com/start/latest/docs/framework/react/guide/server-routes) on 26 September 2026. Export a `GET` handler that queries whatever holds your posts (your Lovable Cloud / Supabase table) and returns real XML:

```ts
export const Route = createFileRoute('/feed.xml')({
  server: {
    handlers: {
      GET: async () => {
        const items = await getPublishedPosts() // your own query
        const xml = buildRss(items) // title, link, pubDate per item
        return new Response(xml, {
          headers: { 'Content-Type': 'application/rss+xml; charset=utf-8' },
        })
      },
    },
  },
})
```

This runs on the same domain as the app, so `/feed.xml` is a real path, not a redirect to a different subdomain, and it updates itself: no republish step when you add a post.

## Path B: React + Vite, a static file in `public/`

An older project has no server to run that handler on, so the feed has to be a plain file. Static files placed in Lovable's `public/` folder are served from the site root automatically, the same mechanism that serves `robots.txt` and `llms.txt`. Ask Lovable to generate `public/feed.xml` with your current posts written out as Atom or RSS entries, then publish. It works, but it's frozen: every new post means editing the file and republishing, and nothing enforces that you remember. If the rendering gap on E3 and C3 already has you considering the TanStack Start migration, doing it once covers this check too instead of maintaining a file by hand indefinitely.

## Declare it in `<head>`

Either path needs the same tag, wherever your `<head>` actually lives:

```html
<link rel="alternate" type="application/rss+xml" title="Blog" href="/feed.xml" />
```

On TanStack Start, that belongs in `src/routes/__root.tsx`, inside the `head` function's `links` array (`createRootRoute({ head: () => ({ links: [...] }) })`), per [TanStack's document head guide](https://tanstack.com/router/latest/docs/guide/document-head-management). It is not hand-edited into a static HTML file, because there isn't one. On the older Vite template it's a one-time edit to the single `index.html` shell in the project root, since a plain SPA serves that one file for every route.

## Verify

```bash
curl -sI https://yoursite.com/feed.xml
# expect: HTTP/1.1 200, content-type: application/rss+xml or application/xml or application/json

curl -s https://yoursite.com/ | grep -o '<link rel="alternate"[^>]*feed[^>]*>'
# expect: the tag above, not empty

curl -s "https://aiscan.site/api/public/v1/scan?url=https://yoursite.com" | grep -o '"E5"[^}]*'
```

If the scan still fails E5 after a fresh deploy, check the item dates first. A feed with every `pubDate` set to build time rather than actual publish time is the most common miss on the static path, and it reads as staleness rather than freshness.

## Exclusions

A preview-only Lovable URL fails every content check regardless of what you fix, because of the `noindex` header above; connect a custom domain before troubleshooting anything else. A feed with fewer than about five items reads as thin. Hold off publishing it until there's enough history to make the dates meaningful, and add the file once there is.

Once the feed is live, run the [AIScan](https://aiscan.site/) scan again to confirm E5 alongside the rest of the content dimension, then check [C3, title tag, meta description and schema](https://aiscan.site/blog/title-meta-schema-lovable) and [the full rendering picture](https://aiscan.site/blog/ai-readiness-setup-lovable). The [content dimension guide](https://aiscan.site/docs/checks/content) and [more Lovable fix guides](https://aiscan.site/guides) cover the rest.

