AI

Créer des Web Scrapers à partir d’une invite avec Kiro et Bright Data

Créer des Scrapers web à partir d’invites avec le Kiro Power de Bright Data.
33 min de lecture
Kiro Power with Bright Data

Un Scraper web tombe en panne lorsqu’un site modifie son balisage ou commence à vous bloquer. Le brightdata-scrape Kiro Power en écrit un à partir d’une invite en langage naturel et l’exécute contre le Web MCP de Bright Data, qui gère le déblocage et l’Analyse. Ce guide applique un pattern Power répétable sur 4 cas d’usage, en menant 2 jusqu’à une exécution API en direct, dont un qui vérifie si ChatGPT mentionne votre marque.

TL;DR

À la fin, vous aurez un pattern Power applicable à 4 cas d’usage, chacun piloté par une invite en langage naturel, avec 2 menés jusqu’à une exécution API en direct :

  • Suivi des prix retail , suit un produit sur Amazon et Walmart.
  • Moniteur de visibilité de marque , voit quels assistants IA mentionnent votre marque.
  • Pipeline de génération de leads LinkedIn , surveille une liste de prospects pour les changements de poste.
  • Tableau de bord d’intelligence Crunchbase , extrait des dizaines de champs en direct par entreprise.
Agent Kiro : search_engine puis scrape_as_markdown retourne un prix Amazon Sony WH-1000XM5 en direct de 248,00 $ avec l'état du stock. 0,9 crédit.

L’agent Kiro effectue 2 appels d’outils en direct , search_engine, puis scrape_as_markdown , et retourne un vrai prix Amazon de 248 $.

Qu’est-ce qu’un Kiro Power ?

Kiro est l’IDE IA conçu par AWS. Un Power est le format d’extension propre à Kiro : un dossier contenant un manifeste, une configuration de serveur MCP, des fichiers de pilotage et des modèles de code. Kiro charge un Power dans le contexte uniquement lorsque votre invite l’active. Parcourez le catalogue officiel sur kiro.dev/powers. Bright Data publie brightdata-scrape séparément sur GitHub, vous pouvez donc l’importer directement.

Les Powers diffèrent des Claude Skills sur un point important : chaque Power est livré avec une configuration de serveur MCP (Model Context Protocol) déjà en place. L’agent dispose ainsi de nouveaux outils à appeler, pas seulement d’instructions. Pour brightdata-scrape, ce serveur est le Web MCP de Bright Data.

Cet endpoint vous donne accès au Web Unlocker, à l’API SERP, à l’API Browser et au catalogue de Jeux de données préconstruits de Bright Data. Le MCP de Bright Data permet à l’agent d’utiliser n’importe lequel d’entre eux en un seul appel d’outil. Ces outils (search_engine, scrape_as_markdown, les 50 outils Pro web_data_*, scraping_browser_* et discover) remplacent ce qui était auparavant 3 intégrations séparées , un Proxy, une API SERP et une ferme de navigateurs , par un seul ensemble d’identifiants et un seul pattern de réessai.

Installer le Kiro Power brightdata-scrape

Il y a 5 étapes pour configurer le projet et confirmer la connexion :

  1. Obtenir un token API Bright Data. Sous Utilisateurs et clés API → Clés API, ajoutez une clé avec la permission Utilisateur, définissez une expiration et copiez la valeur. Aucune carte bancaire n’est nécessaire pour le niveau gratuit.
  2. Installer Kiro, puis créer et ouvrir le projet. Téléchargez et installez Kiro. Le Power a besoin d’un projet pour fonctionner, et ce guide utilise Next.js, alors créez-en un et ouvrez le dossier price-tracker dans Kiro :

npx create-next-app@latest price-tracker \

–typescript, app, tailwind, src-dir, use-npm

cd price-tracker

Vous n’avez rien d’autre à installer maintenant. Kiro ajoutera les packages dont le Scraper généré a besoin plus tard, en Phase 3.

  1. Installer le Power. Ouvrez le panneau Powers dans Kiro (l’icône dans la barre d’activité gauche). Cliquez sur Add Custom Power, puis Import power from GitHub, et collez cette URL :

https://github.com/brightdata/kiro-powers/tree/main/brightdata-scrape

Modal Kiro Add Custom Power : URL GitHub brightdata-scrape collée dans le champ de saisie, avec l'indication 'Appuyez sur Entrée pour confirmer' visible.
  1. Fournir le token à Kiro. L’installation du Power ajoute un serveur brightdata au fichier .kiro/settings/mcp.json de votre projet avec l’URL https://mcp.brightdata.com/mcp?token=${BRIGHTDATA_API_KEY}. Ouvrez ce fichier, remplacez ${BRIGHTDATA_API_KEY} par le token littéral copié à l’étape 1, et sauvegardez. Ajoutez ensuite .kiro/settings/mcp.json au .gitignore pour que le token ne soit jamais commité.

> Pourquoi le token littéral et non le placeholder ${…} ? Kiro n’étend pas actuellement ${VAR} dans mcp.json (un problème connu ouvert), donc le placeholder vous donne Connection Failed / HTTP 404 au lieu d’une connexion.

  1. Confirmer la connexion. Rouvrez le panneau MCP Servers. Après quelques secondes, brightdata affiche Connected avec search_engine et scrape_as_markdown parmi ses outils, ce qui est le signal dont vous avez besoin.
Panneau MCP Servers de l'IDE Kiro affichant brightdata Connected (5 outils), après l'installation du Kiro Power brightdata-scrape.

Créez maintenant .env.local à la racine du projet et placez-y le même token. Vous collez le token deux fois intentionnellement : la copie dans .kiro/settings/mcp.json (étape 4) connecte Kiro à Bright Data pendant la construction, et cette copie est lue par l’application générée lors de son exécution.

BRIGHTDATA_API_KEY=...          # le token que vous avez généré ci-dessus
BRIGHTDATA_UNLOCKER_ZONE=...    # un placeholder convient pour la version retail ; à définir avant un cas d'usage Web Unlocker

Sur un nouveau compte, ou avant d’exécuter un cas d’usage Web Unlocker, définissez d’abord le nom de votre zone. Voir Définir votre zone Web Unlocker dans la section Passer les 4 cas d’usage en production ci-dessous.

Pour les 4 cas d’usage, seule l’invite change ; le workflow en 4 phases reste identique.

Le workflow en 4 phases de Kiro (un seul pattern pour les 4)

Le Power exécute les mêmes 4 phases pour chaque invite. Chaque phase attend votre approbation avant de continuer :

  1. Détecter & planifier. Le Power vérifie le manifeste du workspace (package.json, pyproject.toml, Cargo.toml, go.mod, etc.) et les dépendances qu’il contient. Il choisit ensuite comment intégrer : s’il trouve un framework web, il génère une route API ; s’il trouve un SDK agent, il génère un outil agent ; et si le projet est une bibliothèque, il génère un module. Il vous demande quoi scraper et combien d’éléments.
  1. Playbook de Scraping. Le Power vérifie l’échelle d’outils de Bright Data et, pour chaque site cible, choisit le meilleur chemin que votre niveau autorise : un outil Web Data Pro (l’un des 50 outils web_data_* sur 30+ plateformes, champs typés, nécessite &pro=1) → un déclencheur de dataset (mêmes données, interrogées, sans &pro=1) → Web Unlocker (Proxy + Analyse pour les sites longue traîne) → Browser API (flux de connexion/clic) → API SERP (résultats de recherche).
Kiro Phase 2 : dataset préconstruit choisi pour Amazon et Walmart, avec la porte de confirmation 'Ready to proceed to Phase 3?'. 0,38 crédit, 1m 24s.
  1. Intégrer. Le Power génère les fichiers. L’exécution retail ci-dessous en a produit 4 : un module Scraper, une route API, une page de tableau de bord et une nouvelle section ## Scraping web dans README.md. (.env.local contenait déjà le token API, donc la Phase 3 l’a ignoré. C’est la règle de sécurité des fichiers : elle n’écrase pas un fichier qui existe déjà.)
Chat Kiro montrant la Phase 3 du Power brightdata-scrape terminée : quatre fichiers écrits, zéro erreur TypeScript, 1,38 crédit utilisé en 1m 56s.
  1. MCP & vérifier. Le Power fusionne le serveur MCP de Bright Data dans .kiro/settings/mcp.json et exécute un test de fumée contre l’URL cible. Deux protections de production s’exécutent dans cette phase : le diff-avant-écrasement, et la récupération FAIL → ITERATE. La Phase 4 du cas d’usage 1 montre la récupération en entier.

Ce qui a été exécuté en direct, et ce qui est présenté

Tout ce qui est présenté ici est vérifié contre l’API en direct, pas une maquette. Les prix exacts, les outils et les timings proviennent d’exécutions capturées spécifiques. Comme les Scrapers lisent des données en direct, vos propres résultats refléteront les prix, pages et réponses des modèles actuels, pas ceux capturés ici.

  • Les cas d’usage 1 et 4 ont été exécutés en entier contre l’API en direct : retail (sans dépense Pro) et Crunchbase (sur le niveau Pro). Chaque capture d’écran retail ci-dessous provient de cette exécution, et le code complet du cas d’usage 4 est dans sa section.
  • Les cas d’usage 2 et 3 sont présentés, pas reconstruits : l’invite, les outils que la Phase 2 choisirait, et les formes de champs dont nous avons vérifié les noms en direct contre chaque outil. Ils réutilisent le client callMcpTool du cas d’usage 4, évitant ainsi de recoller du code quasi-identique.
  • Les cas d’usage 2, 3 et 4 s’exécutent en mode Pro (&pro=1), ce que couvre la section Passer en production ci-dessous.

Cas d’usage 1 : suivi des prix multi-retailers

Voici l’invite pour Kiro :

Invite à Kiro : « Ajouter un agent de comparaison de prix qui scrape les prix du Sony WH-1000XM5 sur Amazon et Walmart. »

Choix de la Phase 2 : Sur l’exécution capturée sans Pro, le Power a choisi le chemin dataset-trigger (mêmes données, interrogées). Avec &pro=1, il choisirait plutôt les outils Pro web_data_amazon_product et web_data_walmart_product.

Étendre à d’autres retailers : le même pattern ajoute web_data_ebay_product, web_data_homedepot_products et web_data_bestbuy_products en ré-invitant Kiro avec une liste de retailers plus large. Certains retailers (Best Buy, Target) nécessitent généralement l’activation des domaines Premium sur la zone ; Amazon et Walmart ne l’ont pas requis lors de l’exécution capturée.

L’architecture générée par Kiro

Le tableau de bord récupère l’API au montage. L’API appelle les déclencheurs de dataset de Bright Data en parallèle et retourne les enregistrements structurés.

       Browser opens /
                │
                ▼ (auto-fetch on mount)
        GET /api/scrape-prices
                │
                ▼
    src/scrapers/price-tracker.ts
        fetchAllPrices()
                │
                ▼ (Promise.allSettled, parallel)
   ┌────────────────────────────────────┐
   │  Bright Data Datasets API          │
   │  gd_l7q7dkf244hwjntr0 → Amazon     │
   │  gd_l95fol7l1ru6rlo116 → Walmart   │
   └────────────────────────────────────┘

Un seul chemin de lecture : tableau de bord → route API → module Scraper → 2 déclencheurs de dataset Bright Data. Avec &pro=1, le module Scraper devient des appels MCP web_data_* directs, et la boucle de polling côté client se déplace dans le serveur MCP.*

Le module Scraper

src/scrapers/price-tracker.ts contient les IDs de dataset, un helper triggerAndPoll, et une étape normalise qui aplatit la réponse de Bright Data en une forme PriceResult cohérente. Voici le cœur du fichier, qui fait environ 85 lignes en tout :

// src/scrapers/price-tracker.ts (extrait)
const BASE = "https://api.brightdata.com/datasets/v3";
const DATASETS = { Amazon: "gd_l7q7dkf244hwjntr0", Walmart: "gd_l95fol7l1ru6rlo116" } as const;

async function triggerAndPoll(datasetId: string, url: string) {
  // 1. POST trigger avec l'URL cible
  const trigger = await fetch(`${BASE}/trigger?dataset_id=${datasetId}&include_errors=true`, {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.BRIGHTDATA_API_KEY}`,
               "Content-Type": "application/json" },
    body: JSON.stringify([{ url }]),
  });
  const { snapshot_id } = await trigger.json();
  if (!snapshot_id) throw new Error("no snapshot_id returned from trigger");

  // 2. Interroger l'endpoint snapshot (en cours = HTTP 202 ; plafond ~120 s)
  for (let i = 0; i < 24; i++) {
    await new Promise((r) => setTimeout(r, 5000));
    const res = await fetch(`${BASE}/snapshot/${snapshot_id}?format=json`,
      { headers: { Authorization: `Bearer ${process.env.BRIGHTDATA_API_KEY}` } });
    if (res.status === 202) continue;
    return await res.json();
  }
  throw new Error("snapshot timed out after 120s");
}

// déclenche les deux retailers en parallèle ; Promise.allSettled isole les erreurs par retailer,
// donc un mauvais snapshot n'échoue pas l'autre. Le fichier complet mappe chaque résultat settled
// en un PriceResult (les rejetés portent un champ `error`).
export async function fetchAllPrices() {
  return Promise.allSettled(
    Object.entries(DATASETS).map(([retailer, id]) =>
      triggerAndPoll(id, PRODUCT_URLS[retailer]).then((r) => normalise(r[0], retailer, PRODUCT_URLS[retailer]))),
  );
}

Le chat de Kiro est un client MCP en direct, pas une recherche en mémoire

Pendant la construction, le panneau de chat de Kiro communique avec le même serveur brightdata que votre code appelle. Interrogé sur le prix Sony, le chat n’a pas répondu depuis la mémoire du modèle. Il a effectué des appels search_engine et scrape_as_markdown en direct et retourné un tableau (195,55 $ reconditionné à 248 $ neuf, plus une comparaison XM6 à 398 $) :

Chat Kiro, exécution complète : l'agent choisit lui-même search_engine puis scrape_as_markdown, retournant un prix Amazon Sony WH-1000XM5 en direct. 1m 24s, 0,9 crédit.

Le chat est la façon dont vous explorez pendant la construction. Le tableau de bord ci-dessous est ce que vos utilisateurs finaux voient.

Le tableau de bord

La route principale (/) générée par Kiro affiche le JSON retourné par l’API sous forme de 2 cartes colorées (orange Amazon et bleu Walmart) avec une bannière verte « Meilleur prix » indiquant le moins cher des 2 :

La route principale (/) à 14h27 le 28 mai 2026 : Sony WH-1000XM5 à 248 $ sur Amazon et Walmart, affiché sous forme de cartes avec une bannière verte "Meilleur prix" sur Amazon.

La vue de la route principale (/). Sony WH-1000XM5 à 248 $ sur Amazon et Walmart avec les titres des produits, l’état du stock et les horodatages par retailer lus directement depuis chaque source. Le in_stock brut de Walmart et le In Stock d’Amazon sont transmis tels quels, vous voyez donc exactement ce que chaque source retourne. Normalisez selon votre propre schéma lorsque vous construisez des alertes dessus.

Si vous inspectez vous-même les pages brutes, le sélecteur de prix évident d’Amazon (span.a-price-whole) retourne généralement vide, et le vrai est .a-price .a-offscreen. Walmart ne met pas du tout le prix dans le HTML rendu ; il se trouve dans un blob JSON dans <script id="NEXT_DATA">. Les déclencheurs de dataset ci-dessus évitent ces deux problèmes car Bright Data analyse les pages côté serveur et retourne des champs typés.

Phase 4 : auto-réparation quand l’URL dérive

La Phase 4 est la routine de récupération que le Power exécute automatiquement quand un test de fumée échoue. Dans l’exécution capturée, Amazon a retourné des données propres (248 $, In Stock), mais Walmart a retourné tous les champs à null. Kiro n’a pas déclaré le succès. À la place, il a lu la clé error de l’enregistrement brut (« dead page (404) »), appelé search_engine pour trouver l’URL Walmart actuelle, ré-déclenché le dataset, et basculé vers scrape_as_markdown quand le polling a stagné (retourné 248 $, correspondant à Amazon). Puis il a patché le Scraper généré :

Résumé de la Phase 4 de Kiro montrant la récupération auto-réparatrice : Amazon 248 $ confirmé, URL Walmart obsolète détectée et patchée via MCP scrape. 4,5 crédits, 18m 54s.

La Phase 4 détecte l’URL Walmart morte, trouve la bonne, et patche le Scraper de lui-même. Les 18m 54s incluent le job de dataset ré-interrogé, et les 4,5 crédits sont un coût de phase de construction unique, pas un coût d’exécution.

La boucle de récupération capture les échecs qui lèvent une erreur ou retournent des champs null (404 morts, pages redessinées, erreurs de snapshot). Mais elle ne capture pas une URL qui se résout encore mais pointe vers le mauvais produit. Par exemple, un ID walmart.com/ip/... qui a silencieusement changé des écouteurs Sony vers une liste PS5 retourne des données valides pour le mauvais produit. Pour capturer ce cas, vous avez besoin d’URLs pilotées par la recherche plutôt que d’IDs codés en dur (couvert dans la section passage en production ci-dessous).

Coût capturé sur les phases 2,4 (chacun visible dans les captures d’écran ci-dessus) : 0,38 → 1,38 → 4,5 crédits (total cumulé). Ce sont des crédits de construction dans l’IDE Kiro, l’utilisation de l’agent pendant qu’il écrit le code, séparés de la facturation Bright Data. Donc cette exécution capturée a coûté 4,5 crédits au total, mais la majeure partie était l’auto-réparation unique de la Phase 4. Une construction propre sans récupération représente environ 2 crédits (estimé, car nous n’avons pas capturé d’exécution sans auto-réparation).

Protections de production : auto-réparation, pas d’écrasements silencieux, modèles validés CI

Dans le cas d’usage 1, la Phase 4 a capturé une URL Walmart morte et a refusé de déclarer le succès. Ce comportement n’est pas improvisé à chaque exécution. Il provient des règles de production intégrées dans les fichiers de pilotage du Power. Voici l’ensemble complet de ces règles :

  • Sécurité des fichiers (Phase 3). Le Power n’écrase pas un Scraper existant (il suggère _2.ts), ajoute à README.md / .env.example au lieu de remplacer, et affiche une liste CREATE/MODIFY avant d’écrire.
  • Fusion de config MCP (Phase 4). Le Power détecte une entrée brightdata existante dans .kiro/settings/mcp.json, affiche un diff si l’URL diffère, et demande avant de remplacer, donc pas d’écrasements silencieux.
  • Test de fumée FAIL → ITERATE. Après connexion MCP, le Power exécute le Scraper contre votre cible. Sur vide, null ou erreur, le pilotage dit, mot pour mot, « retourner à la Phase 2… Ne pas déclarer le succès. »
  • Modèles testés CI (49 tests passent). validate_power.py et test_validate_power.py vérifient le frontmatter, la config MCP, le pilotage et la présence des modèles. Ils ne testent pas le code généré contre un site en direct ; c’est le rôle du test de fumée de la Phase 4, par projet.
  • Provisionnement automatique de zone. Le serveur MCP appelle /zone/get_active_zones et crée les zones manquantes à la première exécution, donc un nouveau compte n’a pas besoin de créer manuellement une zone Web Unlocker en premier.

Cas d’usage 2 : moniteur de visibilité de marque GEO

Le problème de visibilité. Les acheteurs forment de plus en plus leur liste restreinte sur les pages de réponses LLM (ChatGPT, Grok, Perplexity) avant de parler aux commerciaux, donc être en dehors du top 3 signifie que beaucoup d’acheteurs pourraient ne jamais vous voir. Le problème est que les outils traditionnels de surveillance de marque (PR, écoute sociale, SEO) n’ont pas été conçus pour surveiller les réponses LLM, donc vous ne pouvez pas voir de façon fiable où vous vous classez.

Invite à Kiro : « Ajouter un moniteur de visibilité de marque qui scrape comment ChatGPT, Grok et Perplexity répondent à mes 5 requêtes acheteurs prioritaires, et m’alerte quand ma marque cesse d’être mentionnée. »

Les outils GEO et ce qu’ils retournent

Outils Pro pour ce cas d’usage : La Phase 2 choisirait le groupe geo : web_data_chatgpt_ai_insights, web_data_grok_ai_insights et web_data_perplexity_ai_insights. Chaque outil est son moteur (il n’y a pas de sélecteur de moteur), prend un seul argument prompt et retourne la réponse LLM rendue en markdown. Avec un outil par moteur, vous couvrez les 3 principales pages de réponses que vos acheteurs utilisent aujourd’hui, pas seulement ChatGPT.

La Phase 3 génère un module src/scrapers/brand_visibility.ts qui appelle chaque outil web_data_* avec un seul { prompt } et collecte son answer_text_markdown. ChatGPT et Perplexity retournent en ligne et s’exécutent ensemble sous Promise.all. Grok dépasse généralement la fenêtre de poll MCP et retourne de façon asynchrone, il reste donc sur un chemin non-bloquant séparé ; traitez-le comme éventuellement cohérent, pas un appel bloquant.

Voici la forme de réponse en direct, capturée directement depuis web_data_chatgpt_ai_insights et web_data_perplexity_ai_insights avec l’invite « Quel est le meilleur CDP pour les SaaS mid-market ? », et les deux ont retourné la même forme à champ unique (l’appel asynchrone de Grok a dépassé un poll de 9 minutes) :

{
  "answer_text_markdown": "Pour la plupart des **entreprises SaaS mid-market (environ 50 à 1 000 employés)**, la réponse dépend moins de \"quel CDP est le meilleur\" que de la maturité de votre stack de données. Mon classement : 1) [Hightouch](https://hightouch.com?utm_source=chatgpt.com) , warehouse-native ; 2) [Twilio Segment](https://segment.com?utm_source=chatgpt.com) , tout-en-un ; 3) [RudderStack](https://www.rudderstack.com?utm_source=chatgpt.com) , orienté ingénierie..."
}

L’outil retourne la réponse du modèle sous forme d’une seule chaîne answer_text_markdown, pas un classement de marque pré-analysé. L’étape d’extraction de marque vous appartient. Une première approche naïve est une simple vérification includes() sur le markdown, mais elle rate la casse, les variantes de nom et votre marque apparaissant à l’intérieur d’un autre mot. Pour tout usage réel, passez le markdown à un appel LLM peu coûteux et demandez la liste classée.

Kiro exécutant web_data_chatgpt_ai_insights : un `prompt` en entrée, un `answer_text_markdown` en sortie ; la réponse classe Hightouch, Twilio Segment, RudderStack.

La boucle d’alerte et qui l’installe

La boucle d’alerte fonctionne ainsi : elle stocke 1 ligne answer_text_markdown par moteur par jour, puis elle extrait si (et où) votre marque apparaît, puis elle vous alerte quand votre marque disparaît d’une réponse où elle figurait, et enfin elle affiche une grille à 3 moteurs des réponses du jour avec des indicateurs de présence de marque.

Une mise en garde avant de câbler les alertes : les réponses LLM sont non-déterministes, donc la même invite peut classer les marques différemment d’une exécution à l’autre. Un seul fetch quotidien est un échantillon, pas un signal stable, donc une marque qui disparaît pendant un jour est souvent du bruit, pas un vrai changement. Échantillonnez chaque invite plusieurs fois, ou lissez sur plusieurs jours, avant de traiter une baisse comme réelle.

Qui installe ceci : C’est pour les équipes marketing B2B SaaS et DevRel, les agences de surveillance de marque ajoutant une couverture LLM, et les chercheurs IA/ML suivant la dérive des sorties de modèles. L’utilisation correspond à 5 invites sur 3 moteurs interrogés quotidiennement, soit environ 450 appels/mois, ou environ 0,68 $/mois au tarif paiement à l’utilisation.

Cas d’usage 3 : pipeline de génération de leads LinkedIn

Le problème B2B est que vous devez suivre 50 prospects commerciaux (ou candidats, ou contacts de programme partenaire) pour des changements de poste, de société ou des promotions. La solution habituelle est LinkedIn Sales Navigator plus un workflow de révision manuelle. L’option données structurées est 1 appel MCP par prospect, interrogé quotidiennement.

Invite à Kiro : « Surveiller ces 50 prospects LinkedIn pour des changements de poste, de société ou des promotions. Notifier mon CRM quand quelque chose change. »

Les outils LinkedIn et ce qu’ils retournent

Outils Pro pour ce cas d’usage. La Phase 2 choisirait le cluster LinkedIn dans le groupe social : web_data_linkedin_person_profile, web_data_linkedin_company_profile, web_data_linkedin_job_listings et web_data_linkedin_people_search.

Voici ce que la Phase 3 génère (noms de champs vérifiés en direct contre l’outil) :

// src/scrapers/linkedin_prospects.ts (extrait)
import { callMcpTool } from "@/lib/mcp-client"; // Kiro génère cet appel client MCP en Phase 3 , pas un package installable

interface ProspectSnapshot {
  url: string;
  current_company_name: string;  // current_company est un objet imbriqué ; *_name est la chaîne
  position: string;              // champ titre du poste , il n'y a pas de "current_title"
  location: string;
  followers: number;
}

type Change = { field: string; from: string; to: string };

export const snapshotProspect = (url: string) =>
  callMcpTool("web_data_linkedin_person_profile", { url }) as Promise<ProspectSnapshot>;

// Diff aujourd'hui vs. hier ; émet un Change pour tout champ qui a bougé.
export function diffProspect(prev: ProspectSnapshot, now: ProspectSnapshot): Change[] {
  return (["current_company_name", "position"] as const)
    .filter((f) => prev[f] !== now[f])
    .map((f) => ({ field: f, from: prev[f], to: now[f] }));
}

L’enregistrement complet retourne 30+ champs typés, incluant current_company (objet), experience[], education[], about, followers, connections, city, country_code, et plus.

La boucle de notification CRM et qui l’installe

La boucle de notification CRM fonctionne ainsi : elle stocke le snapshot d’hier par prospect, puis elle exécute le fetch et le diff du jour une fois par jour depuis un worker en arrière-plan, puis elle envoie les changements au webhook de votre CRM (Salesforce, HubSpot, Attio, pas le MCP de Bright Data).

Qui installe ceci : C’est pour les équipes commerciales B2B, le recrutement, RevOps et les responsables de programme partenaire. L’utilisation correspond à 50 prospects interrogés quotidiennement, soit environ 1 500 appels/mois, ou environ 2,25 $/mois au PAYG.

Cas d’usage 4 : tableau de bord d’Intelligence compétitive

Le problème corp-dev et stratégie est le suivant : les équipes doivent suivre une liste de surveillance de concurrents et de cibles d’acquisition pour les tours de financement, les changements d’effectifs et les changements de momentum. Le niveau de base commun est un workflow manuel de rafraîchissement Crunchbase et tableur. L’option données structurées est 1 appel MCP par entreprise, interrogé hebdomadairement.

Invite à Kiro : « Suivre ces 30 concurrents sur Crunchbase. M’alerter quand l’un d’eux lève un tour, franchit une tranche d’effectifs, ou fait un bond dans le classement de croissance. »

L’outil Crunchbase et ce qu’il retourne

Outil Pro choisi en Phase 2 : Le Power choisit web_data_crunchbase_company (le groupe business). Vérifié en direct, il retourne 93 champs typés par entreprise, incluant funds_raised, num_funding_rounds, acquisitions, exits, num_employees, cb_rank, growth_score, heat_score, founders, built_with_tech, ipo_status et region.

Voici ce que la Phase 3 génère :

// src/scrapers/competitor_intel.ts
import { callMcpTool } from "@/lib/mcp-client"; // Kiro génère cet appel client MCP en Phase 3 , pas un package installable

interface CompanySnapshot {
  name: string;
  num_employees: string;      // tranche, ex. "5001-10000"
  cb_rank: number;            // classement Crunchbase (plus bas = plus prominent)
  growth_score: number;       // 0-100
  heat_score: number;         // signal de momentum 0-100
  funds_raised: unknown[];    // tableau d'événements de financement/investissement
  ipo_status: string;         // "private" | "public" | ...
  region: string;
  url: string;
}

type Alert =
  | { kind: "headcount_band"; from: string; to: string }
  | { kind: "new_funding_event"; count: number }
  | { kind: "growth_surge"; from: number; to: number };

// la ligne MCP arrive non typée, donc vous mappez uniquement les champs suivis dans un CompanySnapshot typé
export async function snapshotCompany(url: string): Promise<CompanySnapshot> {
  const row = await callMcpTool<Record<string, unknown>>("web_data_crunchbase_company", { url });
  return {
    name: String(row.name ?? ""),
    num_employees: String(row.num_employees ?? ""),
    cb_rank: Number(row.cb_rank ?? 0),
    growth_score: Number(row.growth_score ?? 0),
    heat_score: Number(row.heat_score ?? 0),
    funds_raised: Array.isArray(row.funds_raised) ? row.funds_raised : [],
    ipo_status: String(row.ipo_status ?? ""),
    region: String(row.region ?? ""),
    url,
  };
}

export function detectMoves(
  prev: CompanySnapshot, now: CompanySnapshot,
): Alert[] {
  const alerts: Alert[] = [];
  if (now.num_employees !== prev.num_employees) {
    alerts.push({ kind: "headcount_band", from: prev.num_employees, to: now.num_employees });
  }
  if (now.funds_raised.length !== prev.funds_raised.length) {
    alerts.push({ kind: "new_funding_event", count: now.funds_raised.length - prev.funds_raised.length });
  }
  if (now.growth_score - prev.growth_score >= 5) {
    alerts.push({ kind: "growth_surge", from: prev.growth_score, to: now.growth_score });
  }
  return alerts;
}

Échantillon en direct. Un vrai appel à web_data_crunchbase_company pour Stripe a retourné num_employees: "5001-10000", cb_rank: 300, growth_score: 98, heat_score: 60, ipo_status: "private", region: "California", plus un tableau funds_raised rempli d’événements d’investissement.

Kiro exécutant web_data_crunchbase_company pour Stripe : une `url` en entrée, un enregistrement structuré en sortie montrant `name: Stripe`, `cb_rank: 300`, `region: California`.

Le Power a généré les 4 fichiers (le Scraper ci-dessus, le client ci-dessous, une route API, une page de tableau de bord), et le code généré a compilé avec zéro erreur TypeScript. Avec BRIGHTDATA_API_KEY défini, l’exécuter contre le MCP en direct (~58 s pour le scrape en direct) a retourné l’enregistrement Stripe ci-dessus et rendu ceci :

Tableau de bord d'intelligence compétitive depuis un appel web_data_crunchbase_company en direct : Stripe à cb_rank #300, croissance 98/100, heat 60/100, 10 événements de financement.

La route principale (/), rendue en direct depuis le même appel web_data_crunchbase_company qui a retourné l’enregistrement Stripe ci-dessus.

Pour l’exécuter vous-même, clonez le repo exemple : git clone https://github.com/triposat/crunchbase-intel-demo && cd crunchbase-intel-demo && npm install && cp .env.example .env.local, collez un token activé Pro, et exécutez npm run dev. (&pro=1 est déjà dans le mcp-client.ts du repo ; vous avez juste besoin d’un compte avec le mode Pro activé.)

Le client MCP partagé

Le callMcpTool que le Scraper importe est un client MCP léger que le Power génère en Phase 3 , le même que les modules GEO et LinkedIn sont écrits pour réutiliser. Le voici en entier :

// src/lib/mcp-client.ts , le client vers lequel callMcpTool se résout
const MCP_URL = `https://mcp.brightdata.com/mcp?token=${process.env.BRIGHTDATA_API_KEY}&pro=1`;

async function post(body: unknown, sessionId?: string) {
  const headers: Record<string, string> = {
    "Content-Type": "application/json",
    Accept: "application/json, text/event-stream",
  };
  if (sessionId) headers["mcp-session-id"] = sessionId;
  return fetch(MCP_URL, { method: "POST", headers, body: JSON.stringify(body) });
}

// le serveur répond en SSE : un objet JSON par ligne `data:`
function parseSse(text: string) {
  if (!text.includes("data:")) {
    try { return [JSON.parse(text)]; }
    catch { throw new Error(`MCP a retourné une réponse non-JSON : ${text.slice(0, 120)}`); }
  }
  return text.split("\n").filter((l) => l.startsWith("data:"))
    .map((l) => { try { return JSON.parse(l.slice(5).trim()); } catch { return null; } })
    .filter(Boolean);
}

export async function callMcpTool<T = unknown>(name: string, args: Record<string, unknown>): Promise<T> {
  // 1. initialiser , l'id de session revient comme en-tête de réponse
  const init = await post({ jsonrpc: "2.0", id: 1, method: "initialize",
    params: { protocolVersion: "2024-11-05", capabilities: {}, clientInfo: { name: "intel", version: "1.0" } } });
  if (!init.ok) throw new Error(`Échec de connexion MCP : HTTP ${init.status} ${init.statusText}. Vérifiez BRIGHTDATA_API_KEY.`);
  const sessionId = init.headers.get("mcp-session-id") ?? undefined;
  await init.text();

  // 2. confirmer initialized, puis 3. appeler l'outil
  await post({ jsonrpc: "2.0", method: "notifications/initialized", params: {} }, sessionId);
  const res = await post({ jsonrpc: "2.0", id: 2, method: "tools/call", params: { name, arguments: args } }, sessionId);
  if (!res.ok) throw new Error(`Échec de l'appel d'outil MCP : HTTP ${res.status} ${res.statusText}.`);

  const reply = parseSse(await res.text()).find((m: { id?: number }) => m?.id === 2);
  if (reply?.error) throw new Error(`Erreur MCP : ${reply.error.message}`);
  const text = reply?.result?.content?.find((c: { type: string }) => c.type === "text")?.text;
  const payload = text ? JSON.parse(text) : reply?.result;
  return (Array.isArray(payload) ? payload[0] : payload) as T;
}

Placez ce fichier dans src/lib/, et le Scraper Crunchbase ci-dessus est prêt à s’exécuter.

La boucle de surveillance et qui l’installe

La boucle de surveillance fonctionne ainsi : elle stocke le snapshot de la semaine dernière par entreprise, puis elle compare le snapshot de cette semaine avec celui de la semaine dernière, puis elle poste tout événement de financement, franchissement de tranche d’effectifs ou surge de score de croissance dans votre canal Slack stratégie. L’utilisation correspond à 30 entreprises interrogées hebdomadairement, soit environ 120 appels/mois, ou environ 0,18 $/mois au PAYG.

Qui installe ceci : C’est pour le développement corporate, l’Intelligence compétitive, la stratégie, les équipes de deal VC/PE et les commerciaux construisant de l’intel compte. Ces équipes ont besoin de profondeur de données plutôt que de volume retail, car elles veulent 93 champs structurés par entreprise qu’elles rassembleraient sinon manuellement.

Passer les 4 cas d’usage en production

Les Scrapers générés compilent avec zéro erreur TypeScript et s’exécutent contre l’API en direct (les exécutions retail et Crunchbase ci-dessus), avec les protections ci-dessus. Ces changements les amènent à l’échelle de production, en ajoutant les jobs en arrière-plan, les tables de snapshots et les paramètres de volume que les vraies charges de travail nécessitent :

  • Passer aux outils Pro. Ajoutez &pro=1 à l’URL MCP dans .kiro/settings/mcp.json pour qu’elle devienne https://mcp.brightdata.com/mcp?token=<votre-token>&pro=1, et redémarrez le serveur. (Notez le & initial, car token= ouvre déjà la chaîne de requête.) La Phase 2 choisit les outils web_data_* au lieu des déclencheurs de dataset. Le polling tombe généralement à quelques secondes, et l’Analyse devient une lecture de champ typé. Le flag va à 2 endroits : .kiro/settings/mcp.json, pour que l’agent Kiro voie les outils Pro, et le src/lib/mcp-client.ts de l’application générée, pour que l’application en cours les appelle.
  • Définir votre zone Web Unlocker. Le chemin Web Unlocker lit BRIGHTDATA_UNLOCKER_ZONE, et votre zone a un nom spécifique au compte (web_unlocker, mcp_unlocker, web_unlocker1, etc.). Trouvez le nom exact dans votre tableau de bord Web Access et définissez-le dans .env.local. Une non-concordance retourne HTTP 400 avec zone not found. Sur un nouveau compte, le tableau peut être vide jusqu’à ce que le serveur MCP auto-provisionne une zone à son premier appel. Si 2 zones apparaissent, choisissez celle marquée Free tier.
  • Déplacer le polling hors du chemin de requête. Dans nos exécutions, un déclencheur web_data_* à enregistrement unique retournait en environ 10 à 90 s et multi-enregistrement en plusieurs minutes. La latence varie, et les outils de réponse LLM comme Grok peuvent largement dépasser la fenêtre de poll. Le serveur MCP continue de poller pendant plusieurs minutes avant de timeout (la variable d’env POLLING_TIMEOUT fixe le plafond). Pour la production, exécutez les déclencheurs depuis un worker en arrière-plan (Vercel Cron, Inngest, Trigger.dev) et écrivez dans une table de snapshots. Le tableau de bord lit depuis la table, pas le scrape en direct. (L’API Dataset directe hors MCP supporte la livraison par webhook si vous avez besoin de push au lieu de poll, défini avec les paramètres notify et endpoint. Voir la documentation trigger-a-collection de Bright Data.)
  • Batch + scope. scrape_batch et search_engine_batch exécutent plusieurs URLs par appel, réduisant la surcharge de tokens par URL. Ajouter &groups=ecommerce,social,geo,business à l’URL MCP charge uniquement les groupes d’outils dont votre cas d’usage a besoin, réduisant la poignée de main de liste d’outils que l’agent doit lire. Les 11 groupes sont ecommerce, social, finance, business, research, app_stores, travel, geo, code, browser et advanced_scraping.
  • Modèles multi-stack. Le Power inclut 22 modèles de production : routes de framework web pour TS (Next, Express, Fastify, Hono, Koa) et Python (FastAPI, Flask, Django), outils SDK agent (Anthropic, OpenAI, LangChain, Vercel AI SDK, Mastra), et modules génériques (TS fetch + Cheerio, Python stdlib + BeautifulSoup, et un curl.sh universel). Kiro détecte 7 langages par manifeste et choisit la correspondance, mais la génération de code de premier ordre est TS et Python uniquement. Go, Rust, Ruby, Java et PHP sont détectés et routés vers le fallback curl.sh.
  • URLs pilotées par la recherche, pas codées en dur. Les URLs codées en dur peuvent se casser lors de la rotation d’ID de listing, où un ID obsolète se résout encore mais pointe vers le mauvais produit (l’échec PS5-vs-écouteurs du cas d’usage 1 que la boucle de récupération ne peut pas capturer). La correction intégrée est de déclencher les datasets en mode découverte au lieu de par URL. Remplacez le corps du déclencheur de dataset de [{ url }] par une requête de découverte (discover_by=keyword, category_url, ou best_sellers_url), pour que Bright Data trouve le produit actuel. Voir la documentation trigger-a-collection de Bright Data pour la forme de requête discover.
  • Flux de connexion + pilotage. Browser API gère les sites à mur d’authentification avec une interface de snapshot ARIA (style refs Playwright-MCP) conçue pour l’utilisation agent. Ajoutez .kiro/steering/<votre-domaine>.md à votre workspace pour remplacer le pilotage intégré du Power sans le forker. Utilisez les APIs officielles quand la source en publie.
Tableau de bord Web Access de Bright Data : cinq lignes API, deux typées "Web Unlocker API" , `mcp_unlocker` (badge vert "Free tier") et `web_unlocker`.

Avec &pro=1 défini, rouvrir le panneau MCP affiche le catalogue complet d’outils :

Panneau MCP Servers de Kiro après `&pro=1` : `brightdata Connected (72 outils)`, la famille Pro `web_data_*` étendue (geo, finance, social, code, browser).

Prochaines étapes

Un seul Power pilote les 4 cas d’usage depuis un seul endpoint MCP, vous passez donc votre temps sur l’intégration et la logique d’alerte plutôt que sur la plomberie du Scraper.

Construisez le tracker retail vous-même. Collez https://github.com/brightdata/kiro-powers/tree/main/brightdata-scrape dans Add Custom Power → Import power from GitHub de Kiro, puis exécutez l’invite du cas d’usage 1. Dans notre exécution, cela a pris 20 à 30 minutes, n’a utilisé aucune dépense Pro, et a confirmé à la fois l’installation et le workflow en 4 phases. Pressé ? Clonez plutôt l’application terminée : git clone https://github.com/triposat/retail-price-tracker && cd retail-price-tracker && npm install && cp .env.example .env.local, ajoutez un token Bright Data gratuit, et exécutez npm run dev.

Puis passez à l’échelle en ré-invitant, pas en réécrivant. Ajoutez &pro=1 dans .kiro/settings/mcp.json et exécutez l’une des 3 invites de niveau Pro ci-dessus (GEO, LinkedIn ou intel Crunchbase) au tarif paiement à l’utilisation. Pas de nouveau code, juste une nouvelle invite contre le même Power.

Pour aller plus loin : la page Web MCP pour la liste complète des outils, et l’article sur le workflow de chat Kiro de Bright Data pour les mêmes outils utilisés de façon interactive.

Questions fréquemment posées

Qu’est-ce qui est gratuit et qu’est-ce qui est payant ?

Gratuit : vous obtenez 5 outils de base dans le Web MCP (search_engine, search_engine_batch, scrape_as_markdown, scrape_batch et discover), avec 5 000 requêtes/mois sans frais (selon le README MCP de Bright Data). Payant : les outils Pro web_data* coûtent de l’argent, tout comme le chemin dataset-trigger que la version retail utilise, qui appelle directement l’API Datasets de Bright Data. Ce chemin est facturé séparément, avec un essai gratuit d’environ 1 000 enregistrements puis environ 1,50 $/1 000 enregistrements, donc scraper quelques produits par exécution vous coûte généralement une fraction de centime.

Quel est le coût des outils Pro ?

Les outils Pro web_data_* coûtent 1,00 $ à 1,50 $ pour 1 000 résultats selon votre plan (page de tarification de Bright Data) :

Plan Prix pour 1 000 résultats
Paiement à l’utilisation 1,50 $
Starter 1,30 $
Professional 1,10 $
Business 1,00 $

Pour les appels Pro à entité unique , 1 fetch de réponse LLM, 1 profil LinkedIn ou 1 entreprise Crunchbase par appel , les estimations mensuelles supposent 1 appel = 1 résultat facturé, ce qui correspond à la facturation basée sur l’utilisation de Bright Data pour les outils web_data_* à enregistrement unique. Pour les outils de recherche en masse comme web_data_amazon_product_search, le nombre par résultat s’adapte aux éléments retournés. Utilisez le paramètre limit lors du prototypage et vérifiez les tarifs actuels dans votre compte avant de budgétiser.

Browser API est facturé séparément à 5 à 8 $/Go de Bande passante. Si vous ajoutez une couche agent IA, la tarification Anthropic, OpenAI ou Google s’applique également, par appel LLM.

Cela fonctionne-t-il avec GPT ou Gemini ?

Oui, le Power brightdata-scrape fonctionne avec OpenAI (GPT) et Google (Gemini), pas seulement Anthropic. Quand vous invitez Kiro pour une couche agent (« ajouter une route /api/agent qui utilise ces Scrapers comme outils »), il choisit le modèle d’outil correspondant (SDK Anthropic, SDK OpenAI, LangChain, Mastra ou Vercel AI SDK) selon les dépendances de votre projet. Remplacez anthropic(...) par openai(...) ou google(...) dans la route générée, puis ajustez la configuration du client du fournisseur et l’ID du modèle pour correspondre.

Peut-il scraper des sites nécessitant une connexion ?

Le Power brightdata-scrape peut scraper des sites à mur de connexion, mais pas depuis le défaut dataset-trigger. Passez à Browser API pour les sessions avec état, et ajoutez votre propre stockage d’identifiants. L’échelle de Phase 2 du Power escalade vers Browser API pour les flux de connexion et de clic.

Puis-je exécuter les 4 cas d’usage dans un seul projet ?

Oui. Chaque cas d’usage est un module autonome (son propre fichier src/scrapers/, route API et vue) qui réutilise le même serveur MCP, donc les 4 peuvent coexister dans un seul projet Next.js. Ce guide ne les combine pas en une seule application (les 2 builds en direct, retail et Crunchbase, sont des repos de démo séparés, et GEO et LinkedIn sont présentés comme des invites), mais rien ne vous en empêche.

Puis-je l’utiliser depuis Claude Code ou Cursor ?

Pour Claude Code ou Cursor, utilisez les Claude Skills de Bright Data au lieu du Kiro Power brightdata-scrape. Bright Data publie des Skills de scraping sur github.com/brightdata/skills (comme scraper-builder et scrape) qui s’exécutent dans Claude Code, Cursor ou tout hôte agent supportant les Skills. Ils couvrent les mêmes jobs de scraping sur la même infrastructure Bright Data, mais ils sont packagés comme Skills plus le CLI bdata plutôt que la génération de code MCP-et-Next.js de ce Power, donc l’installation et le code généré diffèrent.