Le résultat d'abord
En 28 jours, baccalaureat.sn est passé à 2 150 clics (+80 %) et 31 800 impressions (+82 %) depuis la recherche Google, franchissant les paliers de 1 800 puis 2 000 clics. Voici le travail qui a produit ces chiffres.
1. Le rendu serveur, socle de tout
Le blocage initial : la plateforme était un SPA React, quasi invisible pour Googlebot (HTML vide au chargement). La migration vers Symfony + Turbo a tout changé — chaque page renvoie désormais du HTML complet, indexable immédiatement.
Vérification simple de ce que voit le crawler :
curl -A "Googlebot" https://baccalaureat.sn/annales | grep -c " 0 : le contenu est bien dans le HTML servi
2. Des pages ciblées sur l'intention de recherche
Les élèves cherchent des requêtes précises : « annales bac S1 Sénégal », « statistiques bac 2024 ». J'ai créé des pages dédiées par série, par matière, par année — chacune optimisée pour son intention.
#[Route('/annales/{serie}', name: 'annales_serie')]
public function parSerie(string $serie, AnnaleRepository $repo): Response
{
    $annales = $repo->findBySerie($serie);

    return $this->render('annales/serie.html.twig', [
        'serie'    => $serie,
        'annales'  => $annales,
        'metaTitle' => "Annales {$serie} · Baccalauréat Sénégal",
        'metaDesc'  => "Toutes les épreuves série {$serie} du bac sénégalais, par matière et par année.",
    ]);
}
3. Données structurées JSON-LD
Les données structurées aident Google à comprendre le contenu et débloquent les résultats enrichis.

4. Sitemap dynamique et robots
Un sitemap généré depuis la base, tenu à jour automatiquement, aide Google à découvrir chaque page.
#[Route('/sitemap.xml', name: 'sitemap', defaults: ['_format' => 'xml'])]
public function sitemap(AnnaleRepository $repo): Response
{
    $urls = [];
    foreach ($repo->findAllPublished() as $a) {
        $urls[] = [
            'loc'     => $this->generateUrl('annale_show', ['slug' => $a->getSlug()], UrlGeneratorInterface::ABSOLUTE_URL),
            'lastmod' => $a->getUpdatedAt()->format('c'),
        ];
    }
    $response = $this->render('sitemap.xml.twig', ['urls' => $urls]);
    $response->headers->set('Content-Type', 'application/xml');
    return $response;
}
5. Mesurer et itérer
La Search Console est le tableau de bord du SEO. On y voit quelles pages montent (l'accueil : +386 %, les annales : +440 %), lesquelles stagnent, et sur quelles requêtes se positionner ensuite. Le SEO n'est pas un one-shot, c'est une boucle.
Ce que je retiens
  • Le rendu serveur est un prérequis non négociable pour du contenu qui doit ranker.
  • Une page = une intention de recherche précise. La granularité paie.
  • Les données structurées JSON-LD aident Google à comprendre et enrichir l'affichage.
  • Sitemap dynamique : chaque nouveau contenu est découvert vite.
  • La Search Console pilote l'itération : on suit ce qui monte, on renforce.