SEO Programmatique : Comment nous avons indexé 253K pages avec Next.js et Supabase
SEO Programmatique : Comment Nous Avons Obtenu 253K Pages Indexées avec Next.js & Supabase
L'année dernière, nous avons franchi un jalon que je ne pensais sincèrement pas être possible : 253 000 pages programmatiques indexées sur trois sites de production, tous fonctionnant sur la même stack. Pas un projet jouet. Pas une démo. De vrais sites avec du vrai trafic et des vrais revenus.
Je vais vous montrer exactement comment nous avons construit Deluxe Astrology (91 000 pages), Not Another Sunday (137 000 listes de lieux) et HostList (25 000 profils de sociétés d'hébergement) -- y compris les requêtes Supabase, l'architecture des pages Next.js, les pipelines de données, et plus important encore, ce qui s'est cassé en chemin. Parce que beaucoup de choses se sont cassées.
La plupart du contenu SEO programmatique en ligne ressemble à quelqu'un qui a lu la doc en diagonale et a appelé ça un jour. Ce n'est pas ça. Nous livrons ces pages depuis plus d'un an, en observant les graphiques de Google Search Console, en maudissant les limites du budget de crawl, et en découvrant lentement ce qui marche vraiment à grande échelle.
Table des matières
- Ce que le SEO programmatique signifie réellement en 2025
- Les trois projets : Chiffres de production
- La stack : Supabase, Next.js ISR, Vercel Edge
- Architecture du pipeline de données
- Architecture du modèle de page que Google n'a pas en horreur
- Code réel : De la requête Supabase à la page rendue
- Ce qui s'est cassé et comment nous l'avons réparé
- Résultats : La courbe exponentielle et les honnêtes échecs
- SEO programmatique vs. contenu traditionnel : Quand utiliser lequel
- FAQ

Ce que le SEO programmatique signifie réellement en 2025
Le SEO programmatique consiste à générer des pages à grande échelle à partir de données structurées en utilisant des modèles. C'est la version d'une phrase. La réalité est bien plus compliquée.
La position de Google en 2025 est claire mais nuancée : ils ne pénalisent pas le contenu programmatique parce qu'il est programmatique. Ils le pénalisent quand il est mince, dupliqué ou inutile. La différence entre les 70 000 pages indexées de Zapier contribuant à 140 M$ de revenus annuels et une étude de cas dev.to où 287 000 pages ont obtenu presque zéro indexation se résume à une seule chose -- si chaque page répond réellement à une requête qu'un humain a tapée dans une barre de recherche.
Les données d'Ahrefs nous disent que 96,55 % de toutes les pages web reçoivent zéro trafic organique. Le SEO programmatique amplifie ce problème si vous générez simplement des variations du même contenu. Mais il peut aussi le résoudre de manière spectaculaire si vos données sont véritablement uniques et que vos modèles produisent des pages qui sont significativement différentes les unes des autres.
Voici le modèle mental qui marche pour nous : chaque page programmatique devrait passer le test « aurais-je mettre cette page en favori ? ». Si vous y arriviez depuis Google, resteriez-vous ? Trouveriez-vous quelque chose que vous ne trouviez nulle part ailleurs ? Si la réponse est non, ne publiez pas.
Les trois projets : Chiffres de production
Laissez-moi expliquer ce que nous avons réellement construit et à quoi ressemblent les chiffres.
| Projet | Pages | Types de contenu | Portée géographique | Métrique clé |
|---|---|---|---|---|
| Deluxe Astrology | 91 000 | Horoscopes, profils de célébrités, chiffres angéliques, pièces cosmiques, pierres précieuses, poses de yoga, labo des noms, répertoire d'astrologues | 30 langues | 91K pages indexées |
| Not Another Sunday | 137 000 | Listes de lieux avec cafés & torréfacteurs avec score NRI, photos, cartes | USA, UK, Japon | 137K pages de lieux uniques |
| HostList | 25 000 | Profils de sociétés d'hébergement avec algorithme HostScore | 53 pays | 25K profils indexés |
| Total | 253 000 |
Deluxe Astrology : 91K pages sur 30 langues
Deluxe Astrology a commencé comme un site d'horoscopes dans une seule langue. L'échelle provient de l'intersection des types de contenu et des langues. Pensez à cela : si vous avez 12 signes du zodiaque × 365 horoscopes quotidiens × 30 langues, vous êtes déjà à 131 000 pages potentielles juste à partir d'un seul type de contenu. Nous avons été sélectifs -- chaque combinaison ne reçoit pas une page -- mais la nature combinatoire du contenu astrologique est parfaite pour le SEO programmatique.
La section des profils de célébrités seule compte 28 840 enregistrements, chacun enrichi via Claude pour inclure l'analyse du thème natal, les analyses de personnalité et les perspectives de compatibilité. Plus sur ce pipeline de données plus tard.
Not Another Sunday : 137K listes de lieux
Not Another Sunday est une plateforme de découverte de cafés spécialisés. Chaque café et torréfacteur reçoit une page unique avec un score NRI propriétaire (Index de Pertinence du Quartier), des photos curées, une carte intégrée, les horaires d'ouverture et les avis. Nous tirons les données de plusieurs API, du contenu généré par les utilisateurs et de la curation manuelle.
L'idée clé : aucune deux pages de lieux ne se ressemblent parce qu'aucun deux lieux ne sont identiques. Le modèle est cohérent, mais les données le remplissent différemment chaque fois. Un café à Shibuya avec 4,8 NRI et des compétitions d'art du latte ne ressemble à rien comme une torréfacterie à Brooklyn avec 3,2 NRI et des opérations wholesale uniquement.
HostList : 25K profils d'hébergement sur 53 pays
HostList catalogue les sociétés d'hébergement dans le monde, chacune avec un HostScore -- notre notation algorithmique basée sur les données de disponibilité, les prix, la réactivité du support et les avis des utilisateurs. 25 000 profils sur 53 pays, chacun avec des données de performance uniques, des tableaux de prix et des widgets de comparaison.
La stack : Supabase, Next.js ISR, Vercel Edge
Nous avons standardisé la même stack sur les trois projets. Voici pourquoi chaque composant importe.
Supabase (PostgreSQL + pgvector) : Tout notre calque de données réside dans Supabase. PostgreSQL nous donne la structure relationnelle dont nous avons besoin pour les requêtes complexes (donnez-moi tous les célébrités Sagittaire nés en décembre qui sont aussi musiciens), et pgvector alimente la recherche sémantique dans le contenu. L'offre gratuite de Supabase gère 500 Mo ; nous sommes sur Pro à 25 $/mois par projet pour 8 GB de bases de données avec appels API illimités.
Next.js avec ISR (Incremental Static Regeneration) : Chaque page est générée statiquement au moment de la compilation ou à la première demande, puis revalidée selon un horaire. Cela signifie que le crawler de Google frappe toujours une page HTML pré-rendue rapide -- pas un spinner de chargement en attente de JavaScript côté client. Nous utilisons l'App Router avec generateStaticParams pour la génération de chemins.
Vercel Edge : Déploiement, CDN et middleware edge, tout en un. Le plan Pro de Vercel à 20 $/utilisateur/mois nous donne 1 TB de bande passante, ce qui gère confortablement le trafic de 253K pages. Le middleware Edge gère le routage géo pour la configuration multilingue de Deluxe Astrology sur 30 langues.
Le coût total d'infrastructure pour les trois projets s'élève à environ 150-200 $/mois. C'est l'hébergement de 253 000 pages qui reçoivent des millions de crawls mensuels. Si vous construisez des sites programmatiques et envisagez nos capacités de développement Next.js ou avez besoin d'aide avec l'architecture de CMS headless, c'est la stack que nous recommanderions.

Architecture du pipeline de données
Les données sont ce qui fait ou casse le SEO programmatique. Les modèles sont faciles. Obtenir des données véritablement uniques et de haute qualité pour des dizaines de milliers de pages ? C'est la partie difficile.
Nous utilisons quatre types de sources de données dans nos projets :
1. Scraping d'API
Not Another Sunday récupère les données de lieux depuis Google Places API, Yelp Fusion API, et quelques API régionales pour le Japon. Nous exécutons des travaux de synchronisation nocturnes via les fonctions Edge de Supabase qui vérifient les nouveaux lieux, les horaires mis à jour et les fermetures de lieux. Chaque réponse d'API est normalisée dans notre schéma avant insertion.
2. Import CSV avec validation
Le dataset initial de HostList provenait d'un énorme CSV de sociétés d'hébergement compilé sur deux ans. Nous avons construit un pipeline de validation qui vérifie les doublons, normalise les noms d'entreprise et signale les enregistrements incomplets. Environ 30 % de l'import initial a été signalé et a nécessité un examen manuel.
3. Enrichissement AI avec Claude
C'est là que ça devient intéressant. Pour Deluxe Astrology, nous avions 28 840 enregistrements de célébrités avec des données biographiques basiques -- nom, date de naissance, lieu de naissance. Ce n'est pas suffisant pour une page utile. Nous avons utilisé Claude (API d'Anthropic) pour enrichir chaque enregistrement avec l'interprétation du thème natal, l'analyse de personnalité, les perspectives de compatibilité de carrière et des anecdotes amusantes.
La clé : nous n'avons pas utilisé Claude pour générer du contenu à partir de rien. Nous l'avons utilisé pour analyser et interpréter des données astronomiques réelles. Le thème natal de chaque célébrité est calculé mathématiquement à partir de ses données de naissance, puis Claude fournit l'interprétation astrologique. Les données sous-jacentes sont uniques et vérifiables. La couche IA ajoute de la profondeur, pas de la fabrication.
Voici une version simplifiée de notre pipeline d'enrichissement :
import anthropic
from supabase import create_client
client = anthropic.Anthropic()
supabase = create_client(SUPABASE_URL, SUPABASE_KEY)
def enrich_celebrity(record):
natal_chart = calculate_natal_chart(
birth_date=record['birth_date'],
birth_place=record['birth_place']
)
prompt = f"""Given this natal chart data for {record['name']}:
Sun: {natal_chart['sun_sign']} in {natal_chart['sun_house']}
Moon: {natal_chart['moon_sign']} in {natal_chart['moon_house']}
Rising: {natal_chart['ascendant']}
Write a 300-word astrological personality profile focusing on
how these placements manifest in their career as a {record['profession']}.
Include specific aspect interpretations."""
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=[{"role": "user", "content": prompt}]
)
supabase.table('celebrities').update({
'natal_chart': natal_chart,
'ai_profile': response.content[0].text,
'enriched_at': 'now()'
}).eq('id', record['id']).execute()
Nous avons traité les 28 840 enregistrements sur environ une semaine, en regroupant les demandes pour rester dans les limites de taux. Le coût était d'environ 180 $ en crédits API. Pas mal pour enrichir presque 29K pages avec du contenu unique.
4. Contenu généré par les utilisateurs
Not Another Sunday accepte les avis et les soumissions de photos des utilisateurs. Ce contenu généré par les utilisateurs rend les pages de plus en plus uniques au fil du temps et signale à Google que le contenu est frais et communautaire.
Architecture du modèle de page que Google n'a pas en horreur
C'est là que la plupart des projets de SEO programmatique échouent. Ils créent un modèle comme :
<h1>{City} {Service} Directory</h1>
<p>Looking for {service} in {city}? Browse our directory of {count} providers.</p>
C'est du contenu mince. Google le sait. Les utilisateurs le savent. Ne faites pas ça.
Notre architecture de modèle assure que chaque page a cinq éléments uniques :
H1 unique : Pas seulement
{name}inséré dans un motif. La structure H1 varie selon le type de contenu et inclut des modificateurs contextuels.Description meta unique : Générée à partir des données réelles de la page, pas un modèle avec des blancs remplis.
Contenu body unique : C'est le grand. Chaque page a 400-2 000 mots de contenu spécifique à cette entité. Pour les célébrités, c'est leur analyse du thème natal. Pour les lieux, c'est leur décomposition NRI, le contexte du quartier et les points forts du menu. Pour les sociétés d'hébergement, c'est leur décomposition HostScore avec des pourcentages de disponibilité spécifiques et des tarifs.
Données structurées (schema.org) : Chaque page reçoit le balisage JSON-LD approprié à son type --
Personpour les célébrités,LocalBusinesspour les lieux,Organizationpour les sociétés d'hébergement.Lien interne : Chaque page établit un lien vers 5-15 pages connexes basées sur les relations de données réelles. Une page de célébrité établit un lien vers d'autres célébrités du même signe solaire, même profession ou même année de naissance. Une page de lieu établit un lien vers les lieux à proximité et les lieux avec des scores NRI similaires.
La pièce de lien interne s'est avérée être le facteur unique le plus important pour l'indexation. Plus sur cela dans la section des réparations.
Code réel : De la requête Supabase à la page rendue
Laissez-moi vous montrer le flux réel pour une page de lieu Not Another Sunday. C'est du code de production, simplifié légèrement pour la lisibilité.
D'abord, la couche de requête Supabase :
// lib/queries/venues.ts
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!
)
export async function getVenueBySlug(slug: string) {
const { data, error } = await supabase
.from('venues')
.select(`
id, name, slug, description, nri_score,
address, city, country, lat, lng,
opening_hours, photos, menu_highlights,
created_at, updated_at,
venue_reviews (
id, rating, body, author_name, created_at
),
venue_tags (
tag:tags ( name, slug )
)
`)
.eq('slug', slug)
.eq('status', 'published')
.single()
if (error) throw error
return data
}
export async function getRelatedVenues(venueId: string, city: string, nriScore: number) {
const { data } = await supabase
.rpc('get_related_venues', {
p_venue_id: venueId,
p_city: city,
p_nri_score: nriScore,
p_limit: 12
})
return data ?? []
}
La fonction get_related_venues est une fonction PostgreSQL dans Supabase qui renvoie les lieux à proximité triés par proximité du score NRI :
CREATE OR REPLACE FUNCTION get_related_venues(
p_venue_id UUID,
p_city TEXT,
p_nri_score NUMERIC,
p_limit INT DEFAULT 12
)
RETURNS TABLE (
id UUID, name TEXT, slug TEXT,
nri_score NUMERIC, city TEXT, country TEXT
) AS $$
BEGIN
RETURN QUERY
SELECT v.id, v.name, v.slug, v.nri_score, v.city, v.country
FROM venues v
WHERE v.id != p_venue_id
AND v.status = 'published'
AND v.city = p_city
ORDER BY ABS(v.nri_score - p_nri_score) ASC
LIMIT p_limit;
END;
$$ LANGUAGE plpgsql;
Maintenant le composant de page Next.js utilisant l'App Router :
// app/venues/[country]/[city]/[slug]/page.tsx
import { getVenueBySlug, getRelatedVenues } from '@/lib/queries/venues'
import { VenueHeader } from '@/components/venue/VenueHeader'
import { NRIScoreCard } from '@/components/venue/NRIScoreCard'
import { VenueMap } from '@/components/venue/VenueMap'
import { ReviewSection } from '@/components/venue/ReviewSection'
import { RelatedVenues } from '@/components/venue/RelatedVenues'
import { venueJsonLd } from '@/lib/schema/venue'
import { notFound } from 'next/navigation'
export const revalidate = 3600 // ISR: revalidate every hour
export async function generateMetadata({ params }: Props) {
const venue = await getVenueBySlug(params.slug)
if (!venue) return {}
const reviewCount = venue.venue_reviews?.length ?? 0
const avgRating = reviewCount > 0
? (venue.venue_reviews.reduce((sum, r) => sum + r.rating, 0) / reviewCount).toFixed(1)
: null
return {
title: `${venue.name} -- Specialty Coffee in ${venue.city} | NRI ${venue.nri_score}`,
description: avgRating
? `${venue.name} in ${venue.city} scores ${venue.nri_score}/10 NRI. Rated ${avgRating}/5 from ${reviewCount} reviews. ${venue.description?.slice(0, 80)}...`
: `${venue.name} in ${venue.city} scores ${venue.nri_score}/10 on our Neighbourhood Relevance Index. ${venue.description?.slice(0, 100)}...`,
alternates: {
canonical: `/venues/${params.country}/${params.city}/${params.slug}`
}
}
}
export default async function VenuePage({ params }: Props) {
const venue = await getVenueBySlug(params.slug)
if (!venue) notFound()
const related = await getRelatedVenues(venue.id, venue.city, venue.nri_score)
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(venueJsonLd(venue)) }}
/>
<article>
<VenueHeader venue={venue} />
<NRIScoreCard score={venue.nri_score} breakdown={venue.nri_breakdown} />
<VenueMap lat={venue.lat} lng={venue.lng} />
<section className="venue-body">
<h2>About {venue.name}</h2>
<p>{venue.description}</p>
{venue.menu_highlights && (
<>
<h3>Menu Highlights</h3>
<ul>
{venue.menu_highlights.map(item => (
<li key={item}>{item}</li>
))}
</ul>
</>
)}
</section>
<ReviewSection reviews={venue.venue_reviews} />
<RelatedVenues venues={related} currentCity={venue.city} />
</article>
</>
)
}
Notez revalidate = 3600. C'est l'ISR -- la page est générée statiquement à la première demande et mise en cache pendant une heure. Le crawler de Google obtient toujours du HTML rapide. Les données fraîches s'écoulent lors du prochain cycle de revalidation. C'est énormément important pour le budget de crawl.
Ce qui s'est cassé et comment nous l'avons réparé
C'est là où la plupart des études de cas deviennent malhonnêtes. Ils montrent les résultats sans les mois de débogage. Nous avons eu trois problèmes majeurs.
Problème 1 : Deluxe Astrology -- Privation de budget de crawl
Nous avons lancé avec 91 000 pages et une structure de sitemap plate. Google a indexé environ 12 000 pages au premier mois et puis... s'est arrêté. Le rapport de couverture GSC montrait « Découverte -- actuellement non indexée » pour des dizaines de milliers d'URL.
Le problème était twofold. Premièrement, notre sitemap était un seul fichier avec 91 000 URL. Google recommande max 50 000 par sitemap, mais même dans cette limite, un sitemap unique massif ne signale pas la priorité. Deuxièmement, nos liens internes étaient faibles -- beaucoup de pages n'étaient accessibles que via le sitemap, pas via des liens sur la page.
La correction :
Restructuration du sitemap : Nous avons cassé le sitemap monolithique en sitemaps basés sur les catégories.
sitemap-celebrities.xml,sitemap-horoscopes-en.xml,sitemap-horoscopes-es.xml, etc. Chacun sous 10 000 URL.Surcharge des liens internes : Nous avons ajouté des liens croisés contextuels sur chaque page. Les pages de célébrités établissent maintenant un lien vers les célébrités connexes (même zodiaque, même profession, même année de naissance). Les pages d'horoscope établissent un lien vers les profils de célébrités pour ce signe. Chaque page se connecte à au moins 8 autres pages.
Suppression des pages minces : Nous avons tué environ 4 000 pages qui avaient moins de 200 mots de contenu unique. C'étaient principalement des pages de combinaison générées automatiquement qui n'ajoutaient pas de valeur. Moins de pages, mais de plus haute qualité.
Après ces modifications, l'indexation est passée de 12K à 91K sur environ 10 semaines. Les liens internes étaient le plus grand levier.
Problème 2 : HostList -- Mauvaise configuration ISR
HostList a lancé avec export const dynamic = 'force-dynamic' sur chaque page. Cela signifiait que chaque demande unique -- y compris chaque crawl Googlebot -- frappait Supabase en temps réel. Avec Google crawlant des milliers de pages par jour, notre instance Supabase était martelée, les temps de réponse ont augmenté, et certaines pages ont expiré lors des crawls.
La correction : Nous avons basculé vers export const revalidate = 3600. Les pages sont mises en cache statiquement et servent en moins de 100 ms. Supabase n'est frappée qu'une fois par heure par page au lieu d'une fois par demande. Notre temps de réponse p95 est passé de 2,8 secondes à 47 millisecondes. Googlebot a commencé à crawler 3x plus de pages par jour parce qu'il n'attendait pas.
Problème 3 : Not Another Sunday -- Contenu en double entre les pays
Certaines chaînes de cafés opèrent dans plusieurs pays. Starbucks Reserve à Tokyo et Starbucks Reserve à Londres avaient initialement des contenus de page très similaires parce que le modèle mettait l'accent sur les informations de marque sur les données spécifiques à la localisation.
La correction : Nous avons pondéré le contenu spécifique à la localisation beaucoup plus. Les descriptions de quartier, les comparaisons de lieux à proximité, le sentiment des avis locaux et les prix spécifiques aux pays constituent maintenant 70%+ de chaque page. Les infos de marque sont une petite section. Google a arrêté de signaler ceux-ci comme quasi-doublons.
Résultats : La courbe exponentielle et les honnêtes échecs
Les données GSC combinées sur les trois projets montrent la courbe exponentielle classique -- plate pendant des semaines, puis croissance exponentielle à mesure que le crawler de Google gagnait en confiance dans nos domaines.
| Métrique | Mois 1 | Mois 3 | Mois 6 | Mois 12 |
|---|---|---|---|---|
| Total des pages indexées | 18 200 | 67 000 | 189 000 | 253 000 |
| Clics organiques quotidiens | 340 | 2 100 | 8 400 | 19 600 |
| Position moyenne (toutes les requêtes) | 42 | 28 | 16 | 11 |
| Demandes de crawl/jour (tous les sites) | 4 200 | 12 800 | 31 000 | 48 000 |
| Coût mensuel Supabase | 75 $ | 75 $ | 125 $ | 150 $ |
| Coût mensuel Vercel | 40 $ | 60 $ | 60 $ | 60 $ |
Mais soyons honnêtes sur les échecs aussi. Environ 8 % de nos pages se trouvent toujours dans « Découverte -- actuellement non indexée » après 12 mois. Ceux-ci ont tendance à être les pages avec le potentiel de trafic le plus faible dans la longue traîne -- des pages de chiffres angéliques spécifiques dans les langues à faible volume de recherche, ou des sociétés d'hébergement sur de petits marchés. Nous pourrions probablement les forcer à s'indexer avec plus de liens internes, mais le ROI n'est pas là.
Nous avons également eu une période autour du mois 4 où le trafic de Deluxe Astrology a chuté de 30 % après une mise à jour core de Google. Il s'est rétabli sur 6 semaines sans aucune modification de notre côté, mais c'étaient des semaines stressantes. Les sites programmatiques semblent être plus volatiles lors des mises à jour core parce que Google réévalue les signaux de qualité sur tout le corpus de pages à la fois.
Si vous envisagez de construire quelque chose à cette échelle, nous avons détaillé notre approche et nos prix à notre page de tarification. Pour la génération de sites statiques basée sur Astro -- que nous avons également expérimentée pour le pSEO pur-statique -- consultez nos capacités de développement Astro.
SEO programmatique vs. contenu traditionnel : Quand utiliser lequel
Le SEO programmatique n'est pas un remplacement du contenu éditorial. C'est un outil différent pour un travail différent.
| Facteur | SEO programmatique | Contenu traditionnel |
|---|---|---|
| Mieux pour | Les requêtes basées sur les données (« meilleurs cafés à Shibuya », « horoscope Lion aujourd'hui ») | Les requêtes basées sur l'intention (« comment brasser un café versé ») |
| Unicité du contenu | Provient des données uniques par page | Provient de la perspective/recherche unique |
| Vitesse de mise à l'échelle | 1 000+ pages par semaine | 2-5 articles par semaine |
| Charge de maintenance | Mises à jour de base de données, réparations de modèle | Actualisation périodique du contenu |
| Construction de confiance Google | Plus lente (besoin de prouver la qualité à grande échelle) | Plus rapide (chaque pièce jugée individuellement) |
| Profil de risque | Plus élevé (les pénalités de contenu mince affectent tout le site) | Plus bas (un mauvais article ne tanke pas le domaine) |
Le sweet spot combine les deux. Not Another Sunday a 137K pages de lieux programmatiques et 200+ guides éditoriaux sur la culture du café, les méthodes de brassage et les routes de café spécifiques à la ville. Le contenu éditorial construit des signaux E-E-A-T qui soulèvent tout le domaine, ce qui aide les pages programmatiques à s'indexer plus rapidement.
FAQ
Combien de pages pouvez-vous réalistically obtenir indexées avec le SEO programmatique ?
Cela dépend entièrement de l'autorité du domaine et de la qualité du contenu. Sur les domaines établis avec des profils de lien arrière forts, nous avons vu des taux d'indexation de 90%+ pour 100K+ pages. Les nouveaux domaines luttent -- l'étude de cas dev.to de 287K pages sur un domaine frais recevant presque zéro indexation est la norme, pas l'exception. Commencez avec 1 000-5 000 pages de haute qualité, construisez de l'autorité, puis mettez à l'échelle.
Quel est le contenu minimum par page pour éviter les pénalités de contenu mince ?
Nous visons au moins 400 mots de contenu unique par page, plus les données structurées, les images et les liens internes. Mais le nombre de mots seul n'est pas la métrique -- c'est si la page répond à la requête de l'utilisateur mieux que ce qui existe déjà. Une page de 200 mots avec des tableaux de données uniques et une carte peut surpasser une page de 2 000 mots de texte générique.
Le SEO programmatique est-il toujours sûr après les mises à jour de contenu utile 2025 de Google ?
Oui, mais seulement si vous créez vraiment des pages utiles. Les mises à jour 2025 de Google ciblent spécifiquement le contenu programmatique de faible qualité qui existe uniquement pour capturer le trafic de recherche sans fournir de valeur. Les sites comme Zapier (70K pages, 140 M$ ARR) continuent à prospérer parce que leurs pages résolvent des problèmes réels. Les sites recevant des pénalités sont ceux qui génèrent des variations de « Meilleur {service} à {ville} » sans vraies données derrière.
Combien coûte une stack de SEO programmatique avec Supabase et Vercel ?
Notre stack à trois projets s'exécute à environ 150-200 $/mois total. Supabase Pro est 25 $/mois par projet (nous utilisons trois instances). Vercel Pro est 20 $/utilisateur/mois. L'enrichissement AI via l'API Claude était un coût ponctuel d'environ 180 $ pour 28 840 enregistrements. Pour la plupart des projets sous 50K pages, attendez-vous à 50-100 $/mois en coûts d'infrastructure.
Combien de temps faut-il pour que Google indexe les pages programmatiques ?
Attendez-vous à 2-4 semaines de crawl initial de vos sitemaps, mais l'indexation complète des grands ensembles de pages prend 3-6 mois. Notre expérience montre un motif de courbe exponentielle : crawl lent pendant les 6-8 premières semaines à mesure que Google évalue la qualité, puis accélération rapide une fois qu'il décide que votre contenu vaut la peine d'être indexé. La structure des liens internes et du sitemap affectent dramatiquement cette chronologie.
Dois-je utiliser Next.js SSR ou ISR pour les pages de SEO programmatique ?
ISR, presque toujours. SSR (force-dynamic) signifie que chaque demande du crawler -- y compris chaque crawl Googlebot -- frappe votre base de données, ce qui crée des problèmes de performance à grande échelle et gaspille le budget de crawl sur les réponses lentes. ISR avec revalidate = 3600 (ou même 86400 pour les mises à jour quotidiennes) vous donne les performances du site statique avec la fraîcheur des données dynamique. Nous avons appris cela de manière difficile avec HostList -- passer de force-dynamic à ISR a réduit notre temps de réponse de 2,8 s à 47 ms.
Comment gérez-vous les liens internes sur 100K+ pages ?
Les requêtes de contenu connexe basées sur les bases de données. Chaque page exécute une requête qui trouve 8-15 pages connexes basées sur les relations de données réelles -- même catégorie, scores similaires, proximité géographique, attributs partagés. Ne faites pas juste de liens aléatoires vers les pages. Les liens doivent avoir du sens contextuel pour les utilisateurs et Google. Nous utilisons les fonctions PostgreSQL dans Supabase pour calculer efficacement ces relations.
Quelle est la plus grande erreur que les gens commettent avec le SEO programmatique ?
Se concentrer sur le nombre de pages au lieu de la qualité des pages. C'est tentant de générer toutes les combinaisons possibles de vos données, mais 10 000 pages excellentes surpasseront 100 000 pages médiocres chaque fois. Nous avons tué 4 000 pages minces sur Deluxe Astrology et avons vu l'indexation augmenter sur les pages restantes. Google interprète les pages minces comme un signal que tout votre site pourrait être de faible qualité. Si vous êtes prêt à construire des pages programmatiques de la bonne façon, contactez notre équipe -- nous avons appris ces leçons pour que vous n'ayez pas à les apprendre.