---
title: "Serve custom XML, RSS, JSON, and text feeds from a page"
source: https://support.storeconnect.com/articles/custom-page-feeds
type: article
format: markdown
site: StoreConnect Support — product and developer documentation for StoreConnect
site_index: https://storeconnect.com/llms.txt
docs_index: https://support.storeconnect.com/llms.txt
note: Append .md to any page or article URL on this site to get its Markdown form.
---
# Serve custom XML, RSS, JSON, and text feeds from a page

Use this process to publish a file such as `products.json`, `news.xml`, or `categories.txt` at a path on your store, built from live store data. It uses the same mechanism as [llms.txt](llms-txt-for-stores): a **Page** record with a file extension in the **Path** field, whose **Content Body** is rendered as Liquid and returned without the theme layout.

## Choose between a page and the Feeds object

StoreConnect has two ways to publish a file for another system to read.

| | Page with a file extension | [Feeds](feeds) object |
|---|---|---|
| URL | Any path on the store, such as `/news.xml` | Always under `/feeds/`, such as `/feeds/products.csv` |
| Formats | One per page, set by the extension in **Path** | Several from one template, chosen by the requested extension |
| Data | Store-scoped Liquid globals such as `current_store`, `all_products`, and `all_articles` | Any object StoreConnect syncs to the storefront, picked by a **Query** record |
| Size | A small, fixed number of records per request | Paginated live feeds, or pre-built on a schedule for large collections |
| Delivery | Read on request only | Read on request, or pushed to another system after each scheduled build |
| Records to create | One **Page** | A **Query**, a **Feed**, and a **Store Feed** |

Use a page when a reader expects a file at a specific path, such as a partner who fetches `/news.xml`, and the content is a short list drawn from the current store. Use the [Feeds](feeds) object when the feed covers a large catalog, draws from a custom object, needs several formats, or must be built on a schedule and delivered. See [set up a feed](set-up-a-feed).

## How the format is set

The extension at the end of **Path** sets the response content type. The page renders without the header, footer, or theme wrapper, and `current_request.content_type` returns the content type for the request. Use one of these extensions.

| Path ends in | Content type |
|---|---|
| `.txt` | `text/plain` |
| `.xml` | `application/xml` |
| `.json` | `application/json` |
| `.csv` | `text/csv` |
| `.md` | `text/markdown` |

Serve an RSS feed from a `.xml` path, such as `news.xml`. RSS readers accept `application/xml`. Do not use a `.rss` path, which returns a server error.

## Before you start

- You can create and edit **Page** records (`s_c__Page__c`) for the store.
- You have chosen a **Path** that no other page on the store uses. A page with the **Path** `sitemap.xml` or `robots.txt` replaces the generated file; see [sitemap file](sitemap-file) and [edit robots.txt](robots-txt).
- The **Path** does not start with `feeds/`, which is the path the **Feeds** object serves feeds from.

## Create the page

1.  Go to the **Pages** list for the store and select **New**.
2.  Set **Path** to the file name and extension, such as `news.xml` (no leading `/`).
3.  Set **Title** to a name for the record, such as `News feed`.
4.  Check **Publish the page on the site**.
5.  Check **Hide Page from Navigation and Menus**, so the file does not appear in the navigation, footer, or generated sitemap. The page still appears in on-site search results.
6.  Replace the default `{{ content_page | render_content_blocks }}` snippet in **Content Body (Markdown)** (`s_c__Body_Markdown__c`) with the template for your format from the examples below.
7.  Save the record.

Open `https://shop.example.com/news.xml`. The browser shows the rendered file, with real values from your store and no theme around it.

## Escape values for the format

You write the whole file in the template, so you are responsible for valid syntax, including the commas between JSON items.

Text read from a store record reaches Liquid HTML-escaped, so `Salt & Pepper` arrives as `Salt &amp; Pepper`. Handle text values in each format as follows.

- **XML and RSS** — print values as they arrive. HTML-escaped text is valid XML text. Do not add `| escape`, which escapes the value a second time.
- **JSON** — convert each text value with `| unescape | json`, which restores the original characters and writes them as a quoted JSON string. Do not wrap the result in your own quotes.
- **Plain text** — add `| unescape` to text values, so readers see `&` rather than `&amp;`.
- **Rich text** — fields such as `summary_content` contain HTML. In XML or RSS, place them inside a `<![CDATA[ ... ]]>` section.

StoreConnect adds the XML declaration (`<?xml version="1.0" encoding="UTF-8"?>`) to every `.xml` page. Start an XML or RSS **Content Body** with the root element, such as `<rss>`. A second declaration makes the file invalid XML.

## Examples

Each example is a complete **Content Body** for the **Path** shown. The examples read a fixed number of records with the `paginate` filter, because `all_products` and `all_articles` are paginated collections and a plain loop over them returns nothing. See [paginate](paginate-filter-reference).

### XML (`products.xml`)


```liquid

<products>
{%- assign products = all_products | paginate: 50 -%}
{%- for product in products %}
  <product>
    <name>{{ product.name }}</name>
    <code>{{ product.product_code }}</code>
    <url>{{ product.url }}</url>
  </product>
{%- endfor %}
</products>
```


### RSS 2.0 (`news.xml`)


```liquid

<rss version="2.0">
  <channel>
    <title>{{ current_store.name }}</title>
    <link>{{ current_store.url }}</link>
    <description>{{ current_store.meta_description }}</description>
{%- assign articles = all_articles | paginate: 20 -%}
{%- for article in articles %}
    <item>
      <title>{{ article.title }}</title>
      <link>{{ article.url }}</link>
      <guid>{{ article.url }}</guid>
      <pubDate>{{ article.publish_on | date: "%a, %d %b %Y %H:%M:%S %z" }}</pubDate>
      <description><![CDATA[{{ article.summary_content }}]]></description>
    </item>
{%- endfor %}
  </channel>
</rss>
```


`all_articles` returns the newest articles first, by publish date. The `date` format string writes `pubDate` in the RFC 822 form that RSS 2.0 requires, such as `Thu, 01 Jul 2021 09:30:00 +0000`. The `date` filter translates day and month names into the store's language, so on a store that is not in English, `pubDate` is no longer in RFC 822 form and some RSS readers reject it.

### JSON (`products.json`)


```liquid

{
  "store": {{ current_store.name | unescape | json }},
  "url": {{ current_store.url | json }},
  "products": [
{%- assign products = all_products | paginate: 50 -%}
{%- for product in products %}
    {
      "name": {{ product.name | unescape | json }},
      "code": {{ product.product_code | unescape | json }},
      "url": {{ product.url | json }}
    }{% unless forloop.last %},{% endunless %}
{%- endfor %}
  ]
}
```


The `{% unless forloop.last %}` check places a comma after every item except the last, which JSON requires.

### Plain text (`categories.txt`)


```liquid

{{ current_store.name | unescape }}
{{ current_store.url }}

Product categories
{% for category in current_store.navigation_categories %}
- {{ category.name | unescape }}: {{ category.url }}
{% endfor %}
```


For a file that describes your store to AI tools, follow [generate an llms.txt file for your site](llms-txt-for-stores), which lists the store fields that are available and the ones that do not exist.

## Check the result

Request the URL after saving and check it with a validator for the format, such as an online JSON or XML validator or an RSS feed validator. If the result is wrong, match what you see to one of these causes.

- **A blank value** usually means an attribute that does not exist. Check it against the [Store](store-liquid-object-reference), [Product](product-liquid-object-reference), or [Article](article-liquid-object-reference) object reference.
- **`&amp;` or `&quot;` in the output** means a text value was not unescaped. Add `| unescape` for JSON and plain text. In XML, `&amp;` is correct and parsers read it as `&`.
- **`Liquid error` text in the output** means a filter or tag that does not exist, or a syntax mistake in the template.
- **A not-found page** means the **Page** record is missing, has a different **Path**, or does not have **Publish the page on the site** checked.
- **A themed web page** rather than the raw file means the **Path** is missing the extension.
- **An XML parse error about the XML declaration** means the **Content Body** starts with its own `<?xml` declaration. Remove it, because StoreConnect adds one.

## Stealth mode

[Stealth mode](stealth-mode) suppresses robots.txt, the sitemap, and the merchant feeds. A custom page at any other path is not on that list, so it keeps serving to anyone who requests the URL. Stealth mode changes two things for these pages.

- The store's robots.txt returns `Disallow: /`, which tells compliant crawlers not to request any path, including your feed.
- Every response, including your feed, carries an `X-Robots-Tag: noindex, nofollow` header, which tells compliant crawlers not to index it.

A page with the **Path** `sitemap.xml` returns a 404 while stealth mode is on, and a page with the **Path** `robots.txt` is ignored. A `robots.txt` page is also ignored while the store is in test mode. Stealth mode does not restrict access, so do not rely on it to keep a feed private.

## Remove a feed

Delete the **Page** record, or uncheck **Publish the page on the site**. Requests to the path then return a 404. If another system reads the feed, tell the owner of that system first, because the reader receives a 404 rather than an empty file.

---

## Follow StoreConnect

- [Email Newsletter](https://storeconnect.com/c/lp-newsletter)
- [LinkedIn Newsletter](https://www.linkedin.com/build-relation/newsletter-follow?entityUrn=7444956928444862464)
- [YouTube](https://www.youtube.com/channel/UCngKdP2x8l1wcbAKW3tvU8g)
- [LinkedIn](https://www.linkedin.com/company/storeconnect)
- [X / Twitter](https://x.com/storeconnecthq)

## Popular Links

- [Partners](https://storeconnect.com/partners)
- [Become a Partner](https://storeconnect.com/become-a-partner)
- [News](https://storeconnect.com/articles/news)
- [Events](https://storeconnect.com/articles/events)
- [Feature Comparison](https://storeconnect.com/how-we-compare)
- [Download a free trial](https://appexchange.salesforce.com/appxListingDetail?listingId=a0N3A00000FMkeKUAT)
- [Book a Demo](https://storeconnect.com/contact)

## Documentation

- [Help documentation](https://support.storeconnect.com/help-documentation)
- [AI agents](https://support.storeconnect.com/ai)
- [Videos & tutorials](https://support.storeconnect.com/videos-tutorials)
- [Developer reference](https://support.storeconnect.com/developer-reference)
- [Release notes](https://support.storeconnect.com/release-notes)
- [Troubleshooting](https://support.storeconnect.com/troubleshooting)
- [Trust Center](https://trust.getstoreconnect.com/)
- [Status Page](https://status.storeconnect.com/)

## Contact

- info@getstoreconnect.com
- US +1 415 745 3230
- AUS +61 2 8365 2308

100 S Ashley Dr, Suite 600-2461
Tampa FL 33602-600 USA

Level 22, Sydney Place
180 George Street
Sydney, NSW, 2000, AUS

## Machine-readable

- [Site index for agents](https://storeconnect.com/llms.txt): curated map of the StoreConnect site in llms.txt format
- [Documentation index for agents](https://support.storeconnect.com/llms.txt): full technical and product documentation map

Every page and article on this site has a Markdown rendering: append `.md` to its URL.

Continue in Markdown: [Help documentation](https://support.storeconnect.com/help-documentation.md) · [Developer reference](https://support.storeconnect.com/developer-reference.md) · [Videos & tutorials](https://support.storeconnect.com/videos-tutorials.md) · [Release notes](https://support.storeconnect.com/release-notes.md)

---

StoreConnect Support — https://support.storeconnect.com/articles/custom-page-feeds