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
- Crée ton profil de diffuseur et accepte les règles dans ton espace diffuseur (connexion Google). Notre équipe le valide.
- 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.
- 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. - 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.
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,posterousticky(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.cometimg-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,interstitialourewarded.size(facultatif) : taille de l'emplacement,728x90,320x50,320x100ou300x250; si l'annonce a une bannière prête à cette taille, elle est renvoyée dansbanner.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) oucomplete(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
| Format | Code | Vue comptée après | Intervalle minimum | Prix payé par l'annonceur (pour 1 000) | Tu reçois (65 %) | Balise web |
|---|---|---|---|---|---|---|
| Bannière | banner | 1 s | 30 s | 1 000 F | 650 F | oui |
| Bandeau collant | sticky | 1 s | 30 s | 1 250 F | 812,50 F | oui |
| Carte native | native | 1 s | 20 s | 1 500 F | 975 F | oui |
| Carrousel | carousel | 1 s | 20 s | 1 800 F | 1 170 F | API |
| Affiche | poster | 1 s | 20 s | 2 000 F | 1 300 F | oui |
| Vidéo dans le fil | video | 2 s | 20 s | 2 500 F | 1 625 F | API |
| Interstitiel | interstitial | 1 s | 10 min | 3 000 F | 1 950 F | API |
| Récompensée | rewarded | 1 s, puis lecture complète | 5 min | 3 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.
| Emplacement | Taille de l'emplacement | Image conseillée | Texte 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, fermable | Carré 1:1, au moins 300 × 300 px | Titre court (40 caractères) + bouton |
Rectangle moyen (native / banner) | 300 × 250 (jusqu'à 336 de large) | Paysage 1,91:1 : 1200 × 628 px | Titre, description, bouton pleine largeur |
Carte native (native) | Dans une liste, largeur de la colonne | Portrait 4:5 : 1080 × 1350 px | Titre, description, bouton |
Affiche (poster) | Pleine largeur | Portrait 4:5 : 1080 × 1350 px | Titre + bouton |
Interstitiel (interstitial) | Plein écran de l'application | Vertical 9:16 : 1080 × 1920 px (ou 4:5 centré) | Titre + bouton, croix de fermeture |
Vidéo (video) | Largeur de la colonne, 15 s au plus | MP4 16:9, 1:1 ou 9:16, 25 Mo au plus | Titre + 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) | Nom | Où l'utiliser |
|---|---|---|
728x90 | Leaderboard | Haut ou bas d'une page sur ordinateur |
320x100 | Grande bannière | Dans une page sur téléphone |
320x50 | Mini bannière | Bandeau fixe en bas d'une application (comme les mini bannières d'AdMob) |
300x250 | Rectangle moyen | Dans 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.