---
title: "Build an ETF comparison website with a page per ISIN"
description: "Data model, SEO structure and refresh strategy for a content site that compares ETFs side by side, with one canonical page per ISIN and per pair."
canonical: https://fundfactsapi.com/use-cases/etf-comparison-website
published: 2026-09-04
updated: 2026-09-09
publisher: FundFacts API
---

# Build an ETF comparison website with a page per ISIN

> Data model, SEO structure and refresh strategy for a content site that compares ETFs side by side, with one canonical page per ISIN and per pair.

Comparison sites help investors weigh ETFs side by side: what each one tracks, what it costs, how big it is and how it has behaved. The best ones have a page per ISIN and a comparison view for any pair. This page covers the data model, the SEO structure and how to keep thousands of pages current from a single API.

## The problem

An ETF comparison site is a content site with a data problem. Readers arrive from a search for a specific ETF or a specific pairing ("A vs B"), and they expect the page to show current facts: TER, fund size, structure, distribution policy, index tracked, top holdings and recent performance. Multiply that by the number of UCITS ETFs in Europe and by the number of pairs people search for, and hand-maintained pages are impossible.

The second problem is trust. A comparison page that shows stale fees or a holdings table from eighteen months ago is worse than no page at all.

## What you need from the data

Per ETF:

- Name, ISIN, share class, currency and distribution policy
- Index tracked (benchmark name) and structure
- TER, fund size, inception date
- Top holdings, sector and country breakdowns
- Calendar returns, cumulative returns and an indexed series for a chart
- Risk rating and volatility
- As-of date

For the comparison view you need the same fields for both ETFs and a consistent layout so differences are readable at a glance.

## How it works with FundFacts API

Use static generation with periodic revalidation. Each ETF page and each comparison page is built from cached `data` objects; a scheduled job re-loads ISINs when their `expiresAt` passes and triggers a rebuild of the affected pages.

```typescript
const HEADERS = { Authorization: `Bearer ${process.env.FUNDFACTS_API_KEY}` };

async function fund(isin: string) {
  const res = await fetch(`https://fundfactsapi.com/api/v1/funds/${isin}`, { headers: HEADERS });
  if (!res.ok) throw new Error(`${res.status} loading ${isin}`);
  return res.json();
}

function pick(f: any) {
  return {
    isin: f.isin as string,
    name: f.name as string,
    index: f.data.benchmarkName,
    structure: f.data.structure,
    ter: f.data.headlineMetrics?.ter,
    aum: f.data.headlineMetrics?.aum,
    distribution: f.data.keyFacts?.distribution,
    inception: f.data.keyFacts?.inception,
    riskRating: f.data.riskRating,
    holdings: f.data.keyFacts?.holdings,
    oneYear: f.data.cumulativePerformance?.["1y"],
    dataAsOf: f.data.dataAsOf,
  };
}

export async function comparison(a: string, b: string) {
  const [fa, fb] = await Promise.all([fund(a), fund(b)]);
  return { left: pick(fa), right: pick(fb) };
}

// comparison("IE00B4L5Y983", "IE00BJ0KDQ92") -> two MSCI World trackers side by side
```

Render `left` and `right` as two columns of the same rows. Where both funds track the same index, the interesting rows are TER, size, structure and distribution; where they track different indices, lead with the benchmark and the exposure breakdowns.

## Design notes

**SEO structure.** One canonical URL per ISIN and one per pair, with the alphabetically smaller ISIN first so "A vs B" and "B vs A" resolve to the same page. Put the fund name, ISIN and as-of date in the title and first paragraph. The [ISIN guide](https://fundfactsapi.com/blog/what-is-an-isin) explains why the share-class ISIN, not the ticker, should be the key.

**Caching.** The API refreshes every 24 hours. Persist each response with `expiresAt`, rebuild pages from the store and never call the API during a page request. A site covering a few thousand ISINs needs a Scale or Enterprise plan for a full daily refresh; alternatively refresh popular pages daily and the long tail weekly.

**Quota and errors.** Run the refresh as a queue that respects `X-RateLimit-Remaining` and pauses on `429`. Cold ISINs take one to three minutes on first load, so build the initial catalogue over several days rather than in one burst. A `404 fund_not_found` means the page should be removed or marked as unavailable; a `502 upstream_error` means keep the previous version and retry later.

**Editorial content.** The API provides facts; your value is the explanation around them. Write about what an index covers, what a [replication method](https://fundfactsapi.com/glossary/replication-method) means, why [TER](https://fundfactsapi.com/glossary/ter) differs from total cost of ownership. Keep hand-written text and API data in separate blocks so a data refresh never overwrites prose.

**Disclaimers.** Show `dataAsOf` on every page, state that figures are read from the documents each fund house publishes, and include the standard wording that this is not investment advice and past performance is not a guide to future returns. Avoid "best ETF" framing; present differences and let the reader decide.

The [fund comparison tool guide](https://fundfactsapi.com/blog/build-fund-comparison-tool) walks through the comparison table in more detail.

## FAQ

### Can I call the API from the browser on each page view?

You should not. Your API key would be exposed, every visitor would consume quota and cold ISINs would leave visitors waiting for minutes. Build pages server-side from a store you refresh on a schedule. The 24-hour refresh cycle and the expiresAt field make this straightforward: rebuild a page only when its underlying record has expired and been re-loaded.

### How do I handle ETFs that trade on several exchanges?

Key everything on the share-class ISIN, which is the same on every exchange, and treat tickers as display aliases. A single page for IE00B4L5Y983 can list the London, Xetra and Milan tickers in a table without duplicating content. This avoids thin duplicate pages and matches how the fund house itself identifies the product in its documents.

### Can I show performance figures on a public site?

Yes, with care. Display the calendar-year and cumulative figures with their dataAsOf date, state that they are read from the fund house's published documents, and include the usual statement that past performance is not a reliable guide to future returns. Do not compute or imply rankings based on returns, and do not describe any fund as a good or bad choice.

### How large a catalogue can I maintain?

A full daily refresh needs one request per ISIN. Scale covers 10,000 requests a month, plus overage at $0.04, and Enterprise is metered at $0.01 per request for larger catalogues. Most sites do not need every page refreshed daily: refresh the pages that receive traffic each day and the long tail on a weekly rotation, and the effective catalogue size is several times the daily quota.

## About FundFacts API

FundFacts turns any fund or ETF ISIN into one dated factsheet (fees and KID costs, the 1–7 risk indicator, holdings, sector and country exposure, returns) read from the fund house's own documents: as a client-ready PDF under your firm's name for advisers and wealth managers, as JSON through its API for developers, or inside ChatGPT and Claude through its MCP server.

FundFacts works inside ChatGPT and Claude as a connector (a remote MCP server): ask about any fund or ETF by ISIN, ticker or name and the assistant answers from FundFacts' dated figures, fees, risk, holdings, exposure and returns, with fund cards, side-by-side comparisons, holdings overlap and portfolio look-through.

- Free API key, no card: https://fundfactsapi.com/signup
- Documentation: https://fundfactsapi.com/docs (OpenAPI: https://fundfactsapi.com/openapi.json)
- MCP server: https://fundfactsapi.com/api/mcp (set-up for every client: https://fundfactsapi.com/mcp-server)
- Pricing: https://fundfactsapi.com/pricing
- Site index for AI assistants: https://fundfactsapi.com/llms.txt
- Informational data, not investment advice.
