Implemente o SiteMetric em seu Site

Passo 1: Copie o Script

Copie o código JavaScript abaixo e cole no seu site. O script irá automaticamente:

  • Capturar o IP dos visitantes
  • Monitorar tempo de permanência online
  • Registrar dados de visitação permanentemente
  • Atualizar status a cada minuto

Passo 2: Configure seu Site ID

Substitua site_unico_id no script por um identificador único para seu site:

SITE_ID: 'meu_site_exemplo', // Substitua por seu ID único

Passo 3: Cole no seu Site

Cole o script antes do fechamento da tag </body> em todas as páginas que deseja monitorar.

Código do Script:
/**
 * SiteMetric - Script de Monitoramento de Audiência
 * Implemente este script em seu site para começar a monitorar visitantes
 */

(function() {
    'use strict';
    
    const CONFIG = {
        API_URL: 'https://seu-dominio.com/sitemetric/api/',
        CHECK_INTERVAL: 60000,
        SITE_ID: 'site_unico_id',
        COOKIE_NAME: 'sitemetric_session'
    };

    let started = false;

    function normalizeSiteId(value) {
        return String(value || '').trim().replace(/^www\./i, '');
    }

    function normalizeApiBaseUrl(value) {
        let url = String(value || '').trim();
        if (!url) return '';
        if (url.includes('track.php')) {
            url = url.split('track.php')[0];
        }
        if (!url.endsWith('/')) url += '/';
        return url;
    }

    function findCurrentScript() {
        if (document.currentScript) return document.currentScript;
        const scripts = Array.from(document.getElementsByTagName('script'));
        for (let i = scripts.length - 1; i >= 0; i--) {
            const src = scripts[i].getAttribute('src') || '';
            if (src.includes('script.js')) return scripts[i];
        }
        return null;
    }

    function inferApiUrlFromScript() {
        const scriptEl = findCurrentScript();
        const src = scriptEl?.getAttribute('src') || '';
        if (!src) return '';
        try {
            const u = new URL(src, window.location.href);
            const path = u.pathname.replace(/script\.js$/i, '');
            return `${u.origin}${path.endsWith('/') ? path : path + '/'}`;
        } catch {
            return '';
        }
    }

    function isPlaceholderConfig() {
        return (
            !CONFIG.API_URL ||
            CONFIG.API_URL.includes('seu-dominio.com') ||
            !CONFIG.SITE_ID ||
            CONFIG.SITE_ID === 'site_unico_id'
        );
    }

    function applyConfig(options) {
        const opts = options || {};

        const apiBase = normalizeApiBaseUrl(opts.apiUrl || opts.apiBaseUrl || opts.apiURL || opts.api_base_url);
        const siteId = normalizeSiteId(opts.siteId || opts.site_id || opts.domain);
        const checkInterval = Number.isFinite(Number(opts.checkInterval)) ? Number(opts.checkInterval) : null;

        if (apiBase) CONFIG.API_URL = apiBase;
        if (siteId) CONFIG.SITE_ID = siteId;
        if (checkInterval && checkInterval > 0) CONFIG.CHECK_INTERVAL = checkInterval;
    }

    function autoConfigureIfNeeded() {
        if (!isPlaceholderConfig()) return;

        const inferredApi = inferApiUrlFromScript();
        if (inferredApi) CONFIG.API_URL = inferredApi;

        if (!CONFIG.SITE_ID || CONFIG.SITE_ID === 'site_unico_id') {
            CONFIG.SITE_ID = normalizeSiteId(window.location.hostname);
        }
    }
    
    // Função para obter IP do visitante
    async function getVisitorIP() {
        try {
            const response = await fetch('https://api.ipify.org?format=json');
            const data = await response.json();
            return data.ip;
        } catch (error) {
            console.warn('SiteMetric: Não foi possível obter IP externo, usando IP local');
            return generateLocalIP();
        }
    }
    
    // Função para gerar IP local caso não consiga obter o real
    function generateLocalIP() {
        return '192.168.' + Math.floor(Math.random() * 255) + '.' + Math.floor(Math.random() * 255);
    }
    
    // Função para obter dados do visitante
    function getVisitorData() {
        return {
            userAgent: navigator.userAgent,
            language: navigator.language,
            screenResolution: screen.width + 'x' + screen.height,
            timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
            referrer: document.referrer || 'direct',
            currentPage: window.location.href,
            timestamp: new Date().toISOString()
        };
    }
    
    // Função para criar/atualizar cookie de sessão
    function setSessionCookie(sessionId) {
        const expires = new Date();
        expires.setTime(expires.getTime() + (30 * 60 * 1000)); // 30 minutos
        document.cookie = CONFIG.COOKIE_NAME + '=' + sessionId + '; expires=' + expires.toUTCString() + '; path=/';
    }
    
    // Função para obter ID de sessão
    function getSessionId() {
        const cookies = document.cookie.split(';');
        for (let cookie of cookies) {
            const [name, value] = cookie.trim().split('=');
            if (name === CONFIG.COOKIE_NAME) {
                return value;
            }
        }
        return null;
    }
    
    // Função para gerar ID de sessão único
    function generateSessionId() {
        return 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
    }
    
    // Função para obter link de pagamento configurado
    async function getPaymentLink() {
        try {
            const response = await fetch(CONFIG.API_URL + 'pagamentos.php?action=configuracoes');
            const data = await response.json();
            return data.configuracoes?.link_pagamento || '#';
        } catch (error) {
            console.warn('SiteMetric: Não foi possível obter link de pagamento:', error);
            return '#';
        }
    }
    
    // Função para verificar status de pagamento e mostrar aviso se necessário
    async function checkPaymentStatusAndShowWarning() {
        try {
            // Obter domínio atual
            const dominio = window.location.hostname.replace('www.', '');
            
            const response = await fetch(CONFIG.API_URL + 'pagamentos.php?action=verificar_status&dominio=' + dominio);
            const data = await response.json();
            
            if (data && data.status_detalhado) {
                // Obter link de pagamento
                const paymentLink = await getPaymentLink();
                data.link_pagamento = paymentLink;
                showPaymentWarning(data);
            }
            
        } catch (error) {
            console.warn('SiteMetric: Não foi possível verificar status de pagamento:', error);
        }
    }
    
    // Função para mostrar aviso de pagamento discreto
    function showPaymentWarning(paymentData) {
        // Verificar se já existe um aviso
        if (document.getElementById('sitemetric-payment-warning')) {
            return;
        }
        
        const warningDiv = document.createElement('div');
        warningDiv.id = 'sitemetric-payment-warning';
        
        let message = '';
        let className = '';
        
        if (paymentData.status_detalhado === 'vencendo') {
            message = `⚠️ Sua assinatura vence em ${paymentData.dias_ate_vencimento} dia(s). <a href="#" onclick="window.open('${paymentData.link_pagamento || '#'}', '_blank')" style="color: #ff6b35;">Clique aqui para pagar</a>`;
            className = 'sitemetric-warning-vencendo';
        } else if (paymentData.status_detalhado === 'vencido') {
            message = `⚠️ Assinatura vencida há ${paymentData.dias_atraso} dia(s). <a href="#" onclick="window.open('${paymentData.link_pagamento || '#'}', '_blank')" style="color: #ff6b35;">Pague agora para continuar</a>`;
            className = 'sitemetric-warning-vencido';
        }
        
        if (message) {
            warningDiv.className = 'sitemetric-payment-warning ' + className;
            warningDiv.innerHTML = `
                <div class="sitemetric-warning-content">
                    <span class="sitemetric-warning-text">${message}</span>
                    <button class="sitemetric-warning-close" onclick="this.parentElement.parentElement.remove()">&times;</button>
                </div>
            `;
            
            // Adicionar estilos CSS
            const style = document.createElement('style');
            style.textContent = `
                .sitemetric-payment-warning {
                    position: fixed;
                    bottom: 20px;
                    right: 20px;
                    background: #1a1a1a;
                    color: #ffffff;
                    padding: 12px 16px;
                    border-radius: 8px;
                    box-shadow: 0 4px 12px rgba(0,0,0,0.3);
                    border: 1px solid #ff6b35;
                    max-width: 300px;
                    z-index: 9999;
                    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
                    font-size: 14px;
                    line-height: 1.4;
                    animation: slideInRight 0.3s ease-out;
                }
                
                .sitemetric-warning-vencendo {
                    border-color: #ffc107;
                }
                
                .sitemetric-warning-vencido {
                    border-color: #dc3545;
                }
                
                .sitemetric-warning-content {
                    display: flex;
                    align-items: flex-start;
                    gap: 8px;
                }
                
                .sitemetric-warning-text {
                    flex: 1;
                }
                
                .sitemetric-warning-text a {
                    color: #ff6b35;
                    text-decoration: none;
                    font-weight: 500;
                }
                
                .sitemetric-warning-text a:hover {
                    text-decoration: underline;
                }
                
                .sitemetric-warning-close {
                    background: none;
                    border: none;
                    color: #ffffff;
                    font-size: 18px;
                    cursor: pointer;
                    padding: 0;
                    width: 20px;
                    height: 20px;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    opacity: 0.7;
                }
                
                .sitemetric-warning-close:hover {
                    opacity: 1;
                }
                
                @keyframes slideInRight {
                    from {
                        transform: translateX(100%);
                        opacity: 0;
                    }
                    to {
                        transform: translateX(0);
                        opacity: 1;
                    }
                }
                
                @media (max-width: 480px) {
                    .sitemetric-payment-warning {
                        bottom: 10px;
                        right: 10px;
                        left: 10px;
                        max-width: none;
                    }
                }
            `;
            
            document.head.appendChild(style);
            document.body.appendChild(warningDiv);
            
            // Auto-remover após 10 segundos
            setTimeout(() => {
                if (warningDiv.parentElement) {
                    warningDiv.remove();
                }
            }, 10000);
        }
    }
    
    // Função principal para registrar visita
    async function registerVisit() {
        try {
            // Primeiro verificar status de pagamento
            await checkPaymentStatusAndShowWarning();
            
            const ip = await getVisitorIP();
            const visitorData = getVisitorData();
            let sessionId = getSessionId();
            
            if (!sessionId) {
                sessionId = generateSessionId();
                setSessionCookie(sessionId);
            }
            
            const data = {
                siteId: CONFIG.SITE_ID,
                sessionId: sessionId,
                ip: ip,
                visitorData: visitorData,
                timestamp: new Date().toISOString()
            };
            
            // Envia dados para o servidor
            const response = await fetch(CONFIG.API_URL + 'track.php', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(data)
            });
            
            if (!response.ok) {
                throw new Error('Erro ao enviar dados');
            }
            
            console.log('SiteMetric: Visita registrada com sucesso');
            
        } catch (error) {
            console.error('SiteMetric: Erro ao registrar visita:', error);
        }
    }
    
    // Função para manter visitante online
    async function keepAlive() {
        try {
            const sessionId = getSessionId();
            if (!sessionId) return;
            
            const response = await fetch(CONFIG.API_URL + 'keepalive.php', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    siteId: CONFIG.SITE_ID,
                    sessionId: sessionId,
                    timestamp: new Date().toISOString()
                })
            });
            
            if (!response.ok) {
                if (response.status === 404) {
                    await registerVisit();
                    return;
                }
                throw new Error('Erro ao manter sessão ativa');
            }
            
            console.log('SiteMetric: Sessão mantida ativa');
            
        } catch (error) {
            console.error('SiteMetric: Erro ao manter sessão ativa:', error);
        }
    }
    
    // Inicialização
    function startTracking() {
        if (started) return;
        started = true;

        console.log('SiteMetric: Iniciando monitoramento...');
        
        // Registra visita ao carregar a página
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', registerVisit);
        } else {
            registerVisit();
        }
        
        // Mantém sessão ativa a cada intervalo
        setInterval(keepAlive, CONFIG.CHECK_INTERVAL);
        
        // Atualiza atividade em eventos do usuário
        ['click', 'scroll', 'keypress'].forEach(event => {
            document.addEventListener(event, () => {
                clearTimeout(window.sitemetricActivityTimeout);
                window.sitemetricActivityTimeout = setTimeout(keepAlive, 5000);
            });
        });
    }
    
    window.SiteMetric = window.SiteMetric || {};
    window.SiteMetric.init = function(options) {
        applyConfig(options);
        autoConfigureIfNeeded();

        if (isPlaceholderConfig()) {
            console.warn('SiteMetric: Configuração inválida. Defina domain/siteId e apiUrl.');
            return;
        }

        startTracking();
    };

    autoConfigureIfNeeded();
    if (!isPlaceholderConfig()) {
        startTracking();
    }
    
})();
Importante:
  • O script não coleta dados pessoais identificáveis
  • Apenas IPs são armazenados para métricas
  • Os visitantes podem ser banidos se necessário
  • Todos os dados são armazenados localmente em JSON