afrolook
FREN
Comment gagnerStudio CartesMusiqueFêtesAnnoncerDiffuseursContactEnglish
Afrolook Ads · Diffuseurs

Documentation d'intégration

Afficher les annonces Afrolook Ads sur ton site ou dans ton application. Les annonces sont choisies, signées et comptées par les serveurs d'Afrolook Ads : ton code se contente de les afficher.

1. Démarrer

  1. Crée ton profil de diffuseur et accepte les règles dans ton espace diffuseur (connexion Google). Notre équipe le valide.
  2. Ajoute ton site ou ton application (en ligne obligatoirement) : adresse du site, ou lien Google Play ou App Store ; audience mensuelle ; pays ; catégories d'annonces que tu acceptes.
  3. Prouve que le site est à toi : ajoute la balise de vérification affichée dans ton espace dans la page d'accueil, ou le code seul dans le fichier /afrolook-ads.txt. Elle doit rester en place : retirée 3 jours de suite, la diffusion est suspendue.
  4. Après validation, ton site ou ton application reçoit son identifiant publicitaire ap_xxxxxxxxxx. C'est lui qu'on met dans la balise ou dans l'appel à l'API.
L'identifiant ne marche que sur le site ou l'application déclaré. Utilisé depuis un autre domaine, il est refusé et l'essai est enregistré. Ne le publie pas ailleurs et ne le partage pas.

2. Balise web (le plus simple)

Colle ces deux lignes là où l'annonce doit apparaître. La balise s'occupe de tout : demande, affichage, mesure de la vue, clic.

<ins class="afl-ad" data-pub="ap_xxxxxxxxxx" data-slot="fil-principal" data-format="native"></ins>
<script async src="https://afrolookmedia.com/ads/tag.js"></script>
  • data-pub : ton identifiant publicitaire. data-slot : le nom de l'emplacement (lettres, chiffres, - et _), pour tes statistiques. data-format : banner, native, poster ou sticky (bandeau collant en bas de l'écran, fermable).
  • Une seule annonce par emplacement et par chargement de page, 3 emplacements au plus par page. Pas de rafraîchissement automatique.
  • Si aucune annonce ne convient au visiteur (pays, langue, catégories que tu acceptes…), l'emplacement reste vide : rien n'est compté, rien n'est payé.
  • Si ton site a une politique de sécurité de contenu (CSP) : autorise script-src https://afrolookmedia.com, connect-src https://afrolookmedia.com et img-src https://cdn.afrolookmedia.com.
  • Visiteurs avec « Ne pas suivre » : l'annonce s'affiche, mais ni la vue ni le clic ne sont enregistrés.

Pour afficher plusieurs emplacements, ajoute plusieurs balises <ins class="afl-ad"> (un seul <script> suffit). Les formats vidéo, carrousel, interstitiel et récompensée passent aujourd'hui par l'API (section 4).

3. Application (composant Flutter prêt à l'emploi)

Un composant prêt à l'emploi gère tout : demande de l'annonce à la bonne taille, bannière prête ou mise en page automatique (image entière sur fond flouté), mention « Annonce », vue envoyée au bon moment, clic par le lien d'Afrolook Ads, actualisation, fermeture. Télécharge afrolook_ads_banner.dart, copie-le dans ton projet et ajoute les paquets http, url_launcher et visibility_detector.

// Mini bannière fixe en bas d'un écran (320 × 50, fermable) : l'emplacement des mini bannières d'AdMob
Scaffold(
  body: …,
  bottomNavigationBar: const AfrolookAdsBanner.bottom(pubId: 'ap_xxxxxxxxxx', visitorId: monIdentifiantDeVisiteur),
);

// Rectangle moyen dans le contenu (300 × 250), grande bannière (large) ou leaderboard (tablette)
const AfrolookAdsBanner(pubId: 'ap_xxxxxxxxxx', visitorId: monIdentifiantDeVisiteur, size: AdsBannerSize.medium, slot: 'liste');
  • visitorId : une chaîne de 12 à 64 caractères (lettres, chiffres, tirets), stable d'une session à l'autre (garde-la dans les préférences). Pas de données personnelles.
  • Tailles : AdsBannerSize.mini (320×50), large (320×100), medium (300×250), leaderboard (728×90). Chaque taille demande au moteur une bannière prête à cette taille ; sans bannière, l'annonce est mise en page automatiquement.
  • slot : un nom différent par emplacement de l'écran ; refresh : au moins 30 secondes ; headers : en-têtes ajoutés aux appels (attestation de l'application).
  • S'il n'y a pas d'annonce ou en cas d'erreur réseau, le composant ne prend aucune place et ne lève aucune exception.

Tu préfères dessiner toi-même l'annonce ? Voici le principe, en quelques lignes :

class AfrolookAd extends StatefulWidget {
  const AfrolookAd({super.key, required this.pub, this.slot = 'main', this.format = 'native'});
  final String pub, slot, format; // pub : ton identifiant publicitaire (ap_...)
  @override
  State<AfrolookAd> createState() => _AfrolookAdState();
}

class _AfrolookAdState extends State<AfrolookAd> {
  static const _host = 'afrolookmedia.com';
  Map<String, dynamic>? _ad;
  String _vid = '';
  Timer? _timer;
  bool _sent = false;

  @override
  void initState() {
    super.initState();
    _load();
  }

  @override
  void dispose() {
    _timer?.cancel();
    super.dispose();
  }

  Future<void> _load() async {
    final prefs = await SharedPreferences.getInstance();
    _vid = prefs.getString('aflv') ?? List.generate(24, (_) => Random.secure().nextInt(16).toRadixString(16)).join();
    await prefs.setString('aflv', _vid);
    final r = await http.get(Uri.https(_host, '/ads/api/serve', {'pub': widget.pub, 'fmt': widget.format, 'slot': widget.slot, 'vid': _vid}));
    final ad = (jsonDecode(r.body) as Map<String, dynamic>)['ad'];
    if (mounted && ad != null) setState(() => _ad = ad as Map<String, dynamic>);
  }

  // Une vue = au moins la moitié de l'annonce visible, sans interruption, pendant ad['viewMs'] millisecondes.
  void _visibility(VisibilityInfo info) {
    final ad = _ad;
    if (ad == null || _sent) return;
    _timer?.cancel();
    if (info.visibleFraction >= 0.5) {
      _timer = Timer(Duration(milliseconds: (ad['viewMs'] as int) + 50), () {
        _sent = true;
        http.post(Uri.parse(ad['event'] as String),
            body: {'t': ad['token'], 'e': 'view', 'ms': ((ad['viewMs'] as int) + 50).toString(), 'vid': _vid});
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    final ad = _ad;
    if (ad == null) return const SizedBox.shrink(); // aucune annonce : emplacement vide
    final media = ad['media'] as Map<String, dynamic>;
    return VisibilityDetector(
      key: Key(ad['id'] as String),
      onVisibilityChanged: _visibility,
      child: InkWell(
        // Le clic passe TOUJOURS par le lien d'Afrolook Ads : c'est lui qui compte le clic puis ouvre l'annonceur.
        onTap: () => launchUrl(Uri.parse(ad['click'] as String), mode: LaunchMode.externalApplication),
        child: Card(child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
          const Padding(padding: EdgeInsets.all(8), child: Text('Annonce', style: TextStyle(fontSize: 11))), // mention obligatoire
          // image TOUJOURS entière (jamais rognée) : posée sur une copie floutée d'elle-même, quel que soit son format
          SizedBox(height: 176, width: double.infinity, child: Stack(fit: StackFit.expand, children: [
            ImageFiltered(imageFilter: ImageFilter.blur(sigmaX: 14, sigmaY: 14), child: Image.network((media['thumb'] ?? media['url']) as String, fit: BoxFit.cover, color: Colors.black45, colorBlendMode: BlendMode.darken)),
            Image.network((media['thumb'] ?? media['url']) as String, fit: BoxFit.contain),
          ])),
          ListTile(title: Text(ad['title'] as String, maxLines: 2, overflow: TextOverflow.ellipsis), subtitle: Text((ad['text'] ?? '') as String, maxLines: 2, overflow: TextOverflow.ellipsis)),
          Padding(padding: const EdgeInsets.fromLTRB(12, 0, 12, 12), child: SizedBox(width: double.infinity, height: 44, // bouton d'au moins 44 px
            child: FilledButton(onPressed: () => launchUrl(Uri.parse(ad['click'] as String), mode: LaunchMode.externalApplication), child: Text((ad['cta'] ?? 'En savoir plus') as String)))),
        ])),
      ),
    );
  }
}

Applications : les annonces s'affichent et sont comptées, mais une application n'est rémunérée qu'après la vérification de son authenticité (attestation de l'application, étape prévue). Les applications du réseau Afrolook Ads envoient en plus le jeton de vérification de l'application (Firebase App Check) dans l'en-tête X-Firebase-AppCheck.

4. API

Obtenir une annonce

GET https://afrolookmedia.com/ads/api/serve?pub=ap_xxxxxxxxxx&fmt=native&slot=fil-principal&vid=<identifiant-visiteur>&lang=fr
  • pub (obligatoire) : ton identifiant publicitaire. fmt (obligatoire) : banner, sticky, native, carousel, poster, video, interstitial ou rewarded. size (facultatif) : taille de l'emplacement, 728x90, 320x50, 320x100 ou 300x250 ; si l'annonce a une bannière prête à cette taille, elle est renvoyée dans banner. slot : nom de l'emplacement (1 à 32 caractères : lettres minuscules, chiffres, - et _). vid (obligatoire) : un identifiant anonyme du visiteur, 12 à 64 caractères (lettres, chiffres, -), généré une fois et gardé sur l'appareil. lang : langue du visiteur (2 lettres), facultatif.
  • Le pays du visiteur est déterminé par nos serveurs d'après son adresse IP : n'envoie pas de pays.

Réponse (200) : {"ok":true,"ad":null} s'il n'y a rien à afficher, sinon :

{
  "ok": true,
  "ad": {
    "id": "AbC123…", "format": "native", "label": "Annonce",
    "title": "Boutique Kofi : mode africaine", "text": "Vêtements modernes, livraison à Lomé.", "cta": "Visiter",
    "media": { "type": "image", "url": "https://…", "thumb": "https://…", "images": ["https://…"] },
    "banner": { "url": "https://…", "w": 728, "h": 90 },
    "click": "https://afrolookmedia.com/ads/api/go?t=<jeton>&v=<vid>",
    "token": "<jeton signé à usage unique>",
    "event": "https://afrolookmedia.com/ads/api/event",
    "viewMs": 1000, "ttlMs": 1800000
  }
}

Erreurs : 400 paramètres invalides ; 403 identifiant inconnu ou non validé (diffuseur), appel depuis un autre domaine (origine) ; 429 trop de demandes. Les erreurs ne bloquent jamais ta page : affiche simplement un emplacement vide.

Signaler une vue

POST https://afrolookmedia.com/ads/api/event        (Content-Type: text/plain)
{"t":"<jeton>", "e":"view", "ms":1050, "vid":"<identifiant-visiteur>"}
  • e : view (vue) ou complete (lecture complète d'une vidéo, pour les formats vidéo et récompensée, après une vue valide). ms : durée pendant laquelle l'annonce est restée visible (à moitié au moins) ; elle ne peut pas dépasser le temps écoulé depuis la demande.
  • Réponse : {"ok":true,"counted":true} ou {"ok":true,"counted":false,"reason":"…"} avec le motif : not_visible, too_fast, expired, replay, interval, ad_cap, device_cap, ip_cap, bot, origine, ad_inactive.

Le clic

Le bouton de l'annonce pointe toujours vers le lien click reçu (/go) : Afrolook Ads y compte le clic puis redirige vers l'annonceur. N'appelle jamais ce lien toi-même et ne le remplace pas par l'adresse de l'annonceur : un clic qui ne passe pas par Afrolook Ads n'existe pas.

Limites et durées

  • Le jeton ne vaut que pour une seule vue et expire au bout de 30 minutes (2 heures pour le clic).
  • Au plus 3 vues de la même annonce par visiteur et par jour, 300 affichages par visiteur et par jour, un intervalle minimum entre deux annonces d'un même emplacement (tableau ci-dessous).
  • Les demandes en rafale sont limitées (par adresse et par visiteur).

5. Formats

FormatCodeVue comptée aprèsIntervalle minimumPrix payé par l'annonceur (pour 1 000)Tu reçois (65 %)Balise web
Bannièrebanner1 s30 s1 000 F650 Foui
Bandeau collantsticky1 s30 s1 250 F812,50 Foui
Carte nativenative1 s20 s1 500 F975 Foui
Carrouselcarousel1 s20 s1 800 F1 170 FAPI
Afficheposter1 s20 s2 000 F1 300 Foui
Vidéo dans le filvideo2 s20 s2 500 F1 625 FAPI
Interstitielinterstitial1 s10 min3 000 F1 950 FAPI
Récompenséerewarded1 s, puis lecture complète5 min3 500 F (vue complète)2 275 F (vue complète)API

Prix de lancement : pendant le premier mois de l'offre Réseau, les annonceurs paient 30 % de moins ; ta part de 65 % est alors calculée sur le prix réellement payé. Les prix du tableau sont ceux que paient les annonceurs : tu en reçois 65 % (colonne « Tu reçois »). Tu reçois 65 % du budget des annonces de l'offre Réseau réellement affichées chez toi, sur les seuls affichages valides. Les annonces gratuites ne rémunèrent pas les diffuseurs. L'offre Réseau n'est pas encore ouverte : tes affichages sont comptés dès maintenant, la rémunération démarre à son ouverture.

Mention « Annonce » toujours visible, fermeture possible pour le bandeau collant et l'interstitiel, pas de son qui démarre seul, jamais plus de 3 emplacements par page.

Tailles d'affichage et images (sites et applications)

Un annonceur dépose une seule annonce (jusqu'à 5 images ou une vidéo de 15 s au plus) : le moteur la sert dans le format de ton emplacement. L'image est toujours affichée entière, jamais rognée : si son format diffère de celui de l'emplacement, le reste se remplit d'une copie floutée de la même image (comme AdMob). Les annonceurs sont invités à fournir une image carrée de 1080 × 1080 px, sujet et texte au centre.

EmplacementTaille de l'emplacementImage conseilléeTexte affiché
Grande bannière (banner)320 × 100 (téléphone) · 728 × 90 (ordinateur)Carré 1:1, au moins 600 × 600 px (affiché en 76 à 84 px)Titre sur 2 lignes + description sur 2 lignes + bouton
Bandeau collant (sticky)320 × 50, fermableCarré 1:1, au moins 300 × 300 pxTitre court (40 caractères) + bouton
Rectangle moyen (native / banner)300 × 250 (jusqu'à 336 de large)Paysage 1,91:1 : 1200 × 628 pxTitre, description, bouton pleine largeur
Carte native (native)Dans une liste, largeur de la colonnePortrait 4:5 : 1080 × 1350 pxTitre, description, bouton
Affiche (poster)Pleine largeurPortrait 4:5 : 1080 × 1350 pxTitre + bouton
Interstitiel (interstitial)Plein écran de l'applicationVertical 9:16 : 1080 × 1920 px (ou 4:5 centré)Titre + bouton, croix de fermeture
Vidéo (video)Largeur de la colonne, 15 s au plusMP4 16:9, 1:1 ou 9:16, 25 Mo au plusTitre + bouton

Bannières prêtes à l'emploi (image seule)

Comme sur AdMob ou Adsterra, un annonceur peut déposer des bannières déjà dessinées aux tailles standard. Demande-les avec size : si l'annonce servie en a une, la réponse contient banner (url, w, h) : affiche cette image en entier, sans rien ajouter (juste la mention « Annonce »), cliquable vers le lien click. Sinon, utilise le titre, le texte et l'image comme ci-dessus.

Taille (size)NomOù l'utiliser
728x90LeaderboardHaut ou bas d'une page sur ordinateur
320x100Grande bannièreDans une page sur téléphone
320x50Mini bannièreBandeau fixe en bas d'une application (comme les mini bannières d'AdMob)
300x250Rectangle moyenDans le contenu, sur ordinateur et téléphone

Dans une application, dimensionne l'emplacement comme dans ce tableau, laisse le contenu s'adapter (image BoxFit.contain sur sa copie floutée) et ne rogne jamais l'image de l'annonceur. Taille minimale du texte : 12 px ; bouton d'action de 44 px de haut au moins sur téléphone. L'exemple ci-dessus utilise ImageFilter : ajoute import 'dart:ui' show ImageFilter;.

6. Catégories et ciblage

  • Chaque annonce a une catégorie choisie par l'annonceur et vérifiée par notre équipe : commerce, restauration, mode et beauté, technologie, finance, paris et jeux d'argent, alcool et tabac, médicaments, rencontres, contenu sensuel (corps dénudé ou suggestif), politique, religion, loteries…
  • Tu choisis les catégories que tu acceptes pour chaque site ou application, dans ton espace. Seules celles-là s'affichent chez toi. Les catégories courantes sont acceptées par défaut ; les catégories sensibles ne s'affichent jamais sans ton accord explicite. Une annonce sans catégorie n'est jamais diffusée chez un diffuseur externe.
  • Le contenu sexuellement explicite, les armes, les drogues et les arnaques sont interdits pour tous.
  • Le ciblage est défini par l'annonceur et nous le respectons : pays ou toute l'Afrique ou le monde entier, langues, appareils (téléphone, ordinateur), types de sites. Quand une annonce vise des pays précis, au plus 40 % de ses vues peuvent venir d'autres pays ; le pays du visiteur est déterminé par nos serveurs.
  • Conséquence pour toi : un visiteur n'est pas toujours éligible à toutes les annonces. C'est normal, et c'est ce qui rend les annonces pertinentes pour tes visiteurs.

7. Comptage et fraude

  • Une vue valide : jeton signé, récent et jamais utilisé ; annonce visible à moitié pendant la durée du format ; intervalles et plafonds respectés ; visiteur réel (pas un robot) ; site déclaré.
  • Tout le reste est du trafic invalide : il n'est ni facturé à l'annonceur ni payé au diffuseur. Tu vois ton taux de trafic invalide dans ton espace : moins de 10 % normal, de 10 à 25 % alerte, plus de 25 % emplacement suspendu.
  • Interdit : cliquer sur tes propres annonces ou inciter à cliquer, acheter du trafic, robots et rafraîchissements automatiques, cadres cachés ou empilés, modifier ou masquer une annonce ou la mention « Annonce », faire appeler le serveur par d'autres sites ou applications que ceux déclarés.
  • Les appels faits avec ton identifiant depuis un autre domaine sont refusés et comptés : tu les vois dans tes mesures.
  • Aucun cookie, aucun suivi d'un site à l'autre : le visiteur est reconnu par un identifiant propre à ton site. Ta politique de confidentialité doit mentionner l'affichage d'annonces par Afrolook Ads.

8. Mesures et paiement

  • Pour chaque site, ton espace montre l'audience réelle mesurée par Afrolook Ads sur 30 et 60 jours (personnes différentes pour lesquelles la balise a été chargée), comparée à l'audience que tu as déclarée, jour par jour, avec la répartition par pays et les affichages valides.
  • L'audience retenue est fixée par Afrolook Ads et ne dépasse jamais la déclarée. En cas d'écart important et durable, elle est ajustée.
  • Gains bloqués 30 jours avant retrait, avec une réserve de 10 % pendant 90 jours ; retrait minimum 10 000 F par Mobile Money ; les frais de retrait sont payés par l'annonceur.

9. Questions fréquentes

Aucune annonce ne s'affiche.

Plusieurs raisons normales : pas d'annonce disponible pour ce visiteur (pays, langue, appareil), aucune annonce d'une catégorie que tu acceptes, intervalle minimum non écoulé, ou site pas encore validé. Une erreur 403 diffuseur signifie que l'identifiant est inconnu ou que le site n'est pas encore validé ; 403 origine, que l'appel ne vient pas du domaine déclaré.

Puis-je mettre la balise sur plusieurs sites ?

Non : chaque site ou application déclaré a son propre identifiant. Ajoute chaque site dans ton espace (jusqu'à 10) pour recevoir un identifiant par site.

Puis-je choisir les annonces affichées ?

Tu choisis les catégories acceptées et tes formats. Le choix de l'annonce dans ces limites est fait par Afrolook Ads, selon le ciblage de chaque annonceur.

Que se passe-t-il si mon audience est plus petite que celle déclarée ?

Tu le vois dans ton espace. Un écart important est signalé ; l'audience retenue peut être ajustée, et la diffusion suspendue en cas d'écart durable ou de déclaration manifestement fausse.

Où trouver de l'aide ?

Écris-nous avec ton identifiant publicitaire.