Proteger el contenido de tu web es una preocupación legítima, especialmente si trabajas con material original, fotografías profesionales o artículos que te han costado tiempo y esfuerzo crear.
Sin embargo, antes de meternos en materia, vamos a ser realistas desde el principio…
¿Por qué deberías proteger tu contenido?
La protección de contenido web tiene varios objetivos totalmente razonables:
- Dificultar el robo de imágenes para uso comercial no autorizado
- Evitar que copien tus textos para publicarlos en otras webs
- Proteger el trabajo de fotógrafos, diseñadores y artistas
- Reducir el robo automatizado de tu contenido
- Mantener cierto control sobre cómo se distribuye tu material
Pero … hay una cruda realidad: limitaciones en la protección
Aquí viene la parte que muchos no quieren escuchar: si alguien realmente quiere robarte el contenido, lo va a conseguir. Las medidas de protección web son más bien disuasorias que defensas absolutas.
Un usuario con conocimientos técnicos básicos y poco más puede:
- Deshabilitar JavaScript para saltarse la mayoría de protecciones
- Ver el código fuente directamente
- Usar herramientas para desarrolladores
- Hacer capturas de pantalla
- Usar scripts avanzados para descargar contenido
Entonces, ¿para qué sirve proteger? Pues básicamente para dificultar el proceso y disuadir a usuarios casuales.
Es como poner una valla en tu jardín: no va a parar a un ladrón profesional, pero sí evitará que la gente pase por tu césped sin pensárselo.
El equilibrio entre protección y usabilidad
Este es el punto clave: cada medida de protección que implementes puede afectar negativamente a la experiencia de usuario. Los usuarios normales pueden frustrarse si no pueden seleccionar texto para buscarlo, si no funciona el clic derecho, o si la web se vuelve lenta.
La clave está en encontrar el equilibrio perfecto para tu tipo de contenido y audiencia.
Protecciones generales

Estas técnicas funcionan para proteger todo tipo de contenido de forma general. Te explico cada una con código práctico y sus pros y contras.
Impedir el clic derecho
El clic derecho es la forma más básica que tiene la gente de acceder al menú contextual para guardar imágenes o ver el código fuente.
- Recomendado para: Porfolios, sitios con contenido visual
- Dificultad: Básico
- Implementación: Añadir código CSS al personalizador u hoja de estilos y la función al
functions.phpdel tema o plugin de snippets
Solo CSS
/* Impedir selección y menú contextual - AyudaWP.com */
body {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-touch-callout: none;
-webkit-tap-highlight-color: transparent;
}
/* Impedir el menú contextual- AyudaWP.com */
* {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
/* Permitir selección solo en campos de formulario - AyudaWP.com */
input, textarea, select {
-webkit-user-select: text !important;
-moz-user-select: text !important;
-ms-user-select: text !important;
user-select: text !important;
}
CSS + JavaScript
/* Desactivar clic derecho con CSS y JavaScript - AyudaWP.com */
function ayudawp_desactivar_clic_derecho() {
?>
<style>
body {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-touch-callout: none;
}
/* Permitir selección en formularios */
input, textarea, select {
-webkit-user-select: text !important;
-moz-user-select: text !important;
-ms-user-select: text !important;
user-select: text !important;
}
</style>
<script>
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
return false;
});
// Opcional: mostrar mensaje personalizado
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
alert('Contenido protegido');
return false;
});
</script>
<?php
}
add_action('wp_head', 'ayudawp_desactivar_clic_derecho');
Cómo comprobar que funciona:
- Haz clic derecho en cualquier parte de la página
- No debería aparecer el menú contextual
- En formularios sí debería permitir selección
Pros y contras:
- Fácil de implementar
- Disuade a usuarios básicos
- Se salta fácilmente deshabilitando JavaScript
- Puede molestar a usuarios legítimos
- No funciona en dispositivos móviles de forma efectiva
Bloquear combinaciones de teclas de acceso a la consola de desarrolladores del navegador
Las herramientas para desarrolladores de los navegadores modernos son el método más común para acceder al código fuente y descargar recursos.
- Recomendado para: Porfolios, sitios con contenido premium
- Dificultad: Intermedio
- Implementación: Añadir al
functions.phpo plugin de snippets
/* Impedir acceso a Dev Tools del navegador - AyudaWP.com */
function ayudawp_desactivar_dev_tools() {
?>
<script>
// Deshabilitar teclas de desarrollador
document.addEventListener('keydown', function(e) {
// F12
if (e.keyCode === 123) {
e.preventDefault();
return false;
}
// Ctrl+Shift+I
if (e.ctrlKey && e.shiftKey && e.keyCode === 73) {
e.preventDefault();
return false;
}
// Ctrl+Shift+J
if (e.ctrlKey && e.shiftKey && e.keyCode === 74) {
e.preventDefault();
return false;
}
// Ctrl+U (ver código fuente)
if (e.ctrlKey && e.keyCode === 85) {
e.preventDefault();
return false;
}
// Ctrl+S (guardar página)
if (e.ctrlKey && e.keyCode === 83) {
e.preventDefault();
return false;
}
// Ctrl+A (seleccionar todo)
if (e.ctrlKey && e.keyCode === 65) {
e.preventDefault();
return false;
}
// Ctrl+P (imprimir)
if (e.ctrlKey && e.keyCode === 80) {
e.preventDefault();
return false;
}
// Cmd+Option+I (Mac)
if (e.metaKey && e.altKey && e.keyCode === 73) {
e.preventDefault();
return false;
}
});
// Detectar si las herramientas de desarrollador están abiertas
setInterval(function() {
if (window.outerHeight - window.innerHeight > 200 ||
window.outerWidth - window.innerWidth > 200) {
document.body.innerHTML = "Herramientas de desarrollador detectadas";
}
}, 500);
</script>
<?php
}
add_action('wp_footer', 'ayudawp_desactivar_dev_tools');
Cómo comprobar que funciona:
- Prueba las teclas F12, Ctrl+U, Ctrl+Shift+I, Cmd+Option+I
- Ninguna debería funcionar
- Redimensiona la ventana para simular que las herramientas del desarrollador estén abiertas
Pros y contras:
- Bloquea accesos rápidos comunes
- Detecta herramientas de desarrollador abiertas
- Se puede deshabilitar JavaScript
- Puede interferir con usuarios que usan atajos legítimos
- La detección de dev tools no es 100% precisa
Superposiciones transparentes
Esta técnica lo que hace es colocar elementos transparentes encima del contenido para interceptar clics.
- Recomendado para: Sitios con imágenes valiosas, porfolios
- Dificultad: Intermedio
- Implementación: CSS + función PHP automática
CSS para superposiciones
/* Overlays para evitar robo de contenido - AyudaWP.com */
.content-container {
position: relative;
display: inline-block;
}
.protection-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: transparent;
z-index: 10;
cursor: default;
}
/* Para imágenes específicas - AyudaWP.com */
.protected-image {
position: relative;
display: inline-block;
}
.protected-image::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: transparent;
z-index: 2;
}
Implementación automática en WordPress
/* Superposición automática en imágenes para impedir descarga - AyudaWP.com */
function ayudawp_overlay_automatico($content) {
// Envolver todas las imágenes con superposición protectora
$content = preg_replace_callback('/<img[^>]+>/i', function($matches) {
$img = $matches[0];
return '<div class="protected-image">' . $img . '</div>';
}, $content);
return $content;
}
add_filter('the_content', 'ayudawp_overlay_automatico');
// Añadir CSS automáticamente
function ayudawp_estilos_proteger_contenido() {
echo '<style>
.protected-image {
position: relative;
display: inline-block;
}
.protected-image::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: transparent;
z-index: 2;
}
</style>';
}
add_action('wp_head', 'ayudawp_estilos_proteger_contenido');
Cómo comprobar que funciona:
- Inspecciona el código para ver si las imágenes están envueltas en divs
- Intenta hacer clic derecho directamente sobre una imagen
- Verifica que no se puede arrastrar la imagen
Pros y contras:
- Protege contra clics directos sobre contenido
- Invisible para el usuario final
- Puede afectar la interacción legítima con contenido
- No impide acceso desde código fuente
- Puede interferir con diseños adaptados a móviles
Tabla comparativa de protecciones universales
| Técnica | Nivel de protección | Impacto en usabilidad | Dificultad implementación | Compatible móviles |
|---|---|---|---|---|
| Impedir clic derecho | Bajo | Medio | Básico | Parcial |
| Bloquear teclas desarrollador | Medio | Alto | Intermedio | No aplica |
| Overlays transparentes | Medio | Medio | Intermedio | Sí |
Protección específica de textos

El texto es especialmente vulnerable porque es fácil de copiar una vez que se carga en el navegador. Aquí tienes técnicas específicas para protegerlo.
Fragmentar texto con CSS
- Recomendado para: Contenido premium, artículos exclusivos
- Dificultad: Básico
- Implementación: Solo CSS
/* Hacer texto no seleccionable y difícil de copiar - AyudaWP.com */
.protected-text {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
/* Dificultar la lectura en código fuente - AyudaWP.com */
direction: rtl;
unicode-bidi: bidi-override;
text-align: left;
}
/* Crear confusión visual */
.protected-text::before {
content: attr(data-text);
position: absolute;
left: -9999px;
color: transparent;
}
/* Protección adicional con pseudo-elementos - AyudaWP.com */
.text-shield {
position: relative;
display: inline-block;
}
.text-shield::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: transparent;
z-index: 1;
}
Cómo comprobar que funciona:
- Intenta seleccionar el texto protegido
- Revisa el código fuente para ver la fragmentación
Pros y contras:
- Rápido de implementar
- No afecta al rendimiento
- Fácil de saltarse viendo el código fuente
- Puede afectar la accesibilidad
Fragmentación automática de texto
- Recomendado para: Blogs premium, contenido exclusivo
- Dificultad: Avanzado
- Implementación: Función PHP compleja
/* Fragmentar texto para evitar robos masivos - AyudaWP.com */
function ayudawp_fragmentar_texto($text, $fragment_size = 3) {
$fragments = str_split($text, $fragment_size);
$fragmented = '';
foreach ($fragments as $fragment) {
$fragmented .= '<span>' . esc_html($fragment) . '</span>';
}
return $fragmented;
}
// Usar en posts específicos
function ayudawp_protect_content($content) {
// Solo aplicar en ciertos tipos de contenidos
if (is_single() && get_post_type() === 'premium') {
$content = ayudawp_fragmentar_texto($content, 4);
}
return $content;
}
add_filter('the_content', 'ayudawp_protect_content');
Cómo comprobar que funciona:
- Inspecciona el HTML para ver las etiquetas
span - Verifica que el texto aparece fragmentado en el código
Pros y contras:
- Mantiene la apariencia visual normal
- Dificulta la extracción automática
- Puede afectar el SEO negativamente
- Aumenta el tamaño del HTML
Codificación de contenido con JavaScript
- Recomendado para: Contenido muy sensible
- Dificultad: Avanzado
- Implementación: PHP + JavaScript
/* Cifrar contenido premium para evitar robo - AyudaWP.com */
function ayudawp_cifrar_contenido_sensible($content) {
// Buscar y codificar párrafos específicos con shortcode
$pattern = '/\[proteger\](.*?)\[\/proteger\]/s';
$content = preg_replace_callback($pattern, function($matches) {
$protected_content = $matches[1];
$encoded = base64_encode($protected_content);
return '<div data-encoded="' . $encoded . '">Cargando contenido...</div>';
}, $content);
return $content;
}
add_filter('the_content', 'ayudawp_cifrar_contenido_sensible');
function ayudawp_descifrar_script() {
?>
<script>
function ayudawp_descifrar_contenido() {
// Buscar elementos con texto codificado
const encodedElements = document.querySelectorAll('[data-encoded]');
encodedElements.forEach(function(element) {
const encoded = element.getAttribute('data-encoded');
const decoded = atob(encoded);
element.innerHTML = decoded;
element.removeAttribute('data-encoded');
});
}
// Ejecutar cuando carga la página
document.addEventListener('DOMContentLoaded', ayudawp_descifrar_contenido);
</script>
<?php
}
add_action('wp_footer', 'ayudawp_descifrar_script');
Uso en el editor:
Contenido normal aquí. [proteger] Este contenido estará codificado y será más difícil de extraer. [/proteger] Más contenido normal.
Cómo comprobar que funciona:
- Verifica que el contenido dentro de
[proteger]aparece comobase64en el código fuente - Comprueba que se decodifica correctamente al cargar la página
Pros y contras:
- Más difícil de extraer automáticamente
- Flexible y personalizable
- Se puede deshabilitar JavaScript
- Impacto en SEO si no se implementa bien
Conversión de texto a imagen
- Recomendado para: Contenido extremadamente sensible
- Dificultad: Avanzado
- Implementación: PHP con GD activado en el servidor
/* Convertir texto a imagen con shortcode para impedir robo - AyudaWP.com */
function ayudawp_texto_a_imagen($text, $width = 600, $font_size = 16) {
// Verificar que GD esté disponible
if (!extension_loaded('gd')) {
return $text; // Devolver texto normal si no hay GD
}
// Calcular altura necesaria
$lines = explode("\n", wordwrap($text, 80));
$height = count($lines) * ($font_size + 5) + 20;
$image = imagecreatetruecolor($width, $height);
// Colores
$background = imagecolorallocate($image, 255, 255, 255);
$text_color = imagecolorallocate($image, 0, 0, 0);
// Rellenar fondo
imagefill($image, 0, 0, $background);
// Añadir texto línea por línea
$y_position = 20;
foreach ($lines as $line) {
imagestring($image, 4, 10, $y_position, $line, $text_color);
$y_position += $font_size + 5;
}
// Generar nombre único
$filename = 'protected_text_' . md5($text) . '.png';
$filepath = wp_upload_dir()['path'] . '/' . $filename;
$url = wp_upload_dir()['url'] . '/' . $filename;
// Guardar imagen
imagepng($image, $filepath);
imagedestroy($image);
return '<img src="' . $url . '" alt="Contenido protegido" class="protected-text-image">';
}
// El shortcode
function ayudawp_shortcode_proteger_texto($atts, $content) {
$atts = shortcode_atts(array(
'width' => 600,
'font_size' => 16
), $atts);
return ayudawp_texto_a_imagen($content, $atts['width'], $atts['font_size']);
}
add_shortcode('text_image', 'ayudawp_shortcode_proteger_texto');
Uso del shortcode:
[text_image width="500" font_size="18"] Este texto se convertirá en imagen y será más difícil de copiar. [/text_image]
Cómo comprobar que funciona:
- Verifica que se genera una imagen en lugar del texto
- Comprueba que la imagen se guarda en uploads
- Confirma que el texto no aparece en el código fuente
Pros y contras:
- Muy difícil de extraer texto automáticamente
- Protección visual efectiva
- Terrible para SEO
- Problemas gordos de accesibilidad
- No es adaptable a móviles
- Aumenta el tiempo de carga
Protección específica de imágenes

Las imágenes son el tipo de contenido más comúnmente robado. Aquí tienes técnicas específicas para protegerlas.
Marcas de agua automáticas
- Recomendado para: Porfolios, sitios de fotografía, agencias
- Dificultad: Avanzado
- Implementación: Plugin PHP completo (requerido GD activado en el servidor)
<?php
/**
* Plugin Name: Marca de agua automática en imágenes - por AyudaWP.com
* Plugin URI: https://servicios.ayudawp.com
* Description: Añade marcas de agua automáticas a las imágenes subidas a WordPress
* Version: 1.0.0
* Author: Fernando Tellado
* Author URI: https://ayudawp.com
* Text Domain: ayudawp-watermark
* Requires at least: 5.0
* Requires PHP: 7.4
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
*/
// Exit if accessed directly
if (!defined('ABSPATH')) {
exit;
}
// Main watermark class
class AyudaWP_Watermark {
private $watermark_text;
private $font_size;
private $position;
private $enabled;
public function __construct() {
$this->enabled = get_option('ayudawp_watermark_enabled', false);
$this->watermark_text = get_option('ayudawp_watermark_text', get_bloginfo('name'));
$this->position = get_option('ayudawp_watermark_position', 'bottom-right');
if ($this->enabled) {
add_filter('wp_handle_upload', array($this, 'add_watermark_on_upload'));
}
}
public function add_watermark_on_upload($upload) {
$image_path = $upload['file'];
$image_type = wp_check_filetype($image_path);
// Only process images
if (strpos($image_type['type'], 'image') !== false) {
$this->apply_watermark($image_path);
}
return $upload;
}
private function apply_watermark($image_path) {
// Check if GD is available
if (!extension_loaded('gd')) return;
$info = getimagesize($image_path);
if (!$info) return;
$width = $info[0];
$height = $info[1];
$type = $info[2];
// Create image from file
switch ($type) {
case IMAGETYPE_JPEG:
$image = imagecreatefromjpeg($image_path);
break;
case IMAGETYPE_PNG:
$image = imagecreatefrompng($image_path);
break;
case IMAGETYPE_GIF:
$image = imagecreatefromgif($image_path);
break;
default:
return;
}
if (!$image) return;
// Configure watermark
$this->font_size = max(12, $width / 50);
// Calculate position
$positions = $this->calculate_position($width, $height);
$x = $positions['x'];
$y = $positions['y'];
// Semi-transparent colors
$white = imagecolorallocatealpha($image, 255, 255, 255, 50);
$black = imagecolorallocatealpha($image, 0, 0, 0, 50);
// Add shadow
imagestring($image, 3, $x + 1, $y + 1, $this->watermark_text, $black);
// Add main text
imagestring($image, 3, $x, $y, $this->watermark_text, $white);
// Save modified image
switch ($type) {
case IMAGETYPE_JPEG:
imagejpeg($image, $image_path, 90);
break;
case IMAGETYPE_PNG:
imagepng($image, $image_path);
break;
case IMAGETYPE_GIF:
imagegif($image, $image_path);
break;
}
imagedestroy($image);
}
private function calculate_position($width, $height) {
$text_width = strlen($this->watermark_text) * 10;
$text_height = 20;
switch ($this->position) {
case 'top-left':
return array('x' => 20, 'y' => 20);
case 'top-right':
return array('x' => $width - $text_width - 20, 'y' => 20);
case 'bottom-left':
return array('x' => 20, 'y' => $height - $text_height - 20);
case 'bottom-right':
return array('x' => $width - $text_width - 20, 'y' => $height - $text_height - 20);
case 'center':
return array('x' => ($width - $text_width) / 2, 'y' => ($height - $text_height) / 2);
default:
return array('x' => $width - $text_width - 20, 'y' => $height - $text_height - 20);
}
}
}
// Initialize watermark
new AyudaWP_Watermark();
// Admin page
function ayudawp_watermark_admin_page() {
add_options_page(
__('Ajustes de marca de agua', 'ayudawp-watermark'),
__('Marca de agua', 'ayudawp-watermark'),
'manage_options',
'ayudawp-watermark',
'ayudawp_watermark_admin_content'
);
}
add_action('admin_menu', 'ayudawp_watermark_admin_page');
// Admin page content
function ayudawp_watermark_admin_content() {
if (!current_user_can('manage_options')) {
return;
}
if (isset($_POST['submit']) && check_admin_referer('ayudawp_watermark_settings', 'ayudawp_watermark_nonce')) {
update_option('ayudawp_watermark_enabled', isset($_POST['watermark_enabled']));
update_option('ayudawp_watermark_text', sanitize_text_field($_POST['watermark_text']));
update_option('ayudawp_watermark_position', sanitize_text_field($_POST['watermark_position']));
echo '<div class="notice notice-success"><p>' . __('Ajustes guardados.', 'ayudawp-watermark') . '</p></div>';
}
$enabled = get_option('ayudawp_watermark_enabled', false);
$text = get_option('ayudawp_watermark_text', get_bloginfo('name'));
$position = get_option('ayudawp_watermark_position', 'bottom-right');
?>
<div class="wrap">
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
<form method="post">
<?php wp_nonce_field('ayudawp_watermark_settings', 'ayudawp_watermark_nonce'); ?>
<table class="form-table">
<tr>
<th scope="row"><?php _e('Activar marca de agua', 'ayudawp-watermark'); ?></th>
<td>
<label>
<input type="checkbox" name="watermark_enabled" <?php checked($enabled); ?>>
<?php _e('Añadir automáticamente marca de agua a las imágenes subidas', 'ayudawp-watermark'); ?>
</label>
</td>
</tr>
<tr>
<th scope="row"><?php _e('Texto para la marca de agua', 'ayudawp-watermark'); ?></th>
<td>
<input type="text" name="watermark_text" value="<?php echo esc_attr($text); ?>" class="regular-text">
<p class="description"><?php _e('Texto que aparecerá como marca de agua', 'ayudawp-watermark'); ?></p>
</td>
</tr>
<tr>
<th scope="row"><?php _e('Posición', 'ayudawp-watermark'); ?></th>
<td>
<select name="watermark_position">
<option value="bottom-right" <?php selected($position, 'bottom-right'); ?>><?php _e('Abajo a la derecha', 'ayudawp-watermark'); ?></option>
<option value="bottom-left" <?php selected($position, 'bottom-left'); ?>><?php _e('Abajo a la izquierda', 'ayudawp-watermark'); ?></option>
<option value="top-right" <?php selected($position, 'top-right'); ?>><?php _e('Arriba a la derecha', 'ayudawp-watermark'); ?></option>
<option value="top-left" <?php selected($position, 'top-left'); ?>><?php _e('Arriba a la izquierda', 'ayudawp-watermark'); ?></option>
<option value="center" <?php selected($position, 'center'); ?>><?php _e('Centrada', 'ayudawp-watermark'); ?></option>
</select>
</td>
</tr>
</table>
<?php submit_button(); ?>
</form>
</div>
<?php
}
Con esto tienes un plugin completo de marcas de agua. Para instalarlo:
- Crea una carpeta llamada
ayudawp-watermark - Guarda este código como
ayudawp-watermark.phpdentro de esa carpeta - Sube la carpeta a
/wp-content/plugins/ - Actívalo desde el panel de WordPress
- Configúralo en Ajustes > Watermark
El plugin incluye:
- Clase completa con toda la funcionalidad
- Panel de ajustes
- Seguridad con nonces
- Compatible desde WordPress 5.0 y PHP 7.4
Cómo comprobar que funciona:
- Sube una imagen nueva al sitio
- Verifica que aparece la marca de agua en la posición configurada
- Comprueba que la configuración se guarda correctamente
Pros y contras:
- Protección visual efectiva
- Promoción de tu marca
- Disuade uso comercial no autorizado
- Puede afectar la estética
- Aumenta el tiempo de procesamiento
- Se pueden eliminar con herramientas avanzadas
Protección de URLs directas
- Recomendado para: Todos los sitios con contenido visual
- Dificultad: Intermedio
- Implementación: .htaccess + PHP
Configuración usando .htaccess
# Impedir hotlinking de imágenes
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?tudominio.com [NC]
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?google.com [NC]
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?bing.com [NC]
RewriteRule \.(jpg|jpeg|png|gif|webp)$ /imagen-protegida.png [R,L]
Protección avanzada con PHP
/* Impedir acceso externo directo a imágenes - AyudaWP.com */
function ayudawp_proteger_acceso_directo_imagenes() {
add_action('init', function() {
// Verificar si se está accediendo directamente a una imagen
$request_uri = $_SERVER['REQUEST_URI'];
$image_extensions = array('.jpg', '.jpeg', '.png', '.gif', '.webp');
$is_image_request = false;
foreach ($image_extensions as $ext) {
if (strpos($request_uri, $ext) !== false) {
$is_image_request = true;
break;
}
}
if ($is_image_request) {
// Verificar referer
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
$domain = parse_url(home_url(), PHP_URL_HOST);
// Permitir acceso desde el propio dominio y buscadores principales
$allowed_domains = array($domain, 'google.com', 'bing.com', 'duckduckgo.com');
$access_allowed = false;
if (!empty($referer)) {
$referer_domain = parse_url($referer, PHP_URL_HOST);
foreach ($allowed_domains as $allowed) {
if (strpos($referer_domain, $allowed) !== false) {
$access_allowed = true;
break;
}
}
}
if (!$access_allowed && !empty($referer)) {
header('HTTP/1.1 403 Forbidden');
exit('Acceso directo a imágenes no permitido');
}
}
});
}
add_action('wp_loaded', 'ayudawp_proteger_acceso_directo_imagenes');
Cómo comprobar que funciona:
- Intenta acceder directamente a una URL de imagen desde otro navegador
- Verifica que se bloquea el acceso desde dominios externos
- Comprueba que funciona correctamente desde tu propio sitio
Pros y contras:
- Evita el hotlinking y uso desde otros sitios
- Protege el ancho de banda
- Puede bloquear acceso legítimo desde buscadores si no se configura bien
- No funciona si copian la imagen localmente
Calidad adaptativa de imágenes
- Recomendado para: Porfolios que necesitan balance entre calidad y protección
- Dificultad: Avanzado
- Implementación: PHP con procesamiento de imágenes (requerido GD activado en el servidor)
/* Calidad adaptativa de imágenes para desincentivar el robo - AyudaWP.com */
function ayudawp_calidad_imagenes_adaptativa() {
add_filter('wp_handle_upload', 'ayudawp_create_low_quality_version');
add_filter('the_content', 'ayudawp_replace_with_low_quality');
}
function ayudawp_create_low_quality_version($upload) {
$image_path = $upload['file'];
$image_type = wp_check_filetype($image_path);
// Solo procesar JPEG
if ($image_type['type'] !== 'image/jpeg') {
return $upload;
}
if (!extension_loaded('gd')) {
return $upload;
}
$info = getimagesize($image_path);
if (!$info || $info[2] !== IMAGETYPE_JPEG) {
return $upload;
}
$image = imagecreatefromjpeg($image_path);
if (!$image) {
return $upload;
}
// Crear versión de menor calidad
$low_quality_path = str_replace('.jpg', '_web.jpg', $image_path);
imagejpeg($image, $low_quality_path, 60); // Calidad 60%
imagedestroy($image);
return $upload;
}
function ayudawp_replace_with_low_quality($content) {
// Solo en posts específicos o según configuración
if (!is_single() || get_post_type() !== 'portfolio') {
return $content;
}
return preg_replace_callback('/<img[^>]+src=["\']([^"\']+\.jpg)["\'][^>]*>/i', function($matches) {
$img_tag = $matches[0];
$src = $matches[1];
// Solo procesar imágenes locales
if (strpos($src, home_url()) !== false) {
$low_quality_src = str_replace('.jpg', '_web.jpg', $src);
// Verificar que existe la versión de baja calidad
$upload_dir = wp_upload_dir();
$low_quality_path = str_replace($upload_dir['url'], $upload_dir['path'], $low_quality_src);
if (file_exists($low_quality_path)) {
$img_tag = str_replace($src, $low_quality_src, $img_tag);
}
}
return $img_tag;
}, $content);
}
// Activar solo si está configurado
if (get_option('ayudawp_adaptive_quality_enabled', false)) {
ayudawp_calidad_imagenes_adaptativa();
}
Cómo comprobar que funciona:
- Sube una imagen JPEG y verifica que se crea la versión
_web - Comprueba que en el la parte pública de la web se usa la versión de menor calidad
- Comprueba que la calidad sea claramente inferior
Pros y contras:
- Mejora la velocidad de carga
- Imágenes menos útiles para uso comercial
- Puede afectar negativamente a la experiencia visual
- Requiere procesamiento adicional
- Solo funciona con JPEG
Lazy loading con protección
- Recomendado para: Sitios con muchas imágenes
- Dificultad: Avanzado
- Implementación: Plugin PHP completo
<?php
/**
* Plugin Name: Lazy Loading protegido - por AyudaWP.com
* Plugin URI: https://servicios.ayudawp.com
* Description: Lazy loading de imágenes con protección contra descarga masiva
* Version: 1.0.0
* Author: Fernando Tellado
* Author URI: https://ayudawp.com
* Text Domain: ayudawp-lazy-loading
* Requires at least: 5.0
* Requires PHP: 7.4
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
*/
// Exit if accessed directly
if (!defined('ABSPATH')) {
exit;
}
// Main lazy loading class
class AyudaWP_Protected_Lazy_Loading {
private $enabled;
private $exclude_classes;
public function __construct() {
$this->enabled = get_option('ayudawp_lazy_loading_enabled', false);
$this->exclude_classes = get_option('ayudawp_lazy_loading_exclude', 'no-lazy,skip-lazy');
if ($this->enabled) {
add_filter('the_content', array($this, 'add_lazy_loading'));
add_action('wp_head', array($this, 'add_styles'));
add_action('wp_footer', array($this, 'add_script'));
}
}
public function add_lazy_loading($content) {
// Replace src with data-src in images
$content = preg_replace_callback('/<img([^>]+?)src=["\']?([^"\'\s>]+)["\']?([^>]*)>/i', array($this, 'process_image'), $content);
return $content;
}
private function process_image($matches) {
$before = $matches[1];
$src = $matches[2];
$after = $matches[3];
// Check for exclude classes
$exclude_classes = array_map('trim', explode(',', $this->exclude_classes));
foreach ($exclude_classes as $exclude_class) {
if (strpos($before . $after, $exclude_class) !== false) {
return $matches[0]; // Don't apply lazy loading
}
}
// Create placeholder
$placeholder = 'data:image/svg+xml;base64,' . base64_encode(
'<svg width="400" height="300" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="#f0f0f0"/><text x="50%" y="50%" text-anchor="middle" dy=".3em" fill="#999" font-family="Arial">Cargando...</text></svg>'
);
// Add lazy-load class
$has_class = preg_match('/class=["\']([^"\']*)["\']/', $before . $after, $class_matches);
if ($has_class) {
$existing_classes = $class_matches[1];
$new_img = str_replace('class="' . $existing_classes . '"', 'class="' . $existing_classes . ' lazy-load"', $matches[0]);
} else {
$new_img = '<img' . $before . $after . ' class="lazy-load">';
}
// Replace src with placeholder and add data-src
$new_img = str_replace('src="' . $src . '"', 'src="' . $placeholder . '" data-src="' . $src . '"', $new_img);
$new_img = str_replace("src='" . $src . "'", "src='" . $placeholder . "' data-src='" . $src . "'", $new_img);
return $new_img;
}
public function add_styles() {
?>
<style>
/* Lazy loading styles */
.lazy-load {
opacity: 0;
transition: opacity 0.3s ease-in-out;
}
.lazy-load.loaded {
opacity: 1;
}
.lazy-load.loading {
opacity: 0.5;
}
</style>
<?php
}
public function add_script() {
$max_images = get_option('ayudawp_lazy_loading_max_images', 5);
$time_window = get_option('ayudawp_lazy_loading_time_window', 2000);
?>
<script>
/**
* AyudaWP Protected Lazy Loading
* Loads images when they enter viewport with protection against mass download
*/
class AyudaWP_LazyLoad {
constructor() {
this.images = document.querySelectorAll('img[data-src]');
this.observer = null;
this.loadCount = 0;
this.lastLoadTime = Date.now();
this.maxImages = <?php echo intval($max_images); ?>;
this.timeWindow = <?php echo intval($time_window); ?>;
this.init();
}
init() {
if ('IntersectionObserver' in window) {
// Use IntersectionObserver for better performance
this.observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.loadImage(entry.target);
}
});
}, {
rootMargin: '50px' // Start loading slightly before image enters viewport
});
this.images.forEach(img => this.observer.observe(img));
} else {
// Fallback for old browsers
this.images.forEach(img => this.loadImage(img));
}
}
loadImage(img) {
// Check for mass download
if (this.detectMassDownload()) {
console.warn('AyudaWP: Mass download detected, throttling image loading');
return;
}
const src = img.getAttribute('data-src');
if (!src) return;
// Add loading class
img.classList.add('loading');
// Create temporary image to verify load
const tempImg = new Image();
tempImg.onload = () => {
img.src = src;
img.removeAttribute('data-src');
img.classList.remove('loading');
img.classList.add('loaded');
if (this.observer) {
this.observer.unobserve(img);
}
};
tempImg.onerror = () => {
console.error('AyudaWP: Failed to load image:', src);
img.classList.remove('loading');
};
tempImg.src = src;
}
detectMassDownload() {
const now = Date.now();
this.loadCount++;
// Check if loading more than allowed images in time window
if (this.loadCount > this.maxImages && (now - this.lastLoadTime) < this.timeWindow) {
return true;
}
// Reset counter every time window
if (now - this.lastLoadTime > this.timeWindow) {
this.loadCount = 0;
this.lastLoadTime = now;
}
return false;
}
}
// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
new AyudaWP_LazyLoad();
});
} else {
new AyudaWP_LazyLoad();
}
</script>
<?php
}
}
// Initialize only if enabled
new AyudaWP_Protected_Lazy_Loading();
// Admin page
function ayudawp_lazy_loading_admin_page() {
add_options_page(
__('Ajustes de Lazy Loading protegido', 'ayudawp-lazy-loading'),
__('Lazy Loading protegido', 'ayudawp-lazy-loading'),
'manage_options',
'ayudawp-lazy-loading',
'ayudawp_lazy_loading_admin_content'
);
}
add_action('admin_menu', 'ayudawp_lazy_loading_admin_page');
// Admin page content
function ayudawp_lazy_loading_admin_content() {
if (!current_user_can('manage_options')) {
return;
}
if (isset($_POST['submit']) && check_admin_referer('ayudawp_lazy_loading_settings', 'ayudawp_lazy_loading_nonce')) {
update_option('ayudawp_lazy_loading_enabled', isset($_POST['lazy_loading_enabled']));
update_option('ayudawp_lazy_loading_exclude', sanitize_text_field($_POST['lazy_loading_exclude']));
update_option('ayudawp_lazy_loading_max_images', intval($_POST['lazy_loading_max_images']));
update_option('ayudawp_lazy_loading_time_window', intval($_POST['lazy_loading_time_window']));
echo '<div class="notice notice-success"><p>' . __('Ajustes guardados.', 'ayudawp-lazy-loading') . '</p></div>';
}
$enabled = get_option('ayudawp_lazy_loading_enabled', false);
$exclude = get_option('ayudawp_lazy_loading_exclude', 'no-lazy,skip-lazy');
$max_images = get_option('ayudawp_lazy_loading_max_images', 5);
$time_window = get_option('ayudawp_lazy_loading_time_window', 2000);
?>
<div class="wrap">
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
<form method="post">
<?php wp_nonce_field('ayudawp_lazy_loading_settings', 'ayudawp_lazy_loading_nonce'); ?>
<table class="form-table">
<tr>
<th scope="row"><?php _e('Activar Lazy Loading protegido', 'ayudawp-lazy-loading'); ?></th>
<td>
<label>
<input type="checkbox" name="lazy_loading_enabled" <?php checked($enabled); ?>>
<?php _e('Activa lazy loading con protección frente a descargas masivas', 'ayudawp-lazy-loading'); ?>
</label>
<p class="description">
<?php _e('Las imágenes cargarán solo al entrar en la pantalla del dispositivo (viewport), mejorando la velocidad de carga de las páginas, y protegiendo frente a descargas masivas automatizadas.', 'ayudawp-lazy-loading'); ?>
</p>
</td>
</tr>
<tr>
<th scope="row"><?php _e('Clases a excluir', 'ayudawp-lazy-loading'); ?></th>
<td>
<input type="text" name="lazy_loading_exclude" value="<?php echo esc_attr($exclude); ?>" class="regular-text">
<p class="description">
<?php _e('List separada por comas de clases CSS a excluir del lazy loading (e.g., no-lazy,logo,header-image)', 'ayudawp-lazy-loading'); ?>
</p>
</td>
</tr>
</table>
<h2><?php _e('Protección frente a descargas masivas', 'ayudawp-lazy-loading'); ?></h2>
<p><?php _e('Configura el umbral para detectar descargas masivas automatizadas:', 'ayudawp-lazy-loading'); ?></p>
<table class="form-table">
<tr>
<th scope="row"><?php _e('Imágenes máximas', 'ayudawp-lazy-loading'); ?></th>
<td>
<input type="number" name="lazy_loading_max_images" value="<?php echo esc_attr($max_images); ?>" min="1" max="20" class="small-text">
<p class="description">
<?php _e('Cantidad máxima de imágenes que pueden cargarse en la ventana al mismo tiempo (por defecto: 5)', 'ayudawp-lazy-loading'); ?>
</p>
</td>
</tr>
<tr>
<th scope="row"><?php _e('Intervalo temporal (ms)', 'ayudawp-lazy-loading'); ?></th>
<td>
<input type="number" name="lazy_loading_time_window" value="<?php echo esc_attr($time_window); ?>" min="500" max="10000" step="100" class="small-text">
<p class="description">
<?php _e('Intervalo temporal en milisegundos para la detección de descargas masivas (por defecto: 2000 = 2 segundos)', 'ayudawp-lazy-loading'); ?>
</p>
</td>
</tr>
</table>
<div class="notice notice-info inline">
<p><strong><?php _e('Cómo funciona:', 'ayudawp-lazy-loading'); ?></strong></p>
<ul style="list-style: disc; margin-left: 20px;">
<li><?php _e('Se reemplazan las imágenes con marcadores ligeros', 'ayudawp-lazy-loading'); ?></li>
<li><?php _e('Las imágenes reales solo se cargan al entrar en la pantalla del dispositivo (viewport)', 'ayudawp-lazy-loading'); ?></li>
<li><?php _e('Si se solicitan muchas imágenes demasiado rápido se impide la carga', 'ayudawp-lazy-loading'); ?></li>
<li><?php _e('Usa la IntersectionObserver API para un rendimiento óptimo', 'ayudawp-lazy-loading'); ?></li>
<li><?php _e('Respaldo para navegadores anticuados con IntersectionObserver', 'ayudawp-lazy-loading'); ?></li>
</ul>
</div>
<div class="notice notice-warning inline">
<p><strong><?php _e('Importante:', 'ayudawp-lazy-loading'); ?></strong> <?php _e('Excluir imágenes críticas (logos, imágenes above-the-fold) usando las clases a excluir para asegurar que carguen inmediatamente.', 'ayudawp-lazy-loading'); ?></p>
</div>
<?php submit_button(); ?>
</form>
<h2><?php _e('Beneficios', 'ayudawp-lazy-loading'); ?></h2>
<ul style="list-style: disc; margin-left: 20px;">
<li><?php _e('Carga de página inicial más rápida', 'ayudawp-lazy-loading'); ?></li>
<li><?php _e('Reducción del ancho de banda', 'ayudawp-lazy-loading'); ?></li>
<li><?php _e('Mejor experiencia de uso en conexiones lentas', 'ayudawp-lazy-loading'); ?></li>
<li><?php _e('Protección frente a descargas masivas automatizadas', 'ayudawp-lazy-loading'); ?></li>
<li><?php _e('Mejora de puntuaciones en Google PageSpeed', 'ayudawp-lazy-loading'); ?></li>
</ul>
</div>
<?php
}
Y aquí tienes también este otro plugin completo, ahora para lazy loading protegido. Para instalarlo:
- Crea una carpeta llamada
ayudawp-protected-lazy-loading - Guarda este código como
ayudawp-protected-lazy-loading.phpdentro de esa carpeta - Sube la carpeta a
/wp-content/plugins/ - Actívalo desde el panel de WordPress
- Configúralo en «Ajustes > Lazy Loading protegido»
El plugin incluye:
- Lazy loading automático de todas las imágenes del contenido
- Protección contra descarga masiva configurable
- Sistema de exclusión por clases CSS
- Marcador de posición elegante mientras carga
IntersectionObserverpara mejor rendimiento- Respaldo para navegadores antiguos
- Panel de ajustes completo con opciones configurables
- Transiciones suaves CSS
Cómo comprobar que funciona:
- Inspecciona el HTML para ver
data-srcen lugar desrc - Verifica que las imágenes se cargan al hacer scroll
- Prueba cargar muchas imágenes rápidamente para activar la protección
Pros y contras:
- Dificulta la descarga masiva automatizada
- Mejora el rendimiento general
- Puede fallar con JavaScript desactivado
- Añade complejidad al código
- Puede afectar la experiencia de navegación en conexiones lentas
Protección desde el servidor

Las protecciones del lado del servidor son más difíciles de saltarse porque no dependen del navegador del usuario.
Cabeceras de seguridad
- Recomendado para: Todos los sitios
- Dificultad: Básico
- Implementación: Función PHP simple
/* Cabeceras de seguridad para impedir robo de contenido - AyudaWP.com */
function ayudawp_cabeceras_seguridad() {
// Solo en frontend
if (is_admin()) return;
// Impedir embedding en iframes externos
header('X-Frame-Options: SAMEORIGIN');
// Impedir sniffing de tipo de contenido
header('X-Content-Type-Options: nosniff');
// Activar protección XSS del navegador
header('X-XSS-Protection: 1; mode=block');
// Controlar política de referrer
header('Referrer-Policy: strict-origin-when-cross-origin');
// CSP básico
$csp = "default-src 'self'; ";
$csp .= "script-src 'self' 'unsafe-inline' 'unsafe-eval' *.googleapis.com *.gstatic.com; ";
$csp .= "style-src 'self' 'unsafe-inline' *.googleapis.com; ";
$csp .= "img-src 'self' data: *.gravatar.com; ";
$csp .= "font-src 'self' *.googleapis.com *.gstatic.com;";
header('Content-Security-Policy: ' . $csp);
}
add_action('send_headers', 'ayudawp_cabeceras_seguridad');
Cómo comprobar que funciona:
- Usa herramientas como securityheaders.com para verificarlo
- Inspecciona las cabeceras HTTP con las herramientas de desarrollador
- Verifica que no se puede embeber tu sitio en iframes externos
Pros y contras:
- Protección nativa del navegador
- Estándar web moderno
- Fácil de implementar
- Solo funciona en navegadores modernos
- Puede romper funcionalidades legítimas si no se configura bien
Protección de directorios
- Recomendado para: Todos los sitios
- Dificultad: Intermedio
- Implementación: Función PHP que crea archivos
/* Protección de directorios de contenido para evitar robo - AyudaWP.com */
function ayudawp_proteger_directorios() {
$directories_to_protect = array(
wp_upload_dir()['basedir'],
ABSPATH . 'wp-content/themes',
ABSPATH . 'wp-content/plugins'
);
foreach ($directories_to_protect as $directory) {
ayudawp_create_protection_file($directory);
}
}
function ayudawp_create_protection_file($directory) {
$htaccess_file = $directory . '/.htaccess';
$htaccess_content = '';
// Protección específica para uploads
if (strpos($directory, 'uploads') !== false) {
$htaccess_content = '
# Proteger archivos PHP en uploads
<Files "*.php">
Order Deny,Allow
Deny from all
</Files>
# Bloquear ejecución de scripts
Options -ExecCGI
AddHandler cgi-script .php .pl .py .jsp .asp .sh .cgi
# Solo permitir ciertos tipos de archivo
<FilesMatch "\.(jpg|jpeg|png|gif|webp|pdf|doc|docx|zip)$">
Order Allow,Deny
Allow from all
</FilesMatch>
# Bloquear todo lo demás
<FilesMatch "^(?!.*\.(jpg|jpeg|png|gif|webp|pdf|doc|docx|zip)$).*$">
Order Deny,Allow
Deny from all
</FilesMatch>
';
} else {
// Protección general para otros directorios
$htaccess_content = '
# Bloquear acceso directo a directorios
Options -Indexes
# Proteger archivos sensibles
<Files "*.php">
Order Deny,Allow
Deny from all
</Files>
<Files "*.log">
Order Deny,Allow
Deny from all
</Files>
';
}
// Crear o actualizar .htaccess
if (!file_exists($htaccess_file) || get_option('ayudawp_force_protection_update', false)) {
file_put_contents($htaccess_file, $htaccess_content);
}
}
// Ejecutar al activar el tema o plugin
add_action('wp_loaded', 'ayudawp_proteger_directorios');
Cómo comprobar que funciona:
- Intenta acceder directamente a
/wp-content/uploads/ - Verifica que no se listan los archivos
- Comprueba que se bloquea la ejecución de PHP en uploads
Pros y contras:
- Protección efectiva a nivel servidor
- Impide la ejecución de código malicioso
- Difícil de saltarse desde el navegador
- Algunos hosting limitan las opciones de .htaccess
- Puede interferir con plugins legítimos
Detección y bloqueo de bots
- Recomendado para: Sitios con contenido valioso
- Dificultad: Avanzado
- Implementación: Plugin PHP completo
<?php
/**
* Plugin Name: Protección contra bots - por AyudaWP.com
* Plugin URI: https://servicios.ayudawp.com
* Description: Detecta y bloquea bots y scrapers mediante análisis de comportamiento
* Version: 1.0.0
* Author: Fernando Tellado
* Author URI: https://ayudawp.com
* Text Domain: ayudawp-bot-protection
* Requires at least: 5.0
* Requires PHP: 7.4
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
*/
// Exit if accessed directly
if (!defined('ABSPATH')) {
exit;
}
// Main bot protection class
class AyudaWP_Bot_Protection {
private $bot_patterns = array(
'httrack', 'wget', 'winhttrack', 'htmlparser', 'libwww',
'python', 'scrapy', 'mechanize', 'crawler', 'spider',
'bot', 'curl', 'java', 'perl', 'php', 'ruby'
);
private $allowed_bots = array(
'googlebot', 'bingbot', 'slurp', 'duckduckbot',
'baiduspider', 'yandexbot', 'facebookexternalhit'
);
private $suspicious_score = 0;
private $max_score = 100;
public function __construct() {
add_action('init', array($this, 'analyze_request'));
}
public function analyze_request() {
// Check if already blocked
$ip = $_SERVER['REMOTE_ADDR'];
if (get_transient('ayudawp_blocked_' . md5($ip))) {
$this->block_access(__('IP bloqueada previamente', 'ayudawp-bot-protection'));
return;
}
$this->check_user_agent();
$this->check_request_frequency();
$this->check_browsing_pattern();
$this->check_referrer();
if ($this->suspicious_score >= $this->max_score) {
$this->take_action();
}
}
private function check_user_agent() {
$user_agent = strtolower($_SERVER['HTTP_USER_AGENT'] ?? '');
// Allow legitimate bots first
foreach ($this->allowed_bots as $allowed) {
if (strpos($user_agent, $allowed) !== false) {
return;
}
}
// Suspicious patterns
$suspicious_patterns = array(
'python' => 30,
'java' => 25,
'wget' => 50,
'curl' => 40,
'scrapy' => 60,
'bot' => 20,
'crawler' => 25,
'spider' => 25
);
foreach ($suspicious_patterns as $pattern => $score) {
if (strpos($user_agent, $pattern) !== false) {
$this->suspicious_score += $score;
break;
}
}
// Empty or very short user agents
if (empty($user_agent) || strlen($user_agent) < 10) {
$this->suspicious_score += 40;
}
}
private function check_request_frequency() {
$ip = $_SERVER['REMOTE_ADDR'];
$requests_key = 'ayudawp_requests_' . md5($ip);
$requests = get_transient($requests_key);
if ($requests === false) {
set_transient($requests_key, 1, 300); // 5 minutes
} else {
$requests++;
set_transient($requests_key, $requests, 300);
// Score based on frequency
if ($requests > 50) {
$this->suspicious_score += 60;
} elseif ($requests > 30) {
$this->suspicious_score += 40;
} elseif ($requests > 20) {
$this->suspicious_score += 20;
}
}
}
private function check_browsing_pattern() {
$page_visits_key = 'ayudawp_pages_' . md5($_SERVER['REMOTE_ADDR']);
$visited_pages = get_transient($page_visits_key);
if ($visited_pages === false) {
$visited_pages = array($_SERVER['REQUEST_URI']);
} else {
$visited_pages[] = $_SERVER['REQUEST_URI'];
$visited_pages = array_unique($visited_pages);
}
set_transient($page_visits_key, $visited_pages, 1800); // 30 minutes
// Check if only visiting specific resources
$resource_only = true;
foreach ($visited_pages as $page) {
if (!preg_match('/\.(xml|rss|json|txt|pdf|jpg|png|gif)$/i', $page) &&
strpos($page, '/feed') === false) {
$resource_only = false;
break;
}
}
if ($resource_only && count($visited_pages) > 3) {
$this->suspicious_score += 50;
}
}
private function check_referrer() {
$referrer = $_SERVER['HTTP_REFERER'] ?? '';
// No referrer on multiple requests
if (empty($referrer)) {
$this->suspicious_score += 15;
}
// Suspicious referrer
$suspicious_referrers = array('scrapy', 'bot', 'crawler');
foreach ($suspicious_referrers as $pattern) {
if (strpos(strtolower($referrer), $pattern) !== false) {
$this->suspicious_score += 30;
break;
}
}
}
private function take_action() {
$ip = $_SERVER['REMOTE_ADDR'];
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
// Detailed log
error_log("AyudaWP.com: Scraper detectado - Puntuación: {$this->suspicious_score} - IP: {$ip} - UA: {$user_agent}");
// Temporarily block
set_transient('ayudawp_blocked_' . md5($ip), true, 3600); // 1 hour
$this->block_access(__('Detectada actividad sospechosa', 'ayudawp-bot-protection'));
}
private function block_access($reason = '') {
if (empty($reason)) {
$reason = __('Acceso bloqueado', 'ayudawp-bot-protection');
}
http_response_code(429);
header('Retry-After: 3600');
header('Content-Type: text/html; charset=UTF-8');
echo '<!DOCTYPE html>
<html>
<head>
<title>' . esc_html__('Acceso denegado', 'ayudawp-bot-protection') . '</title>
<meta charset="UTF-8">
</head>
<body>
<h1>' . esc_html__('Acceso denegado', 'ayudawp-bot-protection') . '</h1>
<p>' . esc_html($reason) . '</p>
<p>' . esc_html__('Si crees que ha sido por error contacta con el administrador.', 'ayudawp-bot-protection') . '</p>
</body>
</html>';
exit;
}
}
// Initialize only if enabled
if (get_option('ayudawp_bot_protection_enabled', false)) {
new AyudaWP_Bot_Protection();
}
// Admin page
function ayudawp_bot_protection_admin_page() {
add_options_page(
__('Ajustes de protección contra Bots', 'ayudawp-bot-protection'),
__('Protección contra Bots', 'ayudawp-bot-protection'),
'manage_options',
'ayudawp-bot-protection',
'ayudawp_bot_protection_admin_content'
);
}
add_action('admin_menu', 'ayudawp_bot_protection_admin_page');
// Admin page content
function ayudawp_bot_protection_admin_content() {
if (!current_user_can('manage_options')) {
return;
}
if (isset($_POST['submit']) && check_admin_referer('ayudawp_bot_protection_settings', 'ayudawp_bot_protection_nonce')) {
update_option('ayudawp_bot_protection_enabled', isset($_POST['bot_protection_enabled']));
echo '<div class="notice notice-success"><p>' . __('Ajuste guardados.', 'ayudawp-bot-protection') . '</p></div>';
}
$enabled = get_option('ayudawp_bot_protection_enabled', false);
// Get recent blocks for statistics
$blocked_count = 0;
global $wpdb;
$transient_prefix = '_transient_ayudawp_blocked_';
$blocked_ips = $wpdb->get_results(
$wpdb->prepare(
"SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s",
$wpdb->esc_like($transient_prefix) . '%'
)
);
$blocked_count = count($blocked_ips);
?>
<div class="wrap">
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
<div class="notice notice-info">
<p><strong><?php _e('IPs bloqueadas actualmente:', 'ayudawp-bot-protection'); ?></strong> <?php echo esc_html($blocked_count); ?></p>
</div>
<form method="post">
<?php wp_nonce_field('ayudawp_bot_protection_settings', 'ayudawp_bot_protection_nonce'); ?>
<table class="form-table">
<tr>
<th scope="row"><?php _e('Activar protección contra Bots', 'ayudawp-bot-protection'); ?></th>
<td>
<label>
<input type="checkbox" name="bot_protection_enabled" <?php checked($enabled); ?>>
<?php _e('Activar la detección automática de bots y scrapers', 'ayudawp-bot-protection'); ?>
</label>
<p class="description">
<?php _e('Analiza patrones de comportamiento para detectar y bloquear bots. Los bots de motores de búsqueda legítimos (Google, Bing) entran automáticamente en lista blanca.', 'ayudawp-bot-protection'); ?>
</p>
</td>
</tr>
</table>
<h2><?php _e('Cómo funciona', 'ayudawp-bot-protection'); ?></h2>
<p><?php _e('Este plugin analiz múltiples factores para detectar comportamientos sospechosos:', 'ayudawp-bot-protection'); ?></p>
<ul style="list-style: disc; margin-left: 20px;">
<li><?php _e('Análisis del agente de usuario (detecta herramientas de scraping)', 'ayudawp-bot-protection'); ?></li>
<li><?php _e('Frecuencia de peticiones (detecta accesos automáticos)', 'ayudawp-bot-protection'); ?></li>
<li><?php _e('Patrones de navegación (detecta comportamientos no humanos)', 'ayudawp-bot-protection'); ?></li>
<li><?php _e('Verificación del referente (detecta orígenes sospechosos)', 'ayudawp-bot-protection'); ?></li>
</ul>
<p><?php _e('Las IPs bloqueadas se bloquean temporalmente durante 1 hora. Todas las detecciones se registran en el registro de errores en el servidor.', 'ayudawp-bot-protection'); ?></p>
<?php submit_button(); ?>
</form>
<?php if ($enabled && $blocked_count > 10): ?>
<div class="notice notice-warning">
<p><strong><?php _e('Advertencia:', 'ayudawp-bot-protection'); ?></strong> <?php _e('Hay muchas IPs bloqueadas actualmente. Revisa tus registros de errores para asegurar que no haya falsos positivos.', 'ayudawp-bot-protection'); ?></p>
</div>
<?php endif; ?>
</div>
<?php
}
Y este sería el plugin completo de protección contra bots. Para instalarlo:
- Crea una carpeta llamada
ayudawp-bot-protection - Guarda este código como
ayudawp-bot-protection.phpdentro de esa carpeta - Sube la carpeta a
/wp-content/plugins/ - Actívalo desde WordPress
- Configúralo en «Ajustes > Protección contra Bots»
El plugin incluye:
- Sistema completo de detección por puntuación
- Lista blanca automática de bots legítimos (Google, Bing, etc.)
- Panel de ajustes con estadísticas
- Bloqueo temporal de 1 hora
- Registros automáticos en error_log
- Avisos si hay muchos bloqueos (posibles falsos positivos)
Cómo comprobar que funciona:
- Simula peticiones con
curlowget - Verifica que se bloquean después de varias peticiones
- Comprueba los logs de error para ver las detecciones
Pros y contras:
- Protección proactiva contra scraping
- Personalizable según patrones específicos
- Aprende de comportamientos sospechosos
- Puede generar falsos positivos
- Requiere ajuste fino
- Scrapers avanzados pueden evitar la detección
Protección contra robo de scrapers y feeds

El scraping automatizado y los agregadores de contenido son una amenaza constante para sitios con contenido original.
Limitación de feeds RSS
- Recomendado para: Blogs, sitios de noticias
- Dificultad: Básico
- Implementación: Filtros WordPress
/* Limitar el contenido de feeds para evitar robos masivos - AyudaWP.com */
function ayudawp_limit_feed_content($content) {
global $post;
// Solo mostrar extracto en feeds
if (is_feed()) {
// Limitar a 150 palabras
$excerpt = wp_trim_words($content, 150, '...');
// Añadir enlace al artículo completo
$read_more = sprintf(
'<p><a href="%s" rel="nofollow">Leer artículo completo en %s</a></p>',
get_permalink($post->ID),
get_bloginfo('name')
);
// Añadir información de copyright
$copyright = '<p>© ' . date('Y') . ' ' . get_bloginfo('name') . ' - Todos los derechos reservados</p>';
return $excerpt . $read_more . $copyright;
}
return $content;
}
add_filter('the_content', 'ayudawp_limit_feed_content');
add_filter('the_excerpt_rss', 'ayudawp_limit_feed_content');
function ayudawp_add_feed_copyright() {
if (is_feed()) {
echo '<copyright>' . esc_html(get_bloginfo('name')) . ' - Todos los derechos reservados</copyright>';
echo '<managingEditor>' . esc_html(get_bloginfo('admin_email')) . ' (' . esc_html(get_bloginfo('name')) . ')</managingEditor>';
}
}
add_action('rss2_head', 'ayudawp_add_feed_copyright');
add_action('rss_head', 'ayudawp_add_feed_copyright');
Cómo comprobar que funciona:
- Visita
/feed/en tu sitio - Verifica que solo aparecen extractos
- Comprueba que aparece el enlace para leerlo completo
Pros y contras:
- Reduce el contenido disponible para agregadores
- Mantiene tráfico hacia tu sitio
- Puede afectar la experiencia de lectores legítimos de RSS
- Algunos agregadores pueden adaptar sus métodos
Limitaciones por tipo de contenido
- Recomendado para: Sitios con contenido valioso
- Dificultad: Avanzado
- Implementación: Sistema completo PHP
/* Limitar la tasa de peticiones para evitar robo de contenido - AyudaWP.com */
function ayudawp_content_rate_limiting() {
$ip = $_SERVER['REMOTE_ADDR'];
$current_url = $_SERVER['REQUEST_URI'];
// Diferentes límites según el tipo de contenido
$limits = array(
'feed' => array('requests' => 10, 'period' => 3600), // 10 por hora
'image' => array('requests' => 50, 'period' => 300), // 50 por 5 min
'post' => array('requests' => 30, 'period' => 300), // 30 por 5 min
'page' => array('requests' => 20, 'period' => 300), // 20 por 5 min
);
// Determinar tipo de contenido
$content_type = 'page'; // default
if (strpos($current_url, '/feed') !== false || strpos($current_url, '.xml') !== false) {
$content_type = 'feed';
} elseif (preg_match('/\.(jpg|jpeg|png|gif|webp)$/i', $current_url)) {
$content_type = 'image';
} elseif (is_single()) {
$content_type = 'post';
}
$limit = $limits[$content_type];
$cache_key = "ayudawp_limit_{$content_type}_" . md5($ip);
$requests = get_transient($cache_key);
if ($requests === false) {
set_transient($cache_key, 1, $limit['period']);
} else {
$requests++;
set_transient($cache_key, $requests, $limit['period']);
if ($requests > $limit['requests']) {
// Log del límite excedido
error_log("AyudaWP: Rate limit excedido - Tipo: {$content_type} - IP: {$ip} - Requests: {$requests}");
http_response_code(429);
header('Retry-After: ' . $limit['period']);
wp_die(
"Límite de peticiones excedido para {$content_type}. Intenta de nuevo en " . ($limit['period']/60) . " minutos.",
'Límite Excedido',
array('response' => 429)
);
}
}
}
add_action('template_redirect', 'ayudawp_content_rate_limiting');
Cómo comprobar que funciona:
- Haz múltiples peticiones rápidas al mismo tipo de contenido
- Verifica que se activa el límite
- Comprueba que el mensaje de error es apropiado
Pros y contras:
- Impide la descarga masiva de contenido
- Protege recursos del servidor
- Diferencia entre tipos de contenido
- Puede impactar usuarios legítimos en redes compartidas
- Requiere ajuste fino para evitar bloqueos incorrectos
Detección avanzada de scrapers
- Recomendado para: Sitios con contenido premium
- Dificultad: Avanzado
- Implementación: Sistema de puntuación complejo
/* Proteger feeds frente a scrapers de contenido - AyudaWP.com */
function ayudawp_feed_protection() {
if (!is_feed()) return;
$ip = $_SERVER['REMOTE_ADDR'];
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
// Verificar frecuencia de acceso al feed
$feed_access_key = 'ayudawp_feed_access_' . md5($ip);
$access_count = get_transient($feed_access_key);
if ($access_count === false) {
$access_count = 1;
set_transient($feed_access_key, $access_count, 3600); // 1 hora
} else {
$access_count++;
set_transient($feed_access_key, $access_count, 3600);
}
// Verificar patrones sospechosos
$suspicious_patterns = array('bot', 'crawler', 'spider', 'scraper', 'harvester');
$is_suspicious_ua = false;
foreach ($suspicious_patterns as $pattern) {
if (strpos(strtolower($user_agent), $pattern) !== false) {
$is_suspicious_ua = true;
break;
}
}
// Bloquear si más de 10 accesos por hora o UA sospechoso con más de 3 accesos
if ($access_count > 10 || ($is_suspicious_ua && $access_count > 3)) {
error_log("AyudaWP: Feed bloqueado - IP: {$ip} - UA: {$user_agent} - Accesos: {$access_count}");
wp_die('Acceso al feed limitado. Demasiadas peticiones.', 'Límite superado', array('response' => 429));
}
// Log de accesos frecuentes
if ($access_count > 5) {
error_log("AyudaWP: Acceso frecuente al feed - IP: {$ip} - UA: {$user_agent} - Accesos: {$access_count}");
}
}
add_action('template_redirect', 'ayudawp_feed_protection');
Cómo comprobar que funciona:
- Accede al feed múltiples veces en poco tiempo
- Prueba con diferentes user agents
- Verifica los logs para ver las detecciones
Pros y contras:
- Identificación específica de scrapers de feeds
- Protección granular según comportamiento
- Logs detallados para análisis
- Puede afectar lectores RSS legítimos
- Requiere monitorización de logs
Protección avanzada contra scraping masivo
- Recomendado para: Sitios con contenido muy valioso
- Dificultad: Avanzado
- Implementación: Plugin PHP completo de detección
<?php
/**
* Plugin Name: Detección avanzada de scrapers - por AyudaWP.com
* Plugin URI: https://servicios.ayudawp.com
* Description: Detección avanzada de scrapers mediante análisis de patrones de comportamiento, timing y sesiones
* Version: 1.0.0
* Author: Fernando Tellado
* Author URI: https://ayudawp.com
* Text Domain: ayudawp-advanced-scraper
* Requires at least: 5.0
* Requires PHP: 7.4
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
*/
// Exit if accessed directly
if (!defined('ABSPATH')) {
exit;
}
// Main advanced scraper detection class
class AyudaWP_Advanced_Scraper_Detection {
private $suspicious_score = 0;
private $max_score = 100;
private $ip;
private $user_agent;
public function __construct() {
$this->ip = $_SERVER['REMOTE_ADDR'];
$this->user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
add_action('init', array($this, 'analyze_request'));
}
public function analyze_request() {
// Check if already blocked
if (get_transient('ayudawp_scraper_blocked_' . md5($this->ip))) {
$this->block_access(__('IP previamente bloqueada por scraping', 'ayudawp-advanced-scraper'));
return;
}
$this->check_request_patterns();
$this->check_content_access_pattern();
$this->check_timing_patterns();
$this->check_session_behavior();
if ($this->suspicious_score >= $this->max_score) {
$this->take_scraper_action();
}
}
private function check_request_patterns() {
// Check for suspicious request patterns
$request_uri = $_SERVER['REQUEST_URI'];
$query_string = $_SERVER['QUERY_STRING'] ?? '';
// Automated pattern search
$automated_patterns = array(
'/page/\d+/' => 20, // Sequential page access
'/\?p=\d+/' => 15, // Direct access by ID
'/feed/' => 10, // Feed access
'/sitemap/' => 25, // Sitemap access
);
foreach ($automated_patterns as $pattern => $score) {
if (preg_match($pattern, $request_uri)) {
$this->suspicious_score += $score;
}
}
// Suspicious parameters in query string
$suspicious_params = array('page', 'offset', 'limit', 'batch');
foreach ($suspicious_params as $param) {
if (strpos($query_string, $param) !== false) {
$this->suspicious_score += 15;
}
}
}
private function check_content_access_pattern() {
// Analyze what type of content is being accessed
$content_access_key = 'ayudawp_content_access_' . md5($this->ip);
$accessed_content = get_transient($content_access_key);
if ($accessed_content === false) {
$accessed_content = array(
'images' => 0,
'posts' => 0,
'pages' => 0,
'feeds' => 0
);
}
// Increment counter by current type
if (is_attachment() || preg_match('/\.(jpg|jpeg|png|gif)$/i', $_SERVER['REQUEST_URI'])) {
$accessed_content['images']++;
} elseif (is_single()) {
$accessed_content['posts']++;
} elseif (is_page()) {
$accessed_content['pages']++;
} elseif (is_feed()) {
$accessed_content['feeds']++;
}
set_transient($content_access_key, $accessed_content, 1800); // 30 minutes
// Score based on access patterns
$total_content = array_sum($accessed_content);
if ($total_content > 20) {
// High volume of content access
$this->suspicious_score += 30;
// Specific pattern: only images
if ($accessed_content['images'] > $total_content * 0.8) {
$this->suspicious_score += 25;
}
// Specific pattern: only posts
if ($accessed_content['posts'] > $total_content * 0.7) {
$this->suspicious_score += 20;
}
}
}
private function check_timing_patterns() {
// Analyze timing patterns between requests
$timing_key = 'ayudawp_request_timing_' . md5($this->ip);
$last_requests = get_transient($timing_key);
$current_time = time();
if ($last_requests === false) {
$last_requests = array($current_time);
} else {
$last_requests[] = $current_time;
// Keep only last 10 requests
$last_requests = array_slice($last_requests, -10);
}
set_transient($timing_key, $last_requests, 600); // 10 minutes
if (count($last_requests) >= 5) {
// Calculate intervals between requests
$intervals = array();
for ($i = 1; $i < count($last_requests); $i++) {
$intervals[] = $last_requests[$i] - $last_requests[$i-1];
}
// Check regular patterns (automated scraping)
$avg_interval = array_sum($intervals) / count($intervals);
$variance = 0;
foreach ($intervals as $interval) {
$variance += pow($interval - $avg_interval, 2);
}
$variance = $variance / count($intervals);
// Very regular intervals (low variance)
if ($variance < 2 && $avg_interval < 10) {
$this->suspicious_score += 40;
}
// Very frequent requests
if ($avg_interval < 1) {
$this->suspicious_score += 50;
}
}
}
private function check_session_behavior() {
// Check session behavior
$session_key = 'ayudawp_session_behavior_' . md5($this->ip);
$session_data = get_transient($session_key);
if ($session_data === false) {
$session_data = array(
'start_time' => time(),
'pages_visited' => 1,
'user_interactions' => 0,
'referrers' => array()
);
} else {
$session_data['pages_visited']++;
}
// Record referrer
$referrer = $_SERVER['HTTP_REFERER'] ?? '';
if (!empty($referrer) && !in_array($referrer, $session_data['referrers'])) {
$session_data['referrers'][] = $referrer;
}
set_transient($session_key, $session_data, 3600); // 1 hour
$session_duration = time() - $session_data['start_time'];
// Suspicious session patterns
if ($session_duration > 300) { // More than 5 minutes
$pages_per_minute = $session_data['pages_visited'] / ($session_duration / 60);
// More than 10 pages per minute for more than 5 minutes
if ($pages_per_minute > 10) {
$this->suspicious_score += 35;
}
// No external referrers (possible bot)
if (empty($session_data['referrers'])) {
$this->suspicious_score += 20;
}
}
}
private function take_scraper_action() {
// Detailed log of detected scraper
$log_data = array(
'ip' => $this->ip,
'user_agent' => $this->user_agent,
'score' => $this->suspicious_score,
'url' => $_SERVER['REQUEST_URI'],
'referrer' => $_SERVER['HTTP_REFERER'] ?? '',
'timestamp' => date('Y-m-d H:i:s')
);
error_log("AyudaWP: Advanced scraper detected - " . json_encode($log_data));
// Block for longer (6 hours)
set_transient('ayudawp_scraper_blocked_' . md5($this->ip), true, 21600);
$this->block_access(__('Scraping automatizado detectado', 'ayudawp-advanced-scraper'));
}
private function block_access($reason) {
http_response_code(429);
header('Retry-After: 21600'); // 6 hours
header('Content-Type: text/html; charset=UTF-8');
echo '<!DOCTYPE html>
<html>
<head>
<title>' . esc_html__('Acceso bloqueado', 'ayudawp-advanced-scraper') . '</title>
<meta charset="UTF-8">
</head>
<body>
<h1>' . esc_html__('Acceso temporalmente bloqueado', 'ayudawp-advanced-scraper') . '</h1>
<p>' . esc_html($reason) . '</p>
<p>' . esc_html__('Tu IP ha sido bloqueada temporalmente debido a patrones de acceso sospechosos.', 'ayudawp-advanced-scraper') . '</p>
<p>' . esc_html__('Si eres un usuario legítimo espera 6 horas antes de intentar de nuevo el acceso.', 'ayudawp-advanced-scraper') . '</p>
</body>
</html>';
exit;
}
}
// Initialize only if enabled
if (get_option('ayudawp_advanced_scraper_detection', false)) {
new AyudaWP_Advanced_Scraper_Detection();
}
// Admin page
function ayudawp_advanced_scraper_admin_page() {
add_options_page(
__('Detección avanzada de scrapers', 'ayudawp-advanced-scraper'),
__('Detección de scrapers', 'ayudawp-advanced-scraper'),
'manage_options',
'ayudawp-advanced-scraper',
'ayudawp_advanced_scraper_admin_content'
);
}
add_action('admin_menu', 'ayudawp_advanced_scraper_admin_page');
// Admin page content
function ayudawp_advanced_scraper_admin_content() {
if (!current_user_can('manage_options')) {
return;
}
if (isset($_POST['submit']) && check_admin_referer('ayudawp_advanced_scraper_settings', 'ayudawp_advanced_scraper_nonce')) {
update_option('ayudawp_advanced_scraper_detection', isset($_POST['advanced_scraper_enabled']));
echo '<div class="notice notice-success"><p>' . __('Ajustes guardados.', 'ayudawp-advanced-scraper') . '</p></div>';
}
$enabled = get_option('ayudawp_advanced_scraper_detection', false);
// Get statistics
global $wpdb;
$transient_prefix = '_transient_ayudawp_scraper_blocked_';
$blocked_ips = $wpdb->get_results(
$wpdb->prepare(
"SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s",
$wpdb->esc_like($transient_prefix) . '%'
)
);
$blocked_count = count($blocked_ips);
?>
<div class="wrap">
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
<div class="notice notice-info">
<p><strong><?php _e('Currently blocked scrapers:', 'ayudawp-advanced-scraper'); ?></strong> <?php echo esc_html($blocked_count); ?></p>
<p><?php _e('Las IPs bloqueadas se bloquean temporalmente durante 6 horas.', 'ayudawp-advanced-scraper'); ?></p>
</div>
<form method="post">
<?php wp_nonce_field('ayudawp_advanced_scraper_settings', 'ayudawp_advanced_scraper_nonce'); ?>
<table class="form-table">
<tr>
<th scope="row"><?php _e('Activar la detección avanzada', 'ayudawp-advanced-scraper'); ?></th>
<td>
<label>
<input type="checkbox" name="advanced_scraper_enabled" <?php checked($enabled); ?>>
<?php _e('Activar la detección avanzada de scrapers', 'ayudawp-advanced-scraper'); ?>
</label>
<p class="description">
<?php _e('Usa un sofisticado análisis de comportamientos para detectar scraping automatizado. Es más efectivo, pero puede generar falso positivos en usuarios muy activos.', 'ayudawp-advanced-scraper'); ?>
</p>
</td>
</tr>
</table>
<h2><?php _e('Métodos de detección', 'ayudawp-advanced-scraper'); ?></h2>
<p><?php _e('Este plugin usa múltiples capas de análisis para detectar el scraping:', 'ayudawp-advanced-scraper'); ?></p>
<h3><?php _e('1. Análisis de patrones de petición', 'ayudawp-advanced-scraper'); ?></h3>
<ul style="list-style: disc; margin-left: 20px;">
<li><?php _e('Acceso secuencial a páginas (page/1, page/2...)', 'ayudawp-advanced-scraper'); ?></li>
<li><?php _e('Acceso directo por ID', 'ayudawp-advanced-scraper'); ?></li>
<li><?php _e('Accesos sistemáticos al mapa del sitio', 'ayudawp-advanced-scraper'); ?></li>
<li><?php _e('Parámetros sospechosos (offset, limit, batch)', 'ayudawp-advanced-scraper'); ?></li>
</ul>
<h3><?php _e('2. Patrones de acceso a contenidos', 'ayudawp-advanced-scraper'); ?></h3>
<ul style="list-style: disc; margin-left: 20px;">
<li><?php _e('Vigila el tipo de contenido al que se accede (imágenes, entradas, páginas)', 'ayudawp-advanced-scraper'); ?></li>
<li><?php _e('Detecta enfoque en tipos de contenidos individuales', 'ayudawp-advanced-scraper'); ?></li>
<li><?php _e('Identifica altos volúmenes de consultas en poco tiempo', 'ayudawp-advanced-scraper'); ?></li>
</ul>
<h3><?php _e('3. Análisis de patrones de tiempo', 'ayudawp-advanced-scraper'); ?></h3>
<ul style="list-style: disc; margin-left: 20px;">
<li><?php _e('Calcula intervalos entre peticiones', 'ayudawp-advanced-scraper'); ?></li>
<li><?php _e('Detecta patrones habituales de petición (bots)', 'ayudawp-advanced-scraper'); ?></li>
<li><?php _e('Identifica peticiones demasiado frecuentes', 'ayudawp-advanced-scraper'); ?></li>
</ul>
<h3><?php _e('4. Comportamiento en la sesión', 'ayudawp-advanced-scraper'); ?></h3>
<ul style="list-style: disc; margin-left: 20px;">
<li><?php _e('Analiza las páginas por minuto', 'ayudawp-advanced-scraper'); ?></li>
<li><?php _e('Revisa referentes externos', 'ayudawp-advanced-scraper'); ?></li>
<li><?php _e('Evalúa el comportamiento global de la sesión', 'ayudawp-advanced-scraper'); ?></li>
</ul>
<div class="notice notice-warning inline">
<p><strong><?php _e('Importante:', 'ayudawp-advanced-scraper'); ?></strong> <?php _e('Este plugin es muy estricto y podría bloquear usuarios normales que naveguen muy rápido. Vigila regularmente los registros de errores para comprobar si hay falsos positivos.', 'ayudawp-advanced-scraper'); ?></p>
</div>
<?php submit_button(); ?>
</form>
<?php if ($enabled && $blocked_count > 20): ?>
<div class="notice notice-error">
<p><strong><?php _e('Alerta:', 'ayudawp-advanced-scraper'); ?></strong> <?php _e('Actualmente hay muchos scrapers bloqueados. Esto podría significar:', 'ayudawp-advanced-scraper'); ?></p>
<ul style="list-style: disc; margin-left: 20px;">
<li><?php _e('Un ataque de scraping real (bien)', 'ayudawp-advanced-scraper'); ?></li>
<li><?php _e('Falsos positivos con usuarios normales (revisa los logs)', 'ayudawp-advanced-scraper'); ?></li>
</ul>
<p><?php _e('Revisa tus logs de errores del servidor en cada detección.', 'ayudawp-advanced-scraper'); ?></p>
</div>
<?php endif; ?>
</div>
<?php
}
En esta ocasión es un plugin completo de detección avanzada de scrapers. Para instalarlo:
- Crea una carpeta llamada
ayudawp-advanced-scraper-detection - Guarda este código como
ayudawp-advanced-scraper-detection.phpdentro de esa carpeta - Sube la carpeta a
/wp-content/plugins/ - Actívalo desde el panel de WordPress
- Configúralo en Ajustes > Scraper Detection
El plugin incluye:
- 4 capas de análisis (patrones de requests, contenido, timing, sesión)
- Bloqueo temporal de 6 horas (más largo que el básico)
- Panel de administración con estadísticas y explicación detallada
- Alertas si hay muchos bloqueos (posibles falsos positivos)
- Logs detallados en formato JSON
- Textos preparados para traducción
- Avisos sobre posibles falsos positivos con usuarios muy activos
Este es el más estricto de los tres plugins de protección contra bots/scrapers.
Cómo comprobar que funciona:
- Simula patrones de scraping automatizado
- Accede a múltiples páginas en secuencia rápida
- Verifica que se detectan los patrones y se activa el bloqueo
Pros y contras:
- Detección muy sofisticada de patrones de scraping
- Análisis de comportamiento en múltiples dimensiones
- Logs detallados para análisis posterior
- Mayor complejidad de configuración
- Posibles falsos positivos con usuarios muy activos
- Requiere ajuste fino de parámetros
Uso de plugins para evitar el robo de contenidos

Si prefieres no tocar código, existen varios plugins que pueden ayudarte con la protección de contenido.
WP Content Copy Protection & No Right Click
- Precio: Gratuito
- Recomendado para: Principiantes, sitios básicos
- Dificultad: Básico (instalación automática)
Características principales:
- Deshabilita clic derecho en toda la web
- Bloquea selección de texto
- Impide copiar y pegar
- Desactiva teclas de desarrollador básicas
- Mensajes personalizables al intentar copiar
Cómo comprobar que funciona:
- Activar el plugin desde el panel de WordPress
- Probar clic derecho en cualquier parte de la página
- Intentar seleccionar texto del contenido
- Probar teclas F12 y Ctrl+U
- Verificar que aparecen los mensajes personalizados
Pros:
- Completamente gratuito
- Muy fácil de usar y configurar
- Interfaz simple e intuitiva
- No requiere conocimientos técnicos
- Bien mantenido y actualizado regularmente
- Compatible con la mayoría de temas de WordPress
- Bajo impacto en rendimiento
Contras:
- Protección muy básica y superficial
- Fácil de saltarse deshabilitando JavaScript
- Puede molestar a usuarios legítimos
- No protege contra usuarios con conocimientos técnicos
- Protección solo del lado del cliente
Disable Right Click For WP
- Precio: Gratuito
- Recomendado para: Usuarios que solo necesitan deshabilitar clic derecho
- Dificultad: Básico
Características principales:
- Bloqueo específico de clic derecho
- Mensajes de alerta personalizables
- Configuración muy simple
- Extremadamente ligero
Cómo comprobar que funciona:
- Instalar y activar el plugin
- Hacer clic derecho en cualquier zona de la web
- Verificar que aparece el mensaje de alerta personalizado
- Comprobar que no afecta a formularios
Pros:
- Gratuito
- Extremadamente ligero (casi sin impacto en rendimiento)
- Instalación y configuración en menos de 2 minutos
- Opciones de personalización de mensajes
- No genera conflictos con otros plugins
Contras:
- Solo protege contra clic derecho (nada más)
- Protección muy básica
- No bloquea otras formas de copiar contenido
- Inútil contra usuarios técnicos
- Solo disuasorio para usuarios muy básicos
WP-CopyRight Pro
- Precio: 29-59€ según tipo de licencia
- Recomendado para: Portfolios profesionales, sitios con contenido premium
- Dificultad: Intermedio
Características principales:
- Protección avanzada de imágenes con múltiples capas
- Protección de textos y PDFs
- Detección de herramientas de desarrollador
- Marcas de agua automáticas opcionales
- Sistema de logs y monitorización
- Protección específica por tipo de contenido
- Whitelist de IPs para acceso sin restricciones
Cómo comprobar que funciona:
- Revisar el panel de configuración detallado en WordPress
- Verificar los logs de actividad del plugin
- Probar diferentes niveles de protección en páginas de prueba
- Comprobar funcionamiento en dispositivos móviles
- Revisar estadísticas de intentos de copia bloqueados
Pros:
- Múltiples capas de protección configurables
- Configuración muy granular por tipo de página
- Excelente documentación y tutoriales
- Soporte técnico responsive
- Actualizaciones regulares
- Logs de actividad muy detallados
- Compatible con la mayoría de temas y plugins
- Opciones avanzadas para usuarios expertos
Contras:
- Coste de licencia anual (no es pago único)
- Puede afectar funcionalidades legítimas si se configura mal
- Curva de aprendizaje más pronunciada
- Algunas funciones pueden ralentizar el sitio si se activan todas
- Requiere tiempo para configurar correctamente
- Las actualizaciones a veces cambian configuraciones
UnGrabber
- Precio: 39-89€ según tipo de licencia
- Recomendado para: Fotógrafos, diseñadores, portfolios visuales
- Dificultad: Intermedio
Características principales:
- Especializado en protección de imágenes
- Overlays invisibles sobre imágenes
- Sistema de marcas de agua automáticas
- Protección contra arrastrar imágenes
- Bloqueo de herramientas de inspección en imágenes
- Calidad de imagen adaptativa
- Configuración específica para galerías
Cómo comprobar que funciona:
- Subir imágenes de prueba
- Verificar que las marcas de agua se aplican correctamente
- Intentar hacer clic derecho sobre imágenes
- Probar arrastrar imágenes fuera del navegador
- Comprobar calidad de imagen servida en frontend
Pros:
- Muy especializado en protección visual
- Excelente para portfolios de fotografía
- Buena integración con galerías populares
- Marcas de agua estéticas y personalizables
- Configuración por galería o tipo de imagen
- Buen balance entre protección y estética
Contras:
- Solo protege imágenes (no texto ni otros contenidos)
- Precio elevado para funcionalidad específica
- Impacto medio en rendimiento por procesamiento de imágenes
- Requiere configuración detallada para resultados óptimos
- No incluye protección contra scraping automatizado
- Las marcas de agua son opcionales, no obligatorias
Tabla comparativa de plugins
| Plugin | Precio | Características principales | Protección que ofrece | Impacto en rendimiento | Valoración |
|---|---|---|---|---|---|
| WP Content Copy Protection | Gratuito | Clic derecho, selección, teclas | Básica | Mínimo | 3/5 |
| Disable Right Click | Gratuito | Solo clic derecho | Muy básica | Ninguno | 2/5 |
| WP-CopyRightPro | 29-59€ | Protección completa | Media-Alta | Bajo-Medio | 4/5 |
| UnGrabber | 39-89€ | Especializado imágenes | Media | Medio | 3.5/5 |
Cuándo usar plugins vs código personalizado
Usa plugins cuando
Perfil ideal para plugins:
- No tienes conocimientos técnicos de PHP o JavaScript
- Necesitas una solución rápida e inmediata sin desarrollo
- Quieres soporte técnico profesional y actualizaciones automáticas
- Tu presupuesto permite la inversión en plugins premium
- Prefieres una interfaz de configuración visual en lugar de código
- Trabajas con múltiples sitios y necesitas consistencia entre ellos
- No tienes acceso a un desarrollador o presupuesto para contratarlo
- Valoras más la rapidez de implementación que el control total
Ventajas de usar plugins:
- Instalación en minutos sin tocar código
- Interfaz visual para todas las configuraciones
- Actualizaciones automáticas de seguridad
- Soporte técnico cuando hay problemas
- Documentación y tutoriales incluidos
- Probados en múltiples configuraciones
- Desinstalación limpia si no te convencen
Usa código personalizado cuando
Perfil ideal para código:
- Quieres control absoluto sobre cada funcionalidad
- Necesitas optimización específica para tu caso de uso particular
- Prefieres no depender de desarrolladores externos para cambios
- Quieres evitar costes recurrentes de licencias anuales
- Necesitas funcionalidades muy específicas no disponibles en plugins
- Tienes conocimientos técnicos o acceso a un desarrollador de confianza
- Quieres entender exactamente qué hace cada línea de código
- Necesitas integración profunda con código personalizado existente
Ventajas del código personalizado:
- Control total sobre funcionalidad y rendimiento
- Sin costes recurrentes de licencias
- Código optimizado para tu caso específico
- Sin dependencia de actualizaciones de terceros
- Posibilidad de modificar cualquier aspecto
- Sin conflictos con plugins de terceros
- Código minimalista sin funciones innecesarias
Consideraciones importantes
Antes de elegir plugins:
- Los plugins añaden código que no controlas directamente
- Pueden generar conflictos con otros plugins o temas
- Las actualizaciones pueden cambiar funcionalidades sin previo aviso
- El rendimiento depende completamente de la calidad del desarrollo del plugin
- Algunos plugins pueden introducir vulnerabilidades de seguridad
- Los plugins gratuitos pueden descontinuarse sin aviso
- Los plugins premium requieren renovación anual para actualizaciones
Antes de elegir código personalizado:
- Requiere conocimientos técnicos o presupuesto para desarrollo
- Necesitas mantener y actualizar el código tú mismo
- Sin soporte técnico oficial si algo falla
- Requiere tiempo de desarrollo inicial mayor
- Necesitas documentar tu código para futuras modificaciones
- La responsabilidad de la seguridad es completamente tuya
Combinación recomendada
Para muchos sitios, la mejor solución es una combinación:
- Usa código personalizado para protecciones básicas y críticas
- Complementa con plugins para funcionalidades específicas avanzadas
- Mantén el código personalizado simple y bien documentado
- Usa plugins solo cuando realmente aporten valor significativo
Estrategias por tipo de web

No todas las webs necesitan el mismo nivel de protección. Aquí tienes recomendaciones específicas según tu tipo de sitio.
Blogs y sitios de noticias
Prioridad de protección: Media Enfoque: Proteger contra scraping automático sin afectar la viralidad
Técnicas recomendadas
Protección básica:
- Headers de seguridad (explicado en sección «Protección a nivel servidor»)
- Limitación de feeds RSS (explicado en sección «Protección contra scraping y feeds»)
Protección contra bots:
- Rate limiting moderado por tipo de contenido (explicado en sección «Protección contra scraping y feeds»)
- Detección básica de bots (explicado en sección «Protección a nivel servidor»)
Configurar límites generosos:
- Para feeds: 15-20 accesos por hora en lugar de 10
- Para posts: 40-50 peticiones por 5 minutos en lugar de 30
- Priorizar velocidad sobre protección estricta
Técnicas a evitar
No implementar:
- Deshabilitar selección de texto: Los usuarios necesitan poder seleccionar para compartir citas en redes sociales
- Bloqueo agresivo de clic derecho: Interfiere con la navegación normal (abrir enlaces en pestañas nuevas)
- Overlays transparentes sobre contenido: Dificulta la interacción con artículos
- Marcas de agua en imágenes: Puede afectar la estética informativa y compartibilidad
- Bloqueo de teclas de desarrollador: Algunos usuarios técnicos son lectores legítimos
- Calidad reducida de imágenes: Las imágenes informativas deben verse bien
Por qué este enfoque
Ventajas:
- Mantiene la experiencia de usuario óptima para lectura
- Permite viralidad y compartición del contenido en redes sociales
- Protege contra scraping masivo automatizado sin afectar lectores
- No afecta negativamente al SEO
- Compatible con herramientas de redes sociales y agregadores legítimos
- Velocidad de carga optimizada para noticias de última hora
Desventajas aceptables:
- Protección limitada contra usuarios técnicos determinados
- Contenido textual fácilmente copiable de forma manual
- Las imágenes son fáciles de guardar para usuarios básicos
- Posible uso no autorizado en blogs pequeños
Filosofía: En noticias, la viralidad y el SEO son más valiosos que la protección extrema. Es mejor que te mencionen y enlacen, incluso copiando fragmentos, que perder tráfico por protecciones excesivas.
Porfolios profesionales (fotógrafos, diseñadores, artistas)
Prioridad de protección: Alta Enfoque: Máxima protección visual manteniendo calidad de presentación
Técnicas recomendadas
Protección de imágenes (máxima prioridad):
- Marcas de agua automáticas (explicado en sección «Protección específica de imágenes»)
- Overlays transparentes sobre todas las imágenes (explicado en sección «Protecciones universales»)
- Calidad de imagen reducida para visualización web (explicado en sección «Protección específica de imágenes»)
- Protección de URLs directas contra hotlinking (explicado en sección «Protección específica de imágenes»)
Protección contra interacción:
- Deshabilitar clic derecho completo (explicado en sección «Protecciones universales»)
- Bloquear teclas de desarrollador (explicado en sección «Protecciones universales»)
- Lazy loading con protección contra descarga masiva (explicado en sección «Protección específica de imágenes»)
Protección avanzada:
- Headers de seguridad (explicado en sección «Protección a nivel servidor»)
- Detección avanzada de scrapers (explicado en sección «Protección contra scraping y feeds»)
- Rate limiting estricto para imágenes (explicado en sección «Protección contra scraping y feeds»)
Orden de implementación recomendado
- Primero: Marcas de agua automáticas (protección permanente)
- Segundo: Protección de URLs directas (evitar hotlinking)
- Tercero: Deshabilitar clic derecho y overlays
- Cuarto: Calidad adaptativa de imágenes
- Quinto: Detección de scrapers y rate limiting
Técnicas a evitar
No implementar:
- Nada que deteriore la calidad visual percibida por el visitante
- Protecciones que ralenticen excesivamente la carga inicial de imágenes
- Marcas de agua demasiado intrusivas que arruinen la estética del trabajo
- Bloqueos tan agresivos que impidan a clientes potenciales ver el portfolio
Por qué este enfoque
Ventajas:
- Protección visual máxima contra uso no autorizado
- Disuade efectivamente el uso comercial sin permiso
- Marca visible y constante en todo el contenido
- Protección multicapa difícil de eludir para usuarios no técnicos
- Las marcas de agua también sirven como promoción de marca
Desventajas aceptables:
- Puede afectar ligeramente la experiencia de visualización
- Marcas de agua pueden considerarse intrusivas por algunos visitantes
- Mayor complejidad de implementación y mantenimiento
- Posibles falsos positivos en la detección de scrapers
- Impacto moderado en rendimiento por procesamiento de imágenes
Filosofía: Para portfolios profesionales, las imágenes son el producto. La protección es prioritaria porque el robo de imágenes puede significar pérdida directa de ingresos.
Tiendas online (ecommerce)
Prioridad de protección: Media-Baja Enfoque: Protección mínima que no interfiera con conversiones
Técnicas recomendadas
Protección básica únicamente:
- Headers de seguridad básicos (explicado en sección «Protección a nivel servidor»)
- Rate limiting muy permisivo (explicado en sección «Protección contra scraping y feeds»)
Configurar límites muy generosos:
- Para productos: 100-150 peticiones por 5 minutos
- Para imágenes: 200-300 peticiones por 5 minutos
- Solo bloquear comportamientos extremadamente sospechosos
Técnicas a evitar
No implementar nunca:
- Bloqueo de clic derecho: Los usuarios necesitan abrir productos en pestañas nuevas para comparar
- Marcas de agua en imágenes de productos: Afecta negativamente las conversiones
- Protección agresiva de imágenes: Los clientes necesitan ver bien los productos
- Overlays transparentes: Interfieren con zoom de imágenes y galerías
- Bloqueo de teclas de desarrollador: Usuarios técnicos también compran
- Deshabilitar selección de texto: Impide copiar referencias, códigos de producto, etc.
- Detección estricta de bots: Puede bloquear herramientas legítimas de comparación de precios
- Protección de URLs directas agresiva: Puede afectar compartir en redes sociales
Por qué este enfoque
Ventajas:
- Experiencia de usuario completamente optimizada para conversión
- Velocidad de carga maximizada (crucial para ventas)
- Compatibilidad total con herramientas de comparación de precios
- Sin interferencias con el proceso de checkout
- Permite uso de herramientas de wishlist y comparación
- Facilita compartir productos en redes sociales
- Compatible con aplicaciones móviles de shopping
Desventajas aceptables:
- Protección mínima del contenido visual
- Fácil scraping de información de productos y precios (pero esto también puede ser positivo para comparadores)
- Imágenes fácilmente descargables
- Poca disuasión contra uso no autorizado de imágenes de productos
Filosofía: En ecommerce, cada freno en la experiencia de usuario puede costar ventas. La conversión es infinitamente más valiosa que la protección de imágenes de productos. Los competidores que roben tus imágenes seguirán teniendo que competir en precio, servicio y reputación.
Tabla de recomendaciones por tipo de web
| Web | Prioridad | Técnicas recomendadas principales | Técnicas prohibidas | Métrica principal |
|---|---|---|---|---|
| Blog/Noticias | Media | Headers básicos, feeds limitados, rate limiting suave | Bloqueo selección texto, clic derecho, overlays | SEO y viralidad |
| Portfolio | Alta | Marcas de agua, overlays, protección URLs, calidad reducida, detección avanzada | Nada que afecte calidad visual | Protección visual efectiva |
| Ecommerce | Media-Baja | Solo headers básicos y rate limiting permisivo | Marcas de agua, bloqueo clic derecho, overlays | Tasa de conversión |
Reflexiones finales y buenas prácticas

Después de revisar todas estas técnicas, es importante que tengas una perspectiva realista sobre la protección de contenido web.
Lo que realmente funciona
Protecciones efectivas contra scraping masivo
Más efectivas:
- Rate limiting bien configurado según el tipo de contenido
- Detección de patrones de comportamiento automatizado
- Protección de URLs directas contra hotlinking
- Headers de seguridad del servidor
Por qué funcionan: Estas protecciones están en el lado del servidor y detectan patrones de comportamiento, no intentos puntuales. Los bots automatizados tienen patrones predecibles que se pueden detectar y bloquear.
Protecciones efectivas contra uso comercial
Más efectivas:
- Marcas de agua bien diseñadas y posicionadas
- Calidad de imagen reducida para visualización web
- Información de copyright visible en el contenido
Por qué funcionan: Hacen que el contenido robado sea menos útil comercialmente y mantienen tu marca visible incluso si lo copian.
Protecciones que disuaden usuarios casuales
Efectivas para usuarios básicos:
- Deshabilitar clic derecho
- Bloquear teclas de desarrollador
- Overlays transparentes sobre contenido
- Fragmentación o codificación de texto
Por qué funcionan: La mayoría de usuarios no saben cómo deshabilitar JavaScript o acceder al código fuente de formas alternativas. Estas técnicas detienen al 80% de usuarios casuales.
Lo que NO funciona contra usuarios técnicos
Un usuario con conocimientos técnicos básicos siempre podrá:
Eludir JavaScript:
- Deshabilitar JavaScript completamente desde configuración del navegador
- Usar extensiones que bloquean scripts específicos
- Acceder antes de que se carguen las protecciones
Acceder al código fuente:
- Ver el código fuente con Ctrl+U o desde el menú del navegador
- Usar herramientas de desarrollador accediendo desde el menú
- Inspeccionar elementos específicos directamente
Capturar contenido visual:
- Hacer capturas de pantalla de alta calidad
- Usar herramientas de recorte de pantalla avanzadas
- Grabar la pantalla mientras navegan
Extraer archivos:
- Acceder a archivos desde la cache del navegador
- Usar extensiones específicas para descargar contenido
- Emplear herramientas automatizadas avanzadas con configuraciones anti-detección
Por qué es imposible la protección absoluta
La arquitectura fundamental de la web hace imposible una protección total:
- Todo contenido que se muestra debe descargarse primero al navegador del usuario
- Los navegadores están diseñados para dar control total al usuario final
- Las tecnologías web priorizan la accesibilidad sobre la protección
- Cualquier medida del lado cliente puede ser modificada o deshabilitada por el usuario
Estrategia recomendada por niveles
Nivel 1: Básico (implementar siempre)
Qué implementar:
- Headers de seguridad (sección Protección a nivel servidor)
- Protección básica contra bots conocidos (sección Protección a nivel servidor)
Para qué sirve:
- Protección básica estándar del navegador
- Bloqueo de herramientas de scraping más comunes
- Fundamentos de seguridad web
Tiempo de implementación: 15-30 minutos
Nivel 2: Intermedio (para contenido valioso)
Añadir al nivel básico:
- Rate limiting moderado (sección Protección contra scraping y feeds)
- Protección de URLs directas (sección Protección específica de imágenes)
- Limitación de feeds RSS (sección Protección contra scraping y feeds)
Para qué sirve:
- Protección contra scraping automatizado masivo
- Control del contenido distribuido
- Protección de ancho de banda
Tiempo de implementación: 1-2 horas
Nivel 3: Avanzado (para contenido muy sensible)
Añadir a los niveles anteriores:
- Marcas de agua automáticas (sección Protección específica de imágenes)
- Detección avanzada de scrapers (sección Protección contra scraping y feeds)
- Protección agresiva de imágenes con overlays (secciones Protecciones universales y Protección específica de imágenes)
- Calidad adaptativa de imágenes (sección Protección específica de imágenes)
Para qué sirve:
- Máxima disuasión contra uso comercial no autorizado
- Detección sofisticada de patrones de scraping
- Protección visual multicapa
Tiempo de implementación: 3-5 horas
Guía de implementación gradual
Fundamentos
Implementar:
- Cabeceras de seguridad básicás únicamente
- Protección de directorios
Monitorizar:
- Verificar que no se rompe ninguna funcionalidad
- Comprobar que los headers se aplican correctamente
- Revisar logs en busca de errores
Protección contra bots
Implementar:
- Detección básica de bots conocidos
- Protección de directorios
Monitorizar:
- Revisar logs de bots bloqueados
- Verificar que no se bloquean bots legítimos (Google, Bing)
- Comprobar que usuarios normales no son afectados
Rate limiting
Implementar:
- Rate limiting suave con límites generosos
- Ajustar límites según tu tipo de sitio
Monitorizar:
- Revisar cuántas IPs activan los límites
- Verificar si hay patrones de falsos positivos
- Ajustar límites si es necesario
Protecciones específicas
Implementar:
- Según tu tipo de sitio (blog, portfolio, ecommerce)
- Solo las técnicas recomendadas para tu caso
Monitorizar:
- Métricas de usuario en Google Analytics
- Tasa de rebote y tiempo en página
- Quejas o problemas reportados
Métricas clave a vigilar
En Google Analytics:
- Tiempo de permanencia en página (debería mantenerse estable)
- Tasa de rebote (no debería aumentar significativamente)
- Páginas por sesión (no debería disminuir)
- Conversiones o cumplimiento de objetivos
- Velocidad de carga de página
En logs del servidor:
- Frecuencia de errores 403 y 429
- Patrones de IPs bloqueadas
- Accesos legítimos que puedan estar siendo bloqueados
Feedback directo:
- Comentarios de usuarios sobre dificultades
- Tickets de soporte relacionados con acceso
- Menciones en redes sociales sobre problemas
Señales de que se te ha ido la mano protegiendo
Indicadores claros:
- Aumento del 15% o más en tasa de rebote
- Disminución significativa en tiempo de permanencia
- Quejas de usuarios sobre dificultades de navegación
- Reducción en conversiones o ventas
- Comentarios negativos sobre la experiencia
Qué hacer si detectas problemas:
- Desactivar la última protección implementada
- Monitorizar si el problema se soluciona
- Ajustar parámetros de esa protección
- Reactivar con configuración más permisiva
- Continuar monitorizando
Alternativas a la protección técnica
No descartes la opción, nada descabellada, de optar por alternativas que no pasan por tratar de poner puertas al campo.
Modelos de negocio alternativos
Para contenido valioso:
- Plataformas de membresía con contenido premium detrás de registro
- Diferentes niveles de acceso según suscripción
- Contenido freemium: básico gratis, avanzado de pago
- Marca de agua removible para clientes premium
Para porfolios:
- Versiones de baja resolución en web pública
- Alta resolución solo para clientes registrados
- Galerías privadas con contraseña para cada cliente
- Sistema de vista previa con opción de compra de originales
Para blogs:
- Artículos completos solo para suscriptores
- Contenido exclusivo para miembros
- Acceso temprano a contenido nuevo
- Sindicación controlada solo con partners autorizados
Estrategias de valor añadido
En lugar de solo proteger, añade valor:
- Contenido adicional exclusivo que no se puede robar (comunidad, foros)
- Actualizaciones constantes que hagan obsoleto el contenido robado
- Interacción directa con la audiencia (comentarios, respuestas)
- Herramientas o servicios asociados al contenido
- Rapidez en publicación que haga que seas siempre la fuente original
El futuro de la protección web
Tendencias que afectan la protección
Cambios en navegadores:
- Mayor restricción de técnicas JavaScript invasivas
- Políticas de privacidad más estrictas
- APIs más seguras que limitan técnicas agresivas
- Mayor control del usuario sobre qué se ejecuta
Expectativas de usuarios:
- Menor tolerancia a interferencias en navegación
- Exigencia de experiencias más fluidas y rápidas
- Mayor uso de dispositivos móviles con diferentes limitaciones
- Expectativa de accesibilidad universal
Evolución del scraping:
- Scrapers más sofisticados que imitan comportamiento humano perfectamente
- Uso de navegadores reales automatizados (Puppeteer, Selenium)
- Inteligencia artificial para adaptar comportamiento y eludir detección
- Servicios de scraping comerciales cada vez más avanzados
Adaptarse al futuro
Enfoque estratégico recomendado:
- Priorizar la creación de contenido de calidad que genere una respuesta real
- Construir una comunidad leal alrededor de tu contenido
- Desarrollar una marca fuerte que añada valor más allá del contenido
- Mantener ventaja competitiva en velocidad de publicación
- Ofrecer valor añadido que no se pueda copiar (experiencia, comunidad, servicios)
Adaptación tecnológica:
- Revisar y actualizar protecciones cada 3-6 meses
- Estar al tanto de nuevas técnicas de seguridad web
- Considerar tecnologías emergentes cuando estén maduras
- Mantener el equilibrio entre protección y experiencia de usuario
Conclusión práctica
La protección de contenido web es un equilibrio constante entre seguridad y usabilidad. No existe la protección perfecta, pero una estrategia bien planificada marca la diferencia.
Los 5 principios fundamentales
- Realismo absoluto: Ninguna protección web es infalible. Acepta que las protecciones son disuasorias, no defensas absolutas. Un usuario técnico determinado siempre encontrará la forma.
- Priorización inteligente: No protejas todo por igual. Enfócate en tu contenido más valioso y en lo que realmente importa para tu modelo de negocio.
- Implementación progresiva: Nunca implementes todo de golpe. Ve añadiendo protecciones gradualmente, monitorizando el impacto de cada una.
- Monitorización continua: Los datos son más importantes que las suposiciones. Revisa métricas regularmente y ajusta según resultados reales.
- Análisis coste-beneficio: Pregúntate siempre: ¿el tiempo invertido en protección genera más valor que el posible contenido perdido?
La mejor protección
Al final, la mejor protección no es técnica, es estratégica:
Contenido de calidad
- Crear material original que aporte valor real
- Mantener estándares altos que sean difíciles de replicar
- Actualizar constantemente para mantener relevancia
Audiencia leal
- Construir una comunidad que prefiera consumir en tu plataforma
- Ofrecer experiencias que van más allá del contenido
- Generar confianza y reputación sólida
Marca fuerte
- Desarrollar una identidad que añada valor al contenido
- Hacer que tu marca sea sinónimo de calidad en tu nicho
- Conseguir que copiar tu contenido sin tu marca lo haga menos valioso
Ventaja competitiva
- Ser el primero en publicar (velocidad)
- Ofrecer mayor profundidad (calidad)
- Proporcionar contexto único (experiencia)
Las medidas técnicas explicadas en esta guía son herramientas útiles y necesarias, pero son solo un complemento de una estrategia sólida de contenido, marca y comunidad.
Si tu contenido es realmente valioso, es mejor que la gente lo encuentre en tu web, con tu marca, generando tráfico y beneficios para ti, que copiado en sitios externos sin ningún retorno. Las protecciones técnicas ayudan a ese objetivo, pero no lo garantizan por sí solas.
Recuerda: La protección perfecta no existe, pero una estrategia bien ejecutada, implementada gradualmente y monitorizando constantemente puede marcar una gran diferencia sin sacrificar la experiencia de tus usuarios legítimos.
¿Te gustó este artículo? ¡Ni te imaginas lo que te estás perdiendo en YouTube!







Vamos, seamos sinceros… si alguien de verdad quiere copiarlo, lo hará igual . Pero oye, excelente artículo, todo muy bien explicado y con todos los códigos en un solo sitio, no repartidos por decenas de foros y repos de GitHub
Ya lo dejo claro desde el primer momento, ni hay método infalible, y ni siquiera es recomendable, pero hay gente a la que le sirve, depende del tipo de audiencia y necesidad.