Audit — Spy plateforme ↔ extension BoostEcom (2026-09-10)
Contrat lu cote extension : GET /api/intelligence/lookup?q=…&rich=1 (plus hub/scan, similar?enrich=1, graph, extras). Ce document ne dit pas que l'extension ignore ads/traffic. Les empty states live observes (= KPI mois…
Contrat lu cote extension : GET /api/intelligence/lookup?q=…&rich=1
(plus hub/scan, similar?enrich=1, graph, extras). Ce document ne
dit pas que l'extension ignore ads/traffic. Les empty states live
observes (= KPI mois present, visits_series: null,
ads_absence renseigne — souvent not_observed ou quarantined —
screenshot_url present) matchent le code + l'env, pas un trou de
projecteur.
Symboles cites : projectVisitsSeries, leafAbsence,
projectTopProducts, HubStore, buildEmission (meta-ad-library).
A → E (code)
A. visits_series
| Statut | Juste env / historique manquant (projecteur OK) |
|---|
projectVisitsSeriesexiste (src/services/algorithms/intelligence/hub-projection.ts) et exige ≥ 2 points{visits, month}; sinonnull.- Le scrape public SimilarWeb remplit
monthly_visits(+ souventvisits_change_pct) mais renvoie une serie vide / un seul mois → emissionabsent("not_observed")quand un KPI existe sans courbe (probes/traffic-provider.ts). - La courbe multi-mois arrive des adaptateurs cles :
SIMILARWEB_API_KEY/SEMRUSH_API_KEY/DATOS_API_KEY(docs/ops/intelligence-env-matrix.md§4). - Verdict courbe vide : keys only (ou panel sous plancher =
traffic.no_coverage), pas bug de projection.
B. ads_absence : not_observed vs quarantined
| Statut | Deja fait (semantique types) + Partiel (zero mesure) |
|---|
- Definitions :
src/services/algorithms/intelligence/canonical/types.ts(ABSENCE_REASONS) :not_observed: aucun L2 n'a pose de valeur (ou le producteur n'a rien emis).quarantined: une valeur observee a ete rejetee comme invraisemblable ;projectAdsSeriesdroppe alors l'historique disowned (soundAdSnapshots+canonicalQuarantined).
- Projection :
ads_absence: leafAbsence(rec.ads?.active_creatives). - Piege :
buildEmissiondansprobes/meta-ad-library.tsfaitif (agg.active_creatives === 0) return {}. Un scrape Meta complete a zero ne pose donc paspresent(0); le template restenot_observed. L'UI extension qui attendactive_creatives === 0pour « mesure a zero » ne le verra pas tant que ce chemin n'emet pas 0. - Sans
META_AD_LIBRARY_TOKEN/ Apify : pas d'ingest creatives →not_observed+creatives: []est le resultat attendu, pas une faute derich=1.
C. 0583 + #1001 — top_products enrichis
| Statut | Deja fait (merge origin/main) |
|---|
- Merge PR
#1001(1f75ade). Catalog probe +projectTopProductspassentpublished_at/compare_at_price/tagsquand le feed/products.jsonles porte (hub-projection-top-products.test.ts). - Residual : un store doit etre rescanné apres le deploy pour que le JSON canonique porte les nouveaux champs. Pas un trou d'API.
D. 0584 + #1002 — ContextIQ → BoostEcom Spy
| Statut | Deja fait (code + live privacy) |
|---|
- Merge PR
#1002(44ac65b). Messages / config produit sans string user-facing « ContextIQ » (compat clipboard + tokens de contratdata-contextiq/ slug CWS conserves volontairement). - Vérification en direct de
/legal/privacy(2026-09-10) : copy « BoostEcom Spy ».
E. screenshot_url
| Statut | Deja fait |
|---|
- Projete dans
HubStore.screenshot_urldepuisidentity.screenshot_url(masque siANONYMIZED). - Inclus dans
searchHubStores/lookup?rich=1.
B. Verdicts une phrase
- Courbes trafic vides → keys only (ou historique < 2 mois), projecteur branche.
- Ads
quarantined→ policy corpus (lecture disowned) ; Meta public CTA extension = compensation, pas re-ecriture HubStore. - Creatives vides alors que la Ads Library publique a des pubs →
ingest / token Meta-Apify manquant, ou ownership filter, ou
zero non emis ; pas un oubli
rich=1. - Enrichissement
top_products0583 → merge main ; live apres rescan catalogue. - Etat de l'art 2026 → socle API OK ; edge = cles trafic + job Meta + emit zero honnete.
C. Plan action
| Priorite | Action | Propriétaire |
|---|---|---|
| P0 ops | Poser SIMILARWEB_API_KEY ou SEMRUSH_API_KEY (prod) ; preuve = 1 domaine PUBLIC avec visits_series.length >= 2 via lookup?rich=1 | operateur |
| P0 ops | Poser META_AD_LIBRARY_TOKEN (et/ou Apify) ; relancer scans HOT | operateur |
| P0 docs | Cette note + unites MoM/ratio + matrice env (cette PR) | intelligence |
| P1 code | buildEmission : sur status complete et 0 owned, emettre present(0) pour distinguer mesure vide / jamais vu | intelligence (item suivi) |
| P1 | Job Ads Library robuste (cron plateforme, pas MV3 CWS) | intelligence |
| P2 | Endpoint refresh ads/traffic par domaine pour session extension — interdit : 4e prefixe credential (ADR 0007), POST Origin chrome-extension:// | security + intelligence |
D. Contrat API stable (snake, HubStore)
Confirme pour l'extension (deja projetes) :
monthly_visits, visits_change_pct (RATIO, ex. -0.199),
visits_series: [{ t: "YYYY-MM"|null, v: number }] | null,
mom_growth_pct (POINTS, ex. -19.9 — NE PAS ×100),
country_breakdown, top_source, paid_share,
active_creatives, ads_absence, ads_series: [{ t, v }] | null,
ad_networks, creatives[],
top_products: { handle, title, image_url, price?, published_at?,
compare_at_price?, tags? }[],
screenshot_url, screenshot_at,
niche, categories, rating, total_reviews, revenue_eur, aov_eur, …
lookup?rich=1 → { suggestions, stores: HubStore[] }.
traffic_collection (octobre 2026)
Pour un store SANS chiffre de trafic, le lookup dit lui-meme pourquoi,
sans POST hub/scan (rendus payants, slot par domaine, connexion) :
"traffic_collection": {
"state": "measured" | "no_coverage" | "never",
"checked_at": "2026-09-20T07:30:00.000Z" | null
}
measured: un chiffre de visites a ete stocke (date = son observation).checked_atpeut etrenullpour un chiffre stocke avant que les chiffres soient dates.no_coverage: la source a repondu qu'elle ne suit pas ce site (SimilarWeb, HTTP 404). Autorise « la source de trafic ne couvre pas ce store » avec la datechecked_at. Si un ancien chiffre existe encore, il reste affiche avec sa propre date.never: aucune collecte reelle enregistree ;checked_at: null. Autorise seulement « pas encore collecte », jamais un zero.
Etat de la DERNIERE collecte qui a reellement atteint sa source, quelle
que soit la requete ou le cron qui l'a lancee (scan hub, refresh-runner,
crons, scans admin / agents) : une tentative bloquee, en erreur ou sautee
(cache frais) n'ecrase jamais un etat precedent. Ecrit par le
coordinateur (traffic-collection.ts) dans record.traffic.collection,
sans colonne ni migration ; sans backfill (un chiffre date deja stocke se
lit measured a la lecture).
Gratuit sur tous les plans (il dit si un chiffre existe, jamais le
chiffre) ; absent pour un store ANONYMIZED, et un store masque ou
supprime n'est jamais servi. Sur hub/scan, store.traffic_collection
cohabite avec enrichment / enrichment_at, qui restent « ce que CETTE
requete a collecte ».
similar?enrich=1 → peers avec projection.
Deep-links : /intelligence/top-stores/{domain},
/intelligence/inspect/{theme|apps|ads|emails}?domain=…
(pas /intelligence/inspect/catalog).
E. Procedure de verification (extension / QA)
Sans citer de marque boutique :
# 1. Shape rich
curl -sS "https://www.boostecom.app/api/intelligence/lookup?q={domain}&rich=1&limit=1" \
| jq '{n:(.stores|length),
visits:(.stores[0].monthly_visits),
series:(.stores[0].visits_series|length?),
change:(.stores[0].visits_change_pct),
mom:(.stores[0].mom_growth_pct),
ads_absence:(.stores[0].ads_absence),
active:(.stores[0].active_creatives),
creatives:(.stores[0].creatives|length),
shot:(.stores[0].screenshot_url!=null),
top_keys:(.stores[0].top_products[0]|keys)}'
# 2. Preuve trafic API = series >= 2 (sinon cles / coverage, pas l'extension)
# 3. Legal
curl -sS https://www.boostecom.app/legal/privacy | grep -o 'BoostEcom Spy' | head -1
Unites a tester cote UI : meme magasin avec
visits_change_pct = -0.199 et mom_growth_pct = -19.9 doivent
afficher tous les deux « −19,9 % », jamais −0,2 % / −1990 %.
Bloqueurs (une ligne)
- Secrets trafic prod : sans SimilarWeb/Semrush/Datos,
visits_seriesreste null meme si le KPI mois est rempli. - Secrets Meta/Apify : sans token, creatives +
active_creativesrestent absents (not_observed). - Zero ads non emis :
buildEmission({})sur 0 confond « mesure a zero » et « jamais observe ». - Rescan catalogue : champs 0583 absents sur records pre-merge jusqu'au prochain deep scan.
Preuve live 2026-09-10 (lookup?rich=1)
Sans citer d'autres marques : sur le domaine de reference de la matrice env (§9) :
| Champ | Valeur | Note |
|---|---|---|
monthly_visits | present | scrape gratuit OK |
visits_series | null | pas de preuve courbe |
visits_change_pct | ratio (ex. −0.22) | ne pas afficher brut |
mom_growth_pct | points % (ex. −6.7) | preferer si present |
ads_absence | "quarantined" | ≠ silence |
creatives | [] | pas d'ads observes |
top_products[0].published_at / compare_at_price / tags | presents | 0583 deja en prod sur cette fiche |
screenshot_url | truthy | OK |
→ Extension : wait corpus pour (1)(2). Produits : retest possible sans batch rescan sur cette fiche.