Cómo crear favicons adaptativos para modos claro y oscuro: Guía completa para desarrolladores

Favicon.im

Los sitios web modernos deben adaptarse a las preferencias del usuario, y la tematización del favicon es un detalle que a menudo se pasa por alto pero que puede mejorar significativamente la experiencia del usuario. Cuando los usuarios alternan entre los modos claro y oscuro, tu favicon debería adaptarse en consecuencia para mantener la coherencia visual.

Esta guía completa cubre todo, desde soluciones simples solo con HTML hasta implementaciones avanzadas con JavaScript en frameworks populares. Ya sea que estés construyendo un sitio estático o una aplicación web compleja, encontrarás el enfoque adecuado para tu proyecto.

Método 1: Solución solo con HTML (Recomendado para la mayoría de sitios)

El enfoque solo con HTML es el método más confiable y no requiere JavaScript. Utiliza media queries de CSS dentro del atributo media de las etiquetas link del favicon para cambiar automáticamente los favicons según la preferencia del sistema del usuario.

Por qué este método funciona mejor:

  • ✅ Cero JavaScript requerido
  • ✅ Funciona inmediatamente al cargar la página
  • ✅ Compatible con todos los navegadores modernos
  • ✅ Sin sobrecarga de rendimiento

Implementación básica

<head>
  <!-- Favicon por defecto (respaldo para navegadores no compatibles) -->
  <link rel="icon" href="/favicon-light.ico" type="image/x-icon">

  <!-- Favicon para modo claro -->
  <link rel="icon" href="/favicon-light.ico" type="image/x-icon" media="(prefers-color-scheme: light)">

  <!-- Favicon para modo oscuro -->
  <link rel="icon" href="/favicon-dark.ico" type="image/x-icon" media="(prefers-color-scheme: dark)">
</head>

Implementación completa con múltiples tamaños

Para soporte integral en todos los dispositivos, implementa múltiples tamaños con variantes de tema:

<head>
  <!-- Favicons por defecto (respaldo) -->
  <link rel="icon" type="image/x-icon" href="/favicon-light.ico">
  <link rel="icon" type="image/png" sizes="32x32" href="/favicon-light-32x32.png">

  <!-- Favicons para modo claro -->
  <link rel="icon" type="image/x-icon" href="/favicon-light.ico" media="(prefers-color-scheme: light)">
  <link rel="icon" type="image/png" sizes="16x16" href="/favicon-light-16x16.png" media="(prefers-color-scheme: light)">
  <link rel="icon" type="image/png" sizes="32x32" href="/favicon-light-32x32.png" media="(prefers-color-scheme: light)">
  <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-light.png" media="(prefers-color-scheme: light)">

  <!-- Favicons para modo oscuro -->
  <link rel="icon" type="image/x-icon" href="/favicon-dark.ico" media="(prefers-color-scheme: dark)">
  <link rel="icon" type="image/png" sizes="16x16" href="/favicon-dark-16x16.png" media="(prefers-color-scheme: dark)">
  <link rel="icon" type="image/png" sizes="32x32" href="/favicon-dark-32x32.png" media="(prefers-color-scheme: dark)">
  <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-dark.png" media="(prefers-color-scheme: dark)">

  <!-- Favicons SVG con CSS embebido -->
  <link rel="icon" type="image/svg+xml" href="/favicon-adaptive.svg">
</head>

Favicon SVG adaptativo

Crea un único favicon SVG que se adapta automáticamente al esquema de colores:

<!-- favicon-adaptive.svg -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
  <style>
    .light-mode { fill: #000000; }
    .dark-mode { fill: #ffffff; }

    @media (prefers-color-scheme: dark) {
      .light-mode { display: none; }
    }

    @media (prefers-color-scheme: light) {
      .dark-mode { display: none; }
    }
  </style>

  <!-- Diseño para modo claro -->
  <circle class="light-mode" cx="16" cy="16" r="12"/>
  <text class="light-mode" x="16" y="20" text-anchor="middle" fill="#fff" font-size="14">L</text>

  <!-- Diseño para modo oscuro -->
  <circle class="dark-mode" cx="16" cy="16" r="12"/>
  <text class="dark-mode" x="16" y="20" text-anchor="middle" fill="#000" font-size="14">D</text>
</svg>

Método 2: Implementación con JavaScript

Cuando necesitas cambio dinámico de favicon más allá de las preferencias del sistema, como controles de tema personalizados o actualizaciones en tiempo real, JavaScript proporciona la flexibilidad que necesitas.

Usa JavaScript cuando:

  • 🎯 Tienes controles de tema personalizados
  • 🎯 Necesitas sincronizar con el estado del tema de tu aplicación
  • 🎯 Quieres actualizar favicons sin recargar la página
  • 🎯 Estás construyendo una aplicación de página única

Enfoque básico con JavaScript

// Función para actualizar el favicon según el tema
function updateFavicon(theme) {
  const favicon = document.querySelector('link[rel="icon"]') ||
                 document.createElement('link');

  favicon.rel = 'icon';
  favicon.type = 'image/png';
  favicon.href = theme === 'dark' ? '/favicon-dark.png' : '/favicon-light.png';

  if (!document.querySelector('link[rel="icon"]')) {
    document.head.appendChild(favicon);
  }
}

// Escuchar cambios en el tema del sistema
if (window.matchMedia) {
  const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');

  // Establecer favicon inicial
  updateFavicon(mediaQuery.matches ? 'dark' : 'light');

  // Escuchar cambios
  mediaQuery.addEventListener('change', (e) => {
    updateFavicon(e.matches ? 'dark' : 'light');
  });
}

JavaScript avanzado con múltiples tamaños

class FaviconManager {
  constructor() {
    this.sizes = [
      { size: '16x16', selector: 'link[rel="icon"][sizes="16x16"]' },
      { size: '32x32', selector: 'link[rel="icon"][sizes="32x32"]' },
      { size: '180x180', selector: 'link[rel="apple-touch-icon"]' }
    ];

    this.init();
  }

  init() {
    // Establecer tema inicial
    this.updateTheme(this.getSystemTheme());

    // Escuchar cambios del sistema
    if (window.matchMedia) {
      const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
      mediaQuery.addEventListener('change', (e) => {
        this.updateTheme(e.matches ? 'dark' : 'light');
      });
    }
  }

  getSystemTheme() {
    return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
      ? 'dark' : 'light';
  }

  updateTheme(theme) {
    this.sizes.forEach(({ size, selector }) => {
      let link = document.querySelector(selector);

      if (!link) {
        link = document.createElement('link');
        link.rel = size === '180x180' ? 'apple-touch-icon' : 'icon';
        link.type = 'image/png';
        if (size !== '180x180') link.sizes = size;
        document.head.appendChild(link);
      }

      link.href = `/favicon-${theme}-${size}.png`;
    });

    // Actualizar archivo ico por defecto
    let icoLink = document.querySelector('link[rel="icon"][type="image/x-icon"]');
    if (!icoLink) {
      icoLink = document.createElement('link');
      icoLink.rel = 'icon';
      icoLink.type = 'image/x-icon';
      document.head.appendChild(icoLink);
    }
    icoLink.href = `/favicon-${theme}.ico`;
  }

  // Método para establecer tema manualmente (para controles de tema personalizados)
  setTheme(theme) {
    this.updateTheme(theme);
  }
}

// Inicializar
const faviconManager = new FaviconManager();

// Exportar para cambio manual de tema
window.faviconManager = faviconManager;

Método 3: Integración con frameworks

Los frameworks modernos ofrecen formas elegantes de manejar la tematización de favicons. Aquí te mostramos cómo implementar favicons adaptativos en los frameworks JavaScript más populares.

Implementación en React

import { useEffect, useState } from 'react';
import { Helmet } from 'react-helmet';

function AdaptiveFavicon() {
  const [theme, setTheme] = useState('light');

  useEffect(() => {
    // Verificar preferencia del sistema
    const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
    setTheme(mediaQuery.matches ? 'dark' : 'light');

    // Escuchar cambios
    const handleChange = (e) => {
      setTheme(e.matches ? 'dark' : 'light');
    };

    mediaQuery.addEventListener('change', handleChange);
    return () => mediaQuery.removeEventListener('change', handleChange);
  }, []);

  return (
    <Helmet>
      <link rel="icon" type="image/x-icon" href={`/favicon-${theme}.ico`} />
      <link rel="icon" type="image/png" sizes="32x32" href={`/favicon-${theme}-32x32.png`} />
      <link rel="apple-touch-icon" sizes="180x180" href={`/apple-touch-icon-${theme}.png`} />
    </Helmet>
  );
}

Implementación en Vue 3

<template>
  <div>
    <!-- El contenido de tu aplicación -->
  </div>
</template>

<script setup>
import { ref, onMounted, watch } from 'vue'
import { useHead } from '@unhead/vue'

const isDark = ref(false)

const updateFavicon = () => {
  const theme = isDark.value ? 'dark' : 'light'

  useHead({
    link: [
      { rel: 'icon', type: 'image/x-icon', href: `/favicon-${theme}.ico` },
      { rel: 'icon', type: 'image/png', sizes: '32x32', href: `/favicon-${theme}-32x32.png` },
      { rel: 'apple-touch-icon', sizes: '180x180', href: `/apple-touch-icon-${theme}.png` }
    ]
  })
}

onMounted(() => {
  // Verificar preferencia del sistema
  if (window.matchMedia) {
    const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
    isDark.value = mediaQuery.matches

    // Escuchar cambios
    mediaQuery.addEventListener('change', (e) => {
      isDark.value = e.matches
    })
  }

  updateFavicon()
})

watch(isDark, updateFavicon)
</script>

Implementación en Nuxt 3

// nuxt.config.ts
export default defineNuxtConfig({
  app: {
    head: {
      script: [
        {
          innerHTML: `
            (function() {
              const updateFavicon = (isDark) => {
                const theme = isDark ? 'dark' : 'light';
                const links = [
                  { rel: 'icon', type: 'image/x-icon', href: \`/favicon-\${theme}.ico\` },
                  { rel: 'icon', type: 'image/png', sizes: '32x32', href: \`/favicon-\${theme}-32x32.png\` }
                ];

                links.forEach(linkData => {
                  let link = document.querySelector(\`link[rel="\${linkData.rel}"][sizes="\${linkData.sizes || 'any'}"]\`);
                  if (!link) {
                    link = document.createElement('link');
                    Object.assign(link, linkData);
                    document.head.appendChild(link);
                  } else {
                    link.href = linkData.href;
                  }
                });
              };

              if (window.matchMedia) {
                const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
                updateFavicon(mediaQuery.matches);
                mediaQuery.addEventListener('change', e => updateFavicon(e.matches));
              }
            })();
          `
        }
      ]
    }
  }
})

Método 4: Favicon con CSS-in-JS (Avanzado)

Genera favicons dinámicamente usando Canvas y colores CSS:

class DynamicFaviconGenerator {
  constructor() {
    this.canvas = document.createElement('canvas');
    this.ctx = this.canvas.getContext('2d');
    this.canvas.width = 32;
    this.canvas.height = 32;
  }

  generateFavicon(theme) {
    const colors = {
      light: { bg: '#ffffff', text: '#000000' },
      dark: { bg: '#000000', text: '#ffffff' }
    };

    const { bg, text } = colors[theme];

    // Limpiar canvas
    this.ctx.clearRect(0, 0, 32, 32);

    // Dibujar fondo
    this.ctx.fillStyle = bg;
    this.ctx.fillRect(0, 0, 32, 32);

    // Dibujar borde
    this.ctx.strokeStyle = text;
    this.ctx.lineWidth = 2;
    this.ctx.strokeRect(2, 2, 28, 28);

    // Dibujar icono (ejemplo: letra o símbolo)
    this.ctx.fillStyle = text;
    this.ctx.font = 'bold 20px Arial';
    this.ctx.textAlign = 'center';
    this.ctx.textBaseline = 'middle';
    this.ctx.fillText('🌙', 16, 16);

    return this.canvas.toDataURL('image/png');
  }

  updateFavicon(theme) {
    const dataUrl = this.generateFavicon(theme);

    let link = document.querySelector('link[rel="icon"]');
    if (!link) {
      link = document.createElement('link');
      link.rel = 'icon';
      link.type = 'image/png';
      document.head.appendChild(link);
    }

    link.href = dataUrl;
  }
}

// Uso
const generator = new DynamicFaviconGenerator();
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');

generator.updateFavicon(mediaQuery.matches ? 'dark' : 'light');
mediaQuery.addEventListener('change', e => {
  generator.updateFavicon(e.matches ? 'dark' : 'light');
});

Mejores prácticas de diseño

Crear favicons adaptativos efectivos requiere atención cuidadosa a los principios de diseño y la experiencia del usuario.

Contraste de color y visibilidad

Diseño del favicon para modo claro:

  • ✅ Usa elementos oscuros (texto, iconos) sobre fondos transparentes o claros
  • ✅ Apunta a ratios de contraste WCAG AA (mínimo 4.5:1)
  • ✅ Prueba la apariencia en pestañas blancas del navegador y barras de marcadores
  • ✅ Asegura la claridad a 16x16 píxeles (el tamaño común más pequeño)

Diseño del favicon para modo oscuro:

  • ✅ Usa elementos claros sobre fondos transparentes u oscuros
  • ✅ Prueba la visibilidad contra temas oscuros del navegador
  • ✅ Evita el blanco puro (#ffffff) - usa un blanco apagado (#f0f0f0) para mejor equilibrio
  • ✅ Considera sombras sutiles o contornos para definición

Consejos de consistencia de diseño

  1. Mantén el reconocimiento de marca - Mantén consistentes tus elementos de diseño principales
  2. Prueba en múltiples tamaños - 16x16, 32x32 y 180x180 píxeles
  3. Usa formas simples - Los detalles complejos desaparecen en tamaños pequeños
  4. Considera usuarios daltónicos - No dependas únicamente del color para la diferenciación

Convención de nomenclatura de archivos

Organiza tus archivos de favicon con nombres claros:

/public/
├── favicon-light.ico
├── favicon-dark.ico
├── favicon-light-16x16.png
├── favicon-dark-16x16.png
├── favicon-light-32x32.png
├── favicon-dark-32x32.png
├── apple-touch-icon-light.png
├── apple-touch-icon-dark.png
└── favicon-adaptive.svg

Compatibilidad de navegadores

Soporte de navegadores modernos para favicons adaptativos

Navegador Soporte de Media Query Notas
Chrome 76+ ✅ Soporte completo Funciona perfectamente
Firefox 67+ ✅ Soporte completo Excelente implementación
Safari 12.1+ ✅ Soporte completo iOS Safari incluido
Edge 79+ ✅ Soporte completo Edge basado en Chromium
Internet Explorer ❌ Sin soporte Usa respaldo con JavaScript

Cobertura de mercado: Estas versiones cubren ~95% del uso global de navegadores a partir de 2025.

Estrategia de respaldo

<!-- Siempre proporciona respaldos -->
<link rel="icon" href="/favicon-light.ico" type="image/x-icon">

<!-- Soporte mejorado para navegadores modernos -->
<link rel="icon" href="/favicon-light.ico" type="image/x-icon" media="(prefers-color-scheme: light)">
<link rel="icon" href="/favicon-dark.ico" type="image/x-icon" media="(prefers-color-scheme: dark)">

<!-- Respaldo con JavaScript para navegadores antiguos -->
<script>
  if (!window.matchMedia || !CSS.supports('(prefers-color-scheme: dark)')) {
    // Cargar favicon basado en la hora del día u otras heurísticas
    const hour = new Date().getHours();
    const isDark = hour < 6 || hour > 18;
    document.querySelector('link[rel="icon"]').href =
      isDark ? '/favicon-dark.ico' : '/favicon-light.ico';
  }
</script>

Pruebas y validación

Lista de verificación de pruebas manuales

  • [ ] Probar en modo claro (preferencia del sistema)
  • [ ] Probar en modo oscuro (preferencia del sistema)
  • [ ] Verificar que el favicon cambia inmediatamente al cambiar el tema del sistema
  • [ ] Probar en diferentes navegadores (Chrome, Firefox, Safari, Edge)
  • [ ] Probar en dispositivos móviles
  • [ ] Validar comportamiento de respaldo en navegadores antiguos

Pruebas automatizadas

// Script de prueba para cambio de tema de favicon
function testFaviconThemes() {
  const tests = [
    { theme: 'light', expected: '/favicon-light.ico' },
    { theme: 'dark', expected: '/favicon-dark.ico' }
  ];

  tests.forEach(({ theme, expected }) => {
    // Simular media query
    Object.defineProperty(window, 'matchMedia', {
      writable: true,
      value: jest.fn().mockImplementation(query => ({
        matches: query.includes('dark') ? theme === 'dark' : theme === 'light',
        addEventListener: jest.fn(),
        removeEventListener: jest.fn(),
      })),
    });

    // Activar actualización
    updateFavicon(theme);

    // Verificar
    const favicon = document.querySelector('link[rel="icon"]');
    expect(favicon.href).toContain(expected);
  });
}

Optimización del rendimiento

Precargar favicons de tema

<!-- Precargar ambos favicons de tema para cambio instantáneo -->
<link rel="preload" as="image" href="/favicon-light.ico">
<link rel="preload" as="image" href="/favicon-dark.ico">

Minimizar tamaños de archivo

  • Mantén los archivos ICO por debajo de 1KB
  • Optimiza archivos PNG con herramientas como TinyPNG
  • Usa SVG para diseños geométricos simples
  • Considera el formato WebP para navegadores modernos

Estrategia de caché

# Configuración de Nginx para caché de favicon
location ~* \.(ico|png|svg)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
    add_header Vary "Accept-Encoding";
}

Solución de problemas comunes

El favicon no cambia entre temas

Síntomas: El favicon permanece igual sin importar los cambios de tema del sistema

Causas comunes y soluciones:

  1. Problemas de caché del navegador

    <!-- Añadir parámetros para invalidar caché -->
    <link rel="icon" href="/favicon-light.ico?v=2025" media="(prefers-color-scheme: light)">
    <link rel="icon" href="/favicon-dark.ico?v=2025" media="(prefers-color-scheme: dark)">
    
  2. Sintaxis incorrecta de Media Query

    <!-- ❌ Incorrecto -->
    <link rel="icon" href="/favicon-dark.ico" media="dark">
    
    <!-- ✅ Correcto -->
    <link rel="icon" href="/favicon-dark.ico" media="(prefers-color-scheme: dark)">
    

Múltiples favicons cargando simultáneamente

Síntomas: La pestaña de red muestra múltiples solicitudes de favicon

Solución: Usa JavaScript para reemplazar en lugar de añadir:

function replaceFavicon(href) {
  // Eliminar todos los enlaces de favicon existentes
  document.querySelectorAll('link[rel*="icon"]').forEach(link => link.remove());

  // Añadir nuevo favicon
  const link = document.createElement('link');
  link.rel = 'icon';
  link.type = 'image/x-icon';
  link.href = href;
  document.head.appendChild(link);
}

Los favicons SVG no se muestran

Síntomas: El favicon SVG funciona en algunos navegadores pero no en otros

Causa raíz: Soporte limitado de favicons SVG en navegadores antiguos

Solución: Siempre proporciona respaldos PNG:

<!-- Navegadores modernos: SVG con media queries -->
<link rel="icon" type="image/svg+xml" href="/favicon-adaptive.svg">

<!-- Respaldo: PNG para navegadores antiguos -->
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-light-32x32.png" media="(prefers-color-scheme: light)">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-dark-32x32.png" media="(prefers-color-scheme: dark)">

Técnicas avanzadas

Insignias de notificación adaptativas al tema

class NotificationFavicon {
  constructor() {
    this.canvas = document.createElement('canvas');
    this.ctx = this.canvas.getContext('2d');
    this.canvas.width = 32;
    this.canvas.height = 32;
    this.baseIcons = {
      light: '/favicon-light-32x32.png',
      dark: '/favicon-dark-32x32.png'
    };
  }

  async drawWithBadge(theme, count) {
    const baseIcon = new Image();
    baseIcon.src = this.baseIcons[theme];

    return new Promise(resolve => {
      baseIcon.onload = () => {
        this.ctx.clearRect(0, 0, 32, 32);
        this.ctx.drawImage(baseIcon, 0, 0, 32, 32);

        if (count > 0) {
          // Dibujar insignia de notificación
          const badgeSize = 12;
          const x = 32 - badgeSize;
          const y = 0;

          // Fondo de la insignia
          this.ctx.fillStyle = '#ff4444';
          this.ctx.beginPath();
          this.ctx.arc(x + badgeSize/2, y + badgeSize/2, badgeSize/2, 0, 2 * Math.PI);
          this.ctx.fill();

          // Texto de la insignia
          this.ctx.fillStyle = 'white';
          this.ctx.font = '8px Arial';
          this.ctx.textAlign = 'center';
          this.ctx.textBaseline = 'middle';
          this.ctx.fillText(
            count > 9 ? '9+' : count.toString(),
            x + badgeSize/2,
            y + badgeSize/2
          );
        }

        resolve(this.canvas.toDataURL());
      };
    });
  }

  async updateWithNotification(count = 0) {
    const theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
    const dataUrl = await this.drawWithBadge(theme, count);

    let link = document.querySelector('link[rel="icon"]');
    if (!link) {
      link = document.createElement('link');
      link.rel = 'icon';
      document.head.appendChild(link);
    }
    link.href = dataUrl;
  }
}

// Uso
const notificationFavicon = new NotificationFavicon();
notificationFavicon.updateWithNotification(3); // Mostrar insignia con cuenta 3

Resumen y próximos pasos

Los favicons adaptativos representan una forma pequeña pero impactante de mejorar la experiencia del usuario. Demuestran atención al detalle y respeto por las preferencias del usuario, contribuyendo a un sitio web más pulido y profesional.

Elige el método adecuado para tu proyecto

Método Mejor para Complejidad Rendimiento
Solo HTML Sitios estáticos, blogs, páginas de marketing Baja Excelente
JavaScript SPAs, temas personalizados, actualizaciones dinámicas Media Bueno
Integración con frameworks Aplicaciones React/Vue/Nuxt Media Bueno
Técnicas avanzadas Sistemas de notificación, actualizaciones en tiempo real Alta Variable

Lista de verificación de implementación

Antes de desplegar tu sistema de favicon adaptativo:

  • [ ] Crear ambas versiones de favicon claro y oscuro
  • [ ] Probar en múltiples navegadores (Chrome, Firefox, Safari, Edge)
  • [ ] Verificar que el cambio funciona con los cambios de tema del sistema
  • [ ] Probar en dispositivos móviles (iOS Safari, Android Chrome)
  • [ ] Optimizar tamaños de archivo (mantener por debajo de 1KB para archivos ICO)
  • [ ] Añadir respaldos apropiados para navegadores antiguos
  • [ ] Validar la implementación con herramientas como Favicon.im

Impacto en el rendimiento

Cuando se implementa correctamente, los favicons adaptativos tienen un impacto mínimo en el rendimiento:

  • Método solo HTML: Cero sobrecarga de JavaScript
  • Impacto en tamaño de archivo: ~2-4KB total (versiones claro + oscuro)
  • Tiempo de carga: Insignificante cuando se cachea correctamente

Ir más allá

Considera estas optimizaciones avanzadas:

  • Precargar activos de favicon críticos para cambio instantáneo
  • Usar formato WebP para navegadores modernos (con respaldos PNG)
  • Implementar insignias de favicon dinámicas para notificaciones
  • Añadir animaciones de favicon para eventos especiales o estados

Al implementar favicons adaptativos de manera reflexiva, creas una experiencia web más cohesiva y amigable que se adapta a las preferencias modernas del usuario.

Check Your Favicon

Use favicon.im to quickly check if your favicon is configured correctly. Our free tool ensures your website's favicon displays properly across all browsers and devices.

Free Public Service

Favicon.im is a completely free public service trusted by developers worldwide.

15M+
Monthly Favicon Requests
100%
Free Forever