← Retour au lexique
📖 Link Building

Outil de désaveu

Fonctionnalité Google Search Console permettant de demander à Google d'ignorer certains backlinks toxiques pointant vers votre site.

Définition

L’outil de désaveu (Disavow Tool) est une fonctionnalité de Google Search Console qui permet aux webmasters de signaler à Google les liens entrants qu’ils souhaitent voir ignorés lors du calcul du classement. Cet outil de dernier recours est utilisé pour se protéger contre les backlinks toxiques, spammés ou de mauvaise qualité qui pourraient nuire au référencement, notamment après une pénalité ou une attaque de negative SEO.

Accès et utilisation

Interface Google Search Console

# Process utilisation outil désaveu
disavow_process = {
    'step_1_access': {
        'url': 'https://search.google.com/search-console/disavow-links',
        'requirement': 'Propriétaire vérifié dans Search Console',
        'warning': 'Outil avancé - utilisation prudente recommandée'
    },
    
    'step_2_select_property': {
        'action': 'Choisir la propriété concernée',
        'format': 'Domaine ou préfixe URL',
        'note': 'Vérifier la bonne propriété avant soumission'
    },
    
    'step_3_upload_file': {
        'format': 'Fichier .txt uniquement',
        'encoding': 'UTF-8 ou ASCII',
        'size_limit': '2 MB et 100,000 URLs max',
        'syntax': 'Une URL ou domaine par ligne'
    },
    
    'step_4_confirmation': {
        'warning': 'Action irréversible immédiate',
        'processing': '2-4 semaines pour prise en compte',
        'effect': 'Liens ignorés dans algorithme ranking'
    }
}

Format du fichier désaveu

# Fichier désaveu exemple - monsite.com
# Dernière mise à jour : 2024-12-15
# Contact : seo@monsite.com

# Liens spam individuels identifiés
http://spam-directory.com/liens/monsite.html
http://casino-online.net/partners/link-245.php
https://adult-content.ru/external/site-abc

# Domaine entier spam (tous les liens de ce domaine)
domain:cheap-backlinks.com

# Réseau de liens identifié en juillet 2024
domain:pbn-network1.net
domain:pbn-network2.org
domain:pbn-network3.info

# Negative SEO attack - Août 2024
domain:viagra-pills-cheap.com
domain:casino-gambling-now.net
domain:payday-loans-quick.org

# Sites piratés linkant massivement
domain:hacked-wordpress-485.com
domain:compromised-joomla-site.net

Quand utiliser l’outil

Critères de décision

// Analyse nécessité désaveu
class DisavowNecessityAnalyzer {
    constructor(backlinkProfile) {
        this.backlinks = backlinkProfile;
        this.toxicityThreshold = 0.7; // 70% toxicité
    }
    
    analyzeDisavowNeed() {
        const analysis = {
            totalBacklinks: this.backlinks.length,
            toxicBacklinks: [],
            recommendation: null,
            urgencyLevel: null
        };
        
        // Identifier liens toxiques
        this.backlinks.forEach(link => {
            const toxicity = this.calculateToxicity(link);
            
            if (toxicity >= this.toxicityThreshold) {
                analysis.toxicBacklinks.push({
                    url: link.url,
                    domain: link.domain,
                    toxicityScore: toxicity,
                    reasons: this.getToxicityReasons(link)
                });
            }
        });
        
        // Calculer pourcentage toxique
        const toxicPercentage = (analysis.toxicBacklinks.length / 
                                analysis.totalBacklinks) * 100;
        
        // Recommandations basées sur analyse
        if (toxicPercentage > 20) {
            analysis.recommendation = 'DISAVOW_URGENT';
            analysis.urgencyLevel = 'HIGH';
            analysis.action = 'Créer fichier désaveu immédiatement';
        } else if (toxicPercentage > 10) {
            analysis.recommendation = 'DISAVOW_RECOMMENDED';
            analysis.urgencyLevel = 'MEDIUM';
            analysis.action = 'Préparer désaveu après tentative contact';
        } else if (analysis.toxicBacklinks.length > 50) {
            analysis.recommendation = 'DISAVOW_CONSIDER';
            analysis.urgencyLevel = 'LOW';
            analysis.action = 'Surveiller évolution, désaveu si augmentation';
        } else {
            analysis.recommendation = 'NO_DISAVOW_NEEDED';
            analysis.urgencyLevel = 'NONE';
            analysis.action = 'Continuer monitoring normal';
        }
        
        return analysis;
    }
    
    calculateToxicity(link) {
        let toxicityScore = 0;
        
        // Indicateurs de toxicité
        if (link.domain_authority < 10) toxicityScore += 0.2;
        if (link.spam_score > 60) toxicityScore += 0.3;
        if (this.isToxicAnchor(link.anchor_text)) toxicityScore += 0.3;
        if (this.isToxicDomain(link.domain)) toxicityScore += 0.4;
        if (link.is_sitewide) toxicityScore += 0.2;
        if (!link.is_followed) toxicityScore -= 0.1;
        
        return Math.min(1, Math.max(0, toxicityScore));
    }
    
    isToxicDomain(domain) {
        const toxicPatterns = [
            /viagra|cialis|levitra/i,
            /casino|poker|gambling/i,
            /payday.*loan|quick.*cash/i,
            /adult|porn|xxx/i,
            /essay.*writ|homework.*help/i,
            /replica|fake.*watch/i
        ];
        
        return toxicPatterns.some(pattern => pattern.test(domain));
    }
}

Situations spécifiques

# Scénarios utilisation outil désaveu
def evaluate_disavow_scenarios(site_data):
    """
    Évalue différents scénarios nécessitant désaveu
    """
    scenarios = {
        'manual_penalty': {
            'detected': check_manual_penalty(site_data),
            'action': 'Désaveu requis pour lever pénalité',
            'priority': 'IMMEDIATE',
            'process': [
                'Identifier tous liens non naturels',
                'Tenter suppression manuelle d\'abord',
                'Désavouer liens impossibles à supprimer',
                'Soumettre demande réexamen'
            ]
        },
        
        'algorithmic_penalty': {
            'detected': detect_algorithmic_penalty(site_data),
            'action': 'Désaveu peut aider récupération',
            'priority': 'HIGH',
            'process': [
                'Analyser profil backlinks complet',
                'Identifier patterns spam',
                'Désavouer domaines toxiques',
                'Attendre prochaine mise à jour algo'
            ]
        },
        
        'negative_seo_attack': {
            'detected': detect_negative_seo(site_data),
            'action': 'Désaveu défensif nécessaire',
            'priority': 'HIGH',
            'indicators': [
                'Spike soudain backlinks spam',
                'Ancres sur-optimisées massives',
                'Liens depuis sites adulte/casino',
                'Patterns temporels suspects'
            ]
        },
        
        'preventive_cleanup': {
            'detected': site_data['toxic_ratio'] > 0.15,
            'action': 'Nettoyage préventif recommandé',
            'priority': 'MEDIUM',
            'benefits': [
                'Éviter future pénalité',
                'Améliorer profil liens global',
                'Protéger contre fluctuations algo'
            ]
        }
    }
    
    return scenarios

Process complet

Avant le désaveu

// Étapes préparatoires avant désaveu
class PreDisavowProcess {
    constructor(domain) {
        this.domain = domain;
        this.contactAttempts = new Map();
    }
    
    async executePreDisavowSteps() {
        const steps = {
            audit: await this.completeBacklinkAudit(),
            outreach: await this.attemptLinkRemoval(),
            documentation: this.documentEvidence(),
            filePreparation: this.prepareDisavowFile()
        };
        
        return steps;
    }
    
    async completeBacklinkAudit() {
        // 1. Exporter tous les backlinks
        const sources = [
            'Google Search Console',
            'Ahrefs',
            'Semrush', 
            'Majestic',
            'Moz'
        ];
        
        const allLinks = await this.aggregateBacklinks(sources);
        
        // 2. Analyser toxicité
        const toxicLinks = allLinks.filter(link => 
            this.assessToxicity(link).score > 0.7
        );
        
        // 3. Catégoriser par action
        return {
            total: allLinks.length,
            toxic: toxicLinks.length,
            domains: this.groupByDomain(toxicLinks),
            priority: this.prioritizeForRemoval(toxicLinks)
        };
    }
    
    async attemptLinkRemoval() {
        const removalCampaign = {
            templatesUsed: {
                polite_request: `
                    Bonjour,
                    
                    J'ai remarqué un lien depuis votre site [URL] vers 
                    notre site [Domain]. Pourriez-vous le retirer?
                    
                    Cordialement,
                    [Name]
                `,
                
                second_attempt: `
                    Bonjour,
                    
                    Suite à mon précédent email, je renouvelle ma demande
                    de suppression du lien [URL].
                    
                    Merci d'avance,
                    [Name]
                `
            },
            
            tracking: []
        };
        
        // Contacter webmasters
        for (const domain of this.toxicDomains) {
            const contact = await this.findContactInfo(domain);
            
            if (contact) {
                const result = await this.sendRemovalRequest(contact, domain);
                
                removalCampaign.tracking.push({
                    domain: domain,
                    contacted: new Date(),
                    method: result.method,
                    response: result.response
                });
                
                this.contactAttempts.set(domain, result);
            }
        }
        
        // Attendre réponses (2-3 semaines)
        await this.waitForResponses(14); // 14 jours
        
        return removalCampaign;
    }
}

Création du fichier

# Générateur fichier désaveu optimisé
class DisavowFileGenerator:
    def __init__(self, toxic_links):
        self.toxic_links = toxic_links
        self.output_lines = []
        
    def generate_file(self):
        """
        Génère fichier désaveu formaté
        """
        # Header informatif
        self.add_header()
        
        # Grouper par type
        individual_urls = []
        domains_to_disavow = set()
        
        for link in self.toxic_links:
            if self.should_disavow_entire_domain(link):
                domains_to_disavow.add(link['domain'])
            else:
                individual_urls.append(link['url'])
        
        # Ajouter URLs individuelles
        if individual_urls:
            self.output_lines.append('\n# URLs individuelles à désavouer')
            for url in sorted(individual_urls):
                self.output_lines.append(url)
        
        # Ajouter domaines complets
        if domains_to_disavow:
            self.output_lines.append('\n# Domaines entiers à désavouer')
            for domain in sorted(domains_to_disavow):
                self.output_lines.append(f'domain:{domain}')
        
        return '\n'.join(self.output_lines)
    
    def add_header(self):
        """
        Ajoute header avec informations utiles
        """
        from datetime import datetime
        
        header = f"""# Fichier désaveu pour {self.domain}
# Généré le {datetime.now().strftime('%Y-%m-%d')}
# Total liens toxiques : {len(self.toxic_links)}
# Contact : {self.contact_email}
#
# Ce fichier désavoue les liens identifiés comme toxiques
# après analyse approfondie et tentatives de suppression
"""
        self.output_lines.append(header)
    
    def should_disavow_entire_domain(self, link):
        """
        Détermine si désavouer domaine entier
        """
        domain_stats = self.get_domain_stats(link['domain'])
        
        # Critères pour désaveu domaine complet
        if domain_stats['toxic_links_count'] > 10:
            return True
        if domain_stats['toxic_ratio'] > 0.9:
            return True
        if link['domain'] in self.known_spam_networks:
            return True
        if domain_stats['is_pbn']:
            return True
            
        return False
    
    def validate_file(self):
        """
        Valide fichier avant soumission
        """
        content = '\n'.join(self.output_lines)
        
        validations = {
            'size': len(content.encode('utf-8')) < 2097152,  # < 2MB
            'encoding': self.is_valid_utf8(content),
            'line_count': len(self.output_lines) < 100000,
            'syntax': self.check_syntax_errors(self.output_lines)
        }
        
        if all(validations.values()):
            return {'valid': True, 'content': content}
        else:
            return {
                'valid': False,
                'errors': [k for k, v in validations.items() if not v]
            }

Suivi post-désaveu

Monitoring impact

// Suivi après soumission désaveu
class PostDisavowMonitoring {
    constructor(disavowDate, domain) {
        this.disavowDate = disavowDate;
        this.domain = domain;
        this.checkpoints = [7, 14, 30, 60, 90]; // jours
    }
    
    async monitorImpact() {
        const monitoring = {
            timeline: [],
            metrics: {
                rankings: {},
                traffic: {},
                penalties: {},
                newToxicLinks: {}
            }
        };
        
        for (const days of this.checkpoints) {
            const checkDate = new Date(this.disavowDate);
            checkDate.setDate(checkDate.getDate() + days);
            
            if (new Date() >= checkDate) {
                const checkpoint = await this.analyzeCheckpoint(checkDate);
                monitoring.timeline.push({
                    daysAfter: days,
                    date: checkDate,
                    ...checkpoint
                });
            }
        }
        
        return this.generateReport(monitoring);
    }
    
    async analyzeCheckpoint(date) {
        return {
            rankings: {
                improved: await this.getImprovedRankings(date),
                declined: await this.getDeclinedRankings(date),
                stable: await this.getStableRankings(date)
            },
            
            traffic: {
                organic: await this.getOrganicTraffic(date),
                change: await this.calculateTrafficChange(date)
            },
            
            penalties: {
                manual: await this.checkManualPenalties(),
                algorithmic: await this.detectAlgorithmicIssues()
            },
            
            newLinks: {
                toxic: await this.findNewToxicLinks(date),
                clean: await this.findNewCleanLinks(date)
            }
        };
    }
    
    generateReport(monitoring) {
        const latestData = monitoring.timeline[monitoring.timeline.length - 1];
        
        return {
            summary: {
                dayssSinceDisavow: this.daysSince(this.disavowDate),
                overallImpact: this.calculateOverallImpact(monitoring),
                recommendation: this.getRecommendation(monitoring)
            },
            
            details: monitoring,
            
            nextSteps: this.determineNextSteps(latestData)
        };
    }
}

Maintenance continue

# Maintenance fichier désaveu
class DisavowFileMaintenance:
    def __init__(self, current_file_path):
        self.current_file = self.load_current_file(current_file_path)
        self.last_update = self.get_last_update_date()
        
    def quarterly_review(self):
        """
        Révision trimestrielle du fichier
        """
        review_results = {
            'date': datetime.now(),
            'current_entries': self.count_entries(),
            'changes': {
                'removed': [],
                'added': [],
                'kept': []
            }
        }
        
        # Vérifier si liens désavoués existent encore
        for entry in self.current_file['entries']:
            if entry.startswith('domain:'):
                domain = entry.replace('domain:', '')
                if self.domain_still_exists(domain):
                    if self.domain_still_toxic(domain):
                        review_results['changes']['kept'].append(entry)
                    else:
                        review_results['changes']['removed'].append({
                            'entry': entry,
                            'reason': 'No longer toxic'
                        })
                else:
                    review_results['changes']['removed'].append({
                        'entry': entry,
                        'reason': 'Domain expired/removed'
                    })
        
        # Identifier nouveaux liens toxiques
        new_toxic = self.find_new_toxic_links()
        for link in new_toxic:
            review_results['changes']['added'].append({
                'entry': f'domain:{link["domain"]}',
                'reason': link['toxicity_reason']
            })
        
        # Générer nouveau fichier si changements
        if review_results['changes']['removed'] or review_results['changes']['added']:
            new_file = self.generate_updated_file(review_results)
            review_results['new_file'] = new_file
            review_results['action_required'] = 'Upload new disavow file'
        else:
            review_results['action_required'] = 'No changes needed'
        
        return review_results
    
    def emergency_update(self, threat_data):
        """
        Mise à jour urgente suite à attaque
        """
        if threat_data['severity'] == 'critical':
            # Ajout rapide domaines malveillants
            emergency_additions = []
            
            for domain in threat_data['malicious_domains']:
                if domain not in self.current_file['domains']:
                    emergency_additions.append(f'domain:{domain}')
            
            if emergency_additions:
                # Créer fichier mise à jour
                updated_content = self.current_file['content']
                updated_content += '\n\n# Emergency update - ' + datetime.now().isoformat()
                updated_content += '\n'.join(emergency_additions)
                
                return {
                    'file_content': updated_content,
                    'additions': len(emergency_additions),
                    'action': 'Upload immediately to Search Console'
                }
        
        return None

L’outil de désaveu reste une solution de dernier recours qui doit être utilisée avec précaution, uniquement après avoir épuisé les autres options et effectué une analyse approfondie des liens toxiques.