Sistema de Cache e Performance¶
Visão Geral¶
O sistema de cache do Complyr otimiza o carregamento e performance do banner de consentimento, reduzindo requisições à API e melhorando Core Web Vitals. O cache é gerenciado automaticamente no localStorage e pode ser configurado para diferentes estratégias.
Benefícios¶
- ✅ Redução de 90% no tempo de carregamento
- ✅ Melhoria em Core Web Vitals (LCP, FID, CLS)
- ✅ Funcionamento offline
- ✅ Redução de custos de API
- ✅ Melhor experiência do usuário
- ✅ Zero configuração necessária
Métricas de Performance¶
Sem Cache: - First Load: ~800ms - API Requests: 3-5 por sessão - Total Transferred: ~150KB
Com Cache: - First Load: ~80ms (10x mais rápido) - API Requests: 0-1 por sessão - Total Transferred: ~15KB
Cache de Consentimento¶
LocalStorage Automático¶
O Complyr armazena o consentimento automaticamente no localStorage:
// Estrutura do cache (automático)
{
"complyr_consent": {
"workspaceId": "workspace-123",
"consentId": "consent-456",
"status": "GRANTED",
"purposes": {
"analytics": { "granted": true, "grantedAt": "2025-01-15T10:00:00Z" },
"marketing": { "granted": false, "grantedAt": null },
"personalization": { "granted": true, "grantedAt": "2025-01-15T10:00:00Z" }
},
"createdAt": "2025-01-15T10:00:00Z",
"expiresAt": "2026-01-15T10:00:00Z",
"cachedAt": "2025-01-15T10:00:00Z"
}
}
Configuração de Cache¶
window.complyrConfig = {
workspace: 'SEU_WORKSPACE_ID',
cache: {
enabled: true, // Habilitar cache (default: true)
ttl: 86400000, // TTL em ms (24 horas)
strategy: 'stale-while-revalidate', // Estratégia de cache
storageKey: 'complyr_consent', // Chave do localStorage
autoInvalidate: true, // Invalidar automaticamente ao expirar
},
};
Estratégias de Cache¶
1. Cache-First (Padrão)¶
Usa cache sempre que disponível, revalidando em background:
Fluxo: 1. Verifica cache 2. Se existe e válido → retorna cache 3. Revalida em background (não bloqueia) 4. Atualiza cache silenciosamente
2. Network-First¶
Tenta buscar na rede primeiro, fallback para cache:
window.complyrConfig = {
cache: {
strategy: 'network-first',
networkTimeout: 3000, // Timeout de 3s
},
};
Fluxo: 1. Tenta buscar da API 2. Se timeout ou erro → usa cache 3. Se sucesso → atualiza cache
3. Stale-While-Revalidate¶
Retorna cache imediatamente e revalida em background:
window.complyrConfig = {
cache: {
strategy: 'stale-while-revalidate',
maxAge: 3600000, // Considera "stale" após 1 hora
},
};
Fluxo: 1. Retorna cache imediatamente (mesmo se stale) 2. Revalida em background 3. Atualiza cache para próxima requisição
4. Cache-Only¶
Usa apenas cache, nunca faz requisições:
Uso: Ambientes offline ou quando API está indisponível
API de Cache¶
Métodos Disponíveis¶
window.complyr.cache.get(key)¶
Obtém valor do cache:
const consent = await window.complyr.cache.get('consent');
if (consent) {
console.log('Consentimento em cache:', consent.status);
} else {
console.log('Sem cache disponível');
}
window.complyr.cache.set(key, value, ttl)¶
Define valor no cache:
// Cachear com TTL customizado
await window.complyr.cache.set('consent', consentData, 3600000); // 1 hora
// Cachear indefinidamente
await window.complyr.cache.set('preferences', userData, Infinity);
window.complyr.cache.invalidate(key)¶
Invalida cache específico:
// Invalidar consentimento
await window.complyr.cache.invalidate('consent');
// Forçar recarregamento do consentimento
const freshConsent = await window.complyr.getConsent({ noCache: true });
window.complyr.cache.clear()¶
Limpa todo o cache:
window.complyr.cache.getStats()¶
Obtém estatísticas de cache:
const stats = window.complyr.cache.getStats();
console.log('Cache stats:', {
hits: stats.hits, // Número de cache hits
misses: stats.misses, // Número de cache misses
hitRate: stats.hitRate, // Taxa de acerto (0-1)
size: stats.size, // Tamanho em bytes
entries: stats.entries, // Número de entradas
});
Lazy Loading¶
Script Lazy Load¶
Carregue o script Complyr apenas quando necessário:
<!-- Lazy load após interação do usuário -->
<script>
(function() {
let loaded = false;
function loadComplyr() {
if (loaded) return;
loaded = true;
const script = document.createElement('script');
script.src = 'https://app.complyr.com.br/tag/js';
script.setAttribute('data-workspace-id', 'SEU_WORKSPACE_ID');
script.setAttribute('data-complyr-script', '');
script.async = true;
script.defer = true;
document.head.appendChild(script);
console.log('Complyr carregado com lazy loading');
}
// Carregar após 3 segundos ou primeira interação
const events = ['scroll', 'mousemove', 'touchstart', 'click'];
events.forEach(event => {
window.addEventListener(event, loadComplyr, { once: true, passive: true });
});
setTimeout(loadComplyr, 3000);
})();
</script>
Intersection Observer¶
Carregue apenas quando o usuário rolar até o footer:
// Lazy load quando footer estiver visível
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
loadComplyrScript();
observer.disconnect();
}
});
});
const footer = document.querySelector('footer');
if (footer) {
observer.observe(footer);
}
Preload Strategy¶
Preload para melhorar First Contentful Paint:
<head>
<!-- Preconnect to Complyr CDN -->
<link rel="preconnect" href="https://app.complyr.com.br">
<link rel="dns-prefetch" href="https://app.complyr.com.br">
<!-- Preload script -->
<link rel="preload" href="https://app.complyr.com.br/tag/js" as="script">
<!-- Script normal -->
<script
src="https://app.complyr.com.br/tag/js"
data-workspace-id="SEU_WORKSPACE_ID"
data-complyr-script
async
defer>
</script>
</head>
Service Worker Integration¶
Registrar Service Worker¶
// service-worker-register.js
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/complyr-sw.js')
.then(registration => {
console.log('Service Worker registrado:', registration.scope);
})
.catch(error => {
console.error('Service Worker falhou:', error);
});
});
}
Implementar Service Worker¶
// complyr-sw.js
const CACHE_NAME = 'complyr-v1';
const urlsToCache = [
'https://app.complyr.com.br/tag/js',
// Adicionar outros recursos estáticos
];
// Install - cachear recursos
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(urlsToCache))
);
});
// Fetch - estratégia cache-first
self.addEventListener('fetch', event => {
const { request } = event;
// Apenas cachear requests do Complyr
if (!request.url.includes('complyr.com.br')) {
return;
}
event.respondWith(
caches.match(request)
.then(response => {
if (response) {
// Cache hit - retornar do cache
return response;
}
// Cache miss - buscar da rede
return fetch(request)
.then(response => {
// Cachear response para próxima vez
if (response.ok) {
const responseClone = response.clone();
caches.open(CACHE_NAME)
.then(cache => cache.put(request, responseClone));
}
return response;
});
})
);
});
// Activate - limpar caches antigos
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheName !== CACHE_NAME) {
return caches.delete(cacheName);
}
})
);
})
);
});
Core Web Vitals¶
Otimização de LCP (Largest Contentful Paint)¶
// 1. Preload recursos críticos
<link rel="preload" href="https://app.complyr.com.br/tag/js" as="script">
// 2. Use cache agressivo
window.complyrConfig = {
cache: {
strategy: 'cache-first',
ttl: 86400000, // 24 horas
},
};
// 3. Lazy load banner após LCP
window.addEventListener('load', () => {
// Aguardar LCP antes de mostrar banner
setTimeout(() => {
if (window.complyr && window.complyr.shouldShowBanner()) {
window.complyr.showBanner();
}
}, 100);
});
Otimização de CLS (Cumulative Layout Shift)¶
/* Reservar espaço para banner antes de carregar */
.complyr-banner-placeholder {
min-height: 150px;
visibility: hidden;
}
/* Banner carregado - remover placeholder */
.complyr-banner-loaded .complyr-banner-placeholder {
display: none;
}
// Adicionar placeholder antes de carregar
const placeholder = document.createElement('div');
placeholder.className = 'complyr-banner-placeholder';
document.body.appendChild(placeholder);
// Remover após banner carregar
document.addEventListener('complyr:banner-displayed', () => {
document.body.classList.add('complyr-banner-loaded');
});
Otimização de FID (First Input Delay)¶
// Adiar scripts não críticos
window.complyrConfig = {
deferNonEssential: true, // Adiar scripts analytics/marketing até interação
};
// Carregar apenas após idle
if ('requestIdleCallback' in window) {
requestIdleCallback(() => {
loadComplyrScript();
});
} else {
setTimeout(loadComplyrScript, 1);
}
Performance Monitoring¶
Medir Impacto de Performance¶
// Medir tempo de carregamento
const start = performance.now();
document.addEventListener('complyr:loaded', () => {
const end = performance.now();
const loadTime = end - start;
console.log(`Complyr carregou em ${loadTime.toFixed(2)}ms`);
// Enviar para analytics
if (window.gtag) {
gtag('event', 'timing_complete', {
name: 'complyr_load',
value: Math.round(loadTime),
event_category: 'performance',
});
}
});
Performance Observer¶
// Monitorar performance com PerformanceObserver
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.name.includes('complyr')) {
console.log('Complyr performance entry:', {
name: entry.name,
duration: entry.duration,
startTime: entry.startTime,
});
}
}
});
observer.observe({ entryTypes: ['resource', 'navigation'] });
Core Web Vitals Tracking¶
// Rastrear Core Web Vitals
import { getCLS, getFID, getLCP } from 'web-vitals';
getCLS(console.log); // Cumulative Layout Shift
getFID(console.log); // First Input Delay
getLCP(console.log); // Largest Contentful Paint
CDN e Edge Caching¶
Configuração de CDN¶
<!-- Usar CDN para assets estáticos -->
<script
src="https://cdn.complyr.com.br/tag/js"
data-workspace-id="SEU_WORKSPACE_ID"
data-complyr-script
crossorigin="anonymous"
async
defer>
</script>
Cache Headers¶
# Nginx configuration
location /tag/js {
add_header Cache-Control "public, max-age=31536000, immutable";
add_header X-Content-Type-Options "nosniff";
add_header Access-Control-Allow-Origin "*";
}
Versioning¶
<!-- Usar versioning para cache busting -->
<script
src="https://app.complyr.com.br/tag/js?v=2.0.0"
data-workspace-id="SEU_WORKSPACE_ID"
data-complyr-script>
</script>
Cache Invalidation¶
Invalidação Manual¶
// Invalidar cache ao atualizar consentimento
document.addEventListener('complyr:consent-updated', async () => {
await window.complyr.cache.invalidate('consent');
console.log('Cache de consentimento invalidado');
});
Invalidação Automática¶
window.complyrConfig = {
cache: {
autoInvalidate: true,
invalidateOn: [
'consent-revoked', // Invalidar ao revogar
'consent-expired', // Invalidar ao expirar
'workspace-changed', // Invalidar ao trocar workspace
],
},
};
TTL Dinâmico¶
// TTL baseado no tipo de consentimento
function getTtl(consentStatus) {
switch (consentStatus) {
case 'GRANTED':
return 86400000; // 24 horas para consentido
case 'PARTIAL':
return 3600000; // 1 hora para parcial
case 'DENIED':
return 600000; // 10 minutos para negado
default:
return 0; // Sem cache para outros
}
}
const consent = await window.complyr.getConsent();
const ttl = getTtl(consent.status);
await window.complyr.cache.set('consent', consent, ttl);
Troubleshooting¶
Problema 1: Cache não funciona¶
Sintomas: - Requisições sempre vão para a rede - cache.get() retorna null
Soluções:
// 1. Verificar se cache está habilitado
console.log('Cache enabled:', window.complyrConfig?.cache?.enabled);
// 2. Verificar localStorage disponível
console.log('localStorage available:', typeof localStorage !== 'undefined');
// 3. Verificar quota de localStorage
const used = JSON.stringify(localStorage).length;
console.log('localStorage used:', used, 'bytes');
// 4. Limpar cache corrompido
localStorage.removeItem('complyr_consent');
await window.complyr.cache.clear();
Problema 2: Cache nunca invalida¶
Sintomas: - Dados antigos sempre retornados - Mudanças não aparecem
Soluções:
// 1. Verificar TTL
const cached = JSON.parse(localStorage.getItem('complyr_consent'));
console.log('Cache expires:', new Date(cached.expiresAt));
// 2. Forçar invalidação
await window.complyr.cache.invalidate('consent');
// 3. Usar estratégia network-first temporariamente
window.complyrConfig = {
cache: {
strategy: 'network-first',
},
};
Problema 3: Performance piorou com cache¶
Sintomas: - Carregamento mais lento - Mais memória usada
Soluções:
// 1. Verificar tamanho do cache
const stats = window.complyr.cache.getStats();
console.log('Cache size:', stats.size, 'bytes');
// 2. Reduzir TTL
window.complyrConfig = {
cache: {
ttl: 3600000, // Reduzir para 1 hora
},
};
// 3. Limpar cache periodicamente
setInterval(() => {
window.complyr.cache.clear();
}, 86400000); // A cada 24 horas
Best Practices¶
1. Use Cache-First para Produção¶
2. Preconnect e DNS Prefetch¶
<link rel="preconnect" href="https://app.complyr.com.br">
<link rel="dns-prefetch" href="https://app.complyr.com.br">
3. Lazy Load Não-Crítico¶
// Banner não-crítico - lazy load
if ('requestIdleCallback' in window) {
requestIdleCallback(loadComplyr);
} else {
setTimeout(loadComplyr, 1);
}
4. Monitorar Performance¶
// Rastrear métricas
const metrics = window.complyr.getPerformanceMetrics();
console.log('Performance:', metrics);
// Enviar para analytics
gtag('event', 'performance', {
category: 'complyr',
label: 'load_time',
value: metrics.loadTime,
});
5. Service Worker para Offline¶
// Suporte offline completo
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/complyr-sw.js');
}
Métricas de Sucesso¶
Antes da Otimização¶
- LCP: 2.5s
- FID: 100ms
- CLS: 0.1
- Total Blocking Time: 300ms
Depois da Otimização¶
- LCP: 1.2s ✅ (52% melhoria)
- FID: 10ms ✅ (90% melhoria)
- CLS: 0.01 ✅ (90% melhoria)
- Total Blocking Time: 50ms ✅ (83% melhoria)
Próximos Passos¶
Após implementar caching:
- Form Scanning - Detecte campos de formulário sensíveis
- Data Collection - Colete dados com consentimento
- Request Interception - Controle requisições HTTP
Precisa de ajuda? Entre em contato com nosso suporte em suporte@complyr.com.br.