Use efficient cache lifetimes no Lighthouse: como corrigir
O Lighthouse 13 lista todos os ficheiros que os browsers dos visitantes podem reutilizar durante menos de 30 dias. O que isso custa na página seguinte e na visita de retorno, e o fix por servidor e plataforma.
O "Use efficient cache lifetimes" prejudica a pontuação do Lighthouse?
O Lighthouse assinala todos os ficheiros estáticos com uma duração de cache inferior a 30 dias no insight Use efficient cache lifetimes ("Uma duração de cache longa pode acelerar as visitas repetidas à sua página"), chamado "Serve static assets with an efficient cache policy" antes do Lighthouse 13 e "Leverage browser caching" no PageSpeed Insights mais antigo. Não conta para a pontuação e não a afeta: o Lighthouse carrega sempre com a cache vazia. Configure durações mais longas no servidor, na CDN ou no plugin de cache.
Table of Contents!
O que significa Use efficient cache lifetimes no Lighthouse?
A descrição do Lighthouse diz: "Uma duração de cache longa pode acelerar as visitas repetidas à sua página. Saiba mais sobre a cache."
O Lighthouse lista todos os scripts, folhas de estilo, tipos de letra, imagens, ficheiros de vídeo e de áudio com uma duração de cache inferior a 30 dias, ou sem qualquer duração definida. A duração corresponde ao max-age no header Cache-Control do ficheiro, ou então ao tempo restante até à data do cabeçalho Expires. Os ficheiros de outros domínios são listados da mesma forma que os seus.
O Lighthouse ignora ficheiros cujo Cache-Control indique no-cache, no-store, private ou must-revalidate, qualquer que seja o max-age: interpreta essas diretivas como uma opção deliberada de não colocar em cache. Também ignora ficheiros com max-age=0 e nunca lista a própria página HTML.

Uma página que carrega o Google Tag Manager, o GA4 e o Meta Pixel. A Google envia as suas tags como private, pelo que, das três, apenas o Meta Pixel é listado. Lighthouse 13.5.0, throttling simulado como no PageSpeed Insights.
Como funciona a cache do browser?
O browser guarda o ficheiro juntamente com a respetiva duração. Na página seguinte ou na visita seguinte, consulta primeiro a cópia guardada:
- Dentro da duração: o browser utiliza a cópia local e não envia qualquer request. É o único caso em que não há espera pelo servidor.
- Duração expirada: o browser pergunta ao servidor se o ficheiro foi alterado, utilizando o ETag ou a data Last-Modified que recebeu com o ficheiro. Se não tiver mudado, o servidor responde com 304 Not Modified, sem o ficheiro. Isto poupa o download, mas cada ficheiro continua a custar um round trip ao servidor, e a página não consegue fazer paint até o servidor ter respondido a todas as folhas de estilo.
- Duração expirada e sem ETag ou Last-Modified: o browser descarrega o ficheiro novamente.
| Header no ficheiro | Visualização seguinte no Chrome |
|---|---|
max-age=31536000 | Da cache durante um ano |
max-age=14400 | Da cache durante 4 horas, depois um 304 |
no-cache | Sempre um 304 |
no-store | Descarregado sempre |
Um recarregamento normal no Chrome não volta a verificar ficheiros que ainda estão dentro da duração. O Firefox e o Safari voltam a verificar, a menos que o ficheiro tenha immutable no Cache-Control.
Desde o Chrome 86 que cada site tem a sua própria cache. Um tipo de letra ou um ficheiro jQuery que o visitante já tenha descarregado noutro site é descarregado novamente no seu, mesmo a partir do mesmo URL. Portanto, a duração definida por terceiros só ajuda no seu próprio site, na página seguinte e na visita de retorno; e "já toda a gente tem isto em cache" deixou de ser motivo para carregar tipos de letra da Google (aloje-os localmente).
A cache do browser e a cache da CDN são coisas distintas, tal como a cache de página de um plugin de cache do WordPress. Uma CDN ou uma cache de página guarda uma cópia para que o servidor não tenha de a enviar ou gerar para cada visitante, o que reduz o TTFB (duração da cache). A cache do browser poupa o request inteiro, para um único visitante. Este insight diz respeito apenas à cache do browser, pelo que ter uma cache de página já ativa não elimina o aviso.
Uma duração de cache mais longa melhora o LCP e o FCP?
FCP e LCP numa primeira visita
Não há qualquer alteração. Numa página de produto WooCommerce, num telemóvel com Slow 4G, a página fez o primeiro paint aos 2,13 s e o LCP surgiu aos 2,26 s com qualquer header, desde nenhum até um ano: numa primeira visita, ainda nada está em cache. O Lighthouse e o PageSpeed Insights carregam sempre as páginas desta forma. Corrigir este insight nunca altera a pontuação nem as métricas do Lighthouse, mesmo quando o Lighthouse o mostra a vermelho com estimativas de poupança no FCP e no LCP ao lado.

Sem duração

4 horas da Cloudflare

Um ano

no-store
A mesma página de produto com quatro headers de cache nos seus ficheiros. Lighthouse 13.5.0, mobile, throttling simulado.
FCP e LCP na página seguinte e numa visita de retorno
O first paint (FCP) em segundos, em comparação com os 2,13 s na primeira visita:
| Header de cache | Página seguinte | Uma semana depois |
|---|---|---|
| um ano | 0,79 | 0,78 |
| 4 horas | 0,80 | 1,94 |
no-cache | 1,93 | 1,94 |
no-store | 2,11 | 2,12 |
- O ganho vem dos ficheiros dentro da duração. Uma semana depois, a página com a duração de um ano fez o paint aos 0,78 s, cerca de um terço da primeira visita. O que resta é a espera pelo HTML. Na visita de retorno, o LCP, a foto do produto, surgiu exatamente no mesmo momento do first paint com todos os headers, exceto com no-store (2,24 s).
- Com respostas 304, a visita de retorno foi quase tão lenta como uma primeira visita. Sem uma duração definida, uma semana depois todos os 13 ficheiros próprios da loja responderam com 304: 1 kB pela rede em vez de 404 kB, e ainda assim um first paint aos 1,94 s, apenas 0,19 s mais rápido do que descarregar tudo de novo.
- Durações curtas cobrem a visita e expiram antes do retorno. As 4 horas da Cloudflare serviram a página seguinte a partir da cache. Uma semana depois, foram necessários 304s. Apenas a duração de um ano cobriu ambos os cenários.
- no-cache e no-store tornam todas as páginas mais lentas. Fizeram a página seguinte passar de 0,79 s para 1,93 s e 2,11 s.

Sem duração, uma semana depois

Duração de um ano, uma semana depois
Ambas as páginas aos 0,8 s no telemóvel com throttling.
Numa ligação Slow 4G real, cada visualização demora mais tempo; a ordem entre os headers mantém-se. Em Fast 4G, a duração de um ano fez o paint aos 0,52 s na visita de retorno, e o retorno com 304s demorou 0,85 s, o mesmo que a primeira visita nessa ligação.
Quando pode ignorar o Use efficient cache lifetimes?
Se o Lighthouse lista ficheiros seus e os visitantes regressam dias ou semanas mais tarde, corrija: basta uma regra no servidor e não custa nada durante o carregamento da página. Ignore o aviso quando:
- todos os ficheiros listados estão noutro domínio ou são servidos pela sua plataforma (ver abaixo); no Shopify é sempre o caso;
- o seu CSS e JavaScript mudam com o mesmo nome de ficheiro e não pode adicionar uma versão: nesse caso, uma duração curta é a escolha certa, e o Lighthouse continuará a listar esses ficheiros;
- quase todos os visitantes veem uma única página e nunca mais voltam, como numa landing page de uma campanha de anúncios: ninguém usa a cache.
Como medir o efeito das durações de cache nos seus field data?
Os seus field data misturam primeiras visitas com páginas seguintes e visitas de retorno. No CoreDash, agrupe o LCP em mobile por Repeat Visitor e, em seguida, o TTFB da mesma forma:


O CoreDash num site de demonstração, acme-pagespeed.com: mobile, p75.
Os visitantes de retorno têm um LCP de 0,65 s; os novos visitantes, 1,74 s. Nem toda esta diferença se deve à cache: os visitantes de retorno também recebem o primeiro byte mais cedo, 323 ms contra 0,87 s, frequentemente porque o browser já tem uma ligação estabelecida ao servidor. Portanto, subtraia o TTFB ao LCP. Após o primeiro byte, os visitantes de retorno esperam 0,33 s e os novos visitantes 0,87 s. Esses 0,54 s são, grosso modo, o que a cache poupa — cerca de metade da diferença; o primeiro byte mais rápido representa a outra metade.
Para ver a página seguinte de uma visita isoladamente, agrupe por Navigation Origin: same origin significa que o visitante veio de outra página do mesmo site. O CrUX junta todas estas visitas num único p75 por página ou por site, pelo que não consegue mostrar esta divisão.
Como verificar os headers de cache de um ficheiro no DevTools?
Abra o painel Network e certifique-se de que a opção Disable cache está desativada (as definições de rede do DevTools explicam quando deve ativá-la). Carregue a página e, em seguida, clique para avançar para uma segunda página. As colunas Status e Size mostram o que aconteceu a cada ficheiro:
- (disk cache) ou (memory cache) na coluna Size: obtido a partir da cache, sem qualquer request.
- 304 na coluna Status: o browser consultou o servidor e não recebeu nenhum ficheiro de volta.
- 200 com um tamanho: descarregado novamente.

Sem duração: 304 em todos os ficheiros

Um ano: a partir da disk cache
A visita de retorno uma semana depois no painel Network, Slow 4G.
Clique num ficheiro e abra o separador Headers. Em Response Headers, o cache-control e o expires mostram a duração que o servidor enviou; o etag e o last-modified mostram com o que o browser pode fazer a revalidação. A partir da linha de comandos:
curl -sI https://www.example.com/wp-content/themes/acme/style.css | grep -iE "cache-control|expires|etag|last-modified" O painel Performance tem o mesmo insight. Grave um recarregamento e abra o Use efficient cache lifetimes na barra lateral Insights: lista os ficheiros e destaca-os na faixa Network. Um ficheiro sem duração surge aí como 0 ms, e como None no Lighthouse. A validação baseia-se nos headers, pelo que um ficheiro que veio da cache continua a ser listado se a respetiva duração for curta.

Como corrigir o Use efficient cache lifetimes?
O domínio de cada ficheiro listado pelo Lighthouse indica quem define o header: no seu próprio domínio é o seu servidor, o alojamento ou a CDN; em qualquer outro domínio é o fornecedor desse ficheiro.
nginx, Apache, IIS e Caddy
No seu servidor, uma regra por tipo de ficheiro define a duração. Estas regras atribuem um ano, com immutable: utilize-as para imagens e para ficheiros CSS, JavaScript e tipos de letra assim que os respetivos URLs incluam uma versão (que duração atribuir a cada ficheiro). No nginx:
location ~* \.(?:css|js|mjs|woff2|svg|png|jpe?g|gif|webp|avif|ico)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
} Coloque-a no bloco server que serve estes ficheiros a partir do disco. Se a sua configuração já tiver uma diretiva location para estas extensões, adicione a linha add_header a essa mesma diretiva, porque o nginx utiliza apenas a primeira location com regex que fizer correspondência. Remova qualquer linha expires aí presente, caso contrário os ficheiros recebem dois headers Cache-Control. Um add_header dentro de uma location faz com que o nginx ignore todos os add_header do bloco server para esses ficheiros, por isso copie também para esta location as linhas add_header do bloco server (o header HSTS, por exemplo).
No Apache, coloque isto no .htaccess:
<IfModule mod_headers.c>
<FilesMatch "\.(css|js|mjs|woff2|svg|png|jpe?g|gif|webp|avif|ico)$">
Header set Cache-Control "public, max-age=31536000, immutable"
</FilesMatch>
</IfModule> A diretiva FilesMatch atua pelo nome do ficheiro, pelo que as páginas geradas pelo PHP mantêm os seus próprios headers. Se o Lighthouse continuar a listar os ficheiros depois disto, o servidor não está a aplicar a regra: o mod_headers está desativado ou o fornecedor de alojamento serve estes ficheiros a partir de outro servidor que ignora o .htaccess. Fale com o seu alojamento.
Por predefinição, o IIS não envia qualquer duração. Defina o header no web.config, limitado à pasta dos ficheiros estáticos:
<configuration>
<location path="assets">
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Cache-Control" value="public, max-age=31536000, immutable" />
</customHeaders>
</httpProtocol>
</system.webServer>
</location>
</configuration> No Caddy:
@static path *.css *.js *.mjs *.woff2 *.svg *.png *.jpg *.jpeg *.gif *.webp *.avif *.ico
header @static Cache-Control "public, max-age=31536000, immutable" WordPress
O próprio WordPress não envia qualquer duração para nada em /wp-content/ ou /wp-includes/: a decisão cabe ao alojamento, ao servidor ou a um plugin. A Kinsta, a WP Engine, o WordPress VIP e o WordPress.com já enviam um ano: se o seu site estiver aí alojado, os ficheiros listados pelo Lighthouse estão normalmente noutros domínios (ver abaixo). O aviso surge habitualmente em alojamentos partilhados com Apache que não enviam duração, em servidores geridos por si com nginx e com a configuração predefinida da Cloudflare. Nos plugins de cache:
- WP Rocket escreve regras mod_expires no .htaccess em servidores Apache e LiteSpeed: um ano para CSS e JavaScript, quatro meses para imagens e tipos de letra. No nginx não faz nada: adicione a regra de nginx acima ou fale com o seu alojamento.
- LiteSpeed Cache tem a opção Browser Cache desativada por predefinição. Ative-a em LiteSpeed Cache, Cache, Browser; passa então a enviar um ano.
- W3 Total Cache tem a opção Browser Cache ativada por predefinição. No nginx, cria um ficheiro nginx.conf que tem de incluir manualmente na configuração do servidor.
O WordPress adiciona ?ver= a cada folha de estilo e script que carrega: a versão do WordPress por predefinição, ou a versão passada pelo tema ou plugin. Isso só muda numa atualização. Quando edita o seu CSS sem alterar a versão, o URL permanece idêntico e os visitantes de retorno mantêm o CSS antigo enquanto a respetiva duração de cache estiver ativa. Carregue os seus próprios ficheiros com a data de modificação como versão, para que o URL mude a cada edição:
add_action( 'wp_enqueue_scripts', function () {
$file = '/css/custom.css';
wp_enqueue_style( 'acme-custom', get_stylesheet_directory_uri() . $file, array(), filemtime( get_stylesheet_directory() . $file ) );
} ); Os uploads não têm versão. O WordPress atribui um novo nome a um ficheiro que carregue novamente (photo-1.jpg), pelo que um ano é seguro para estes casos, a não ser que algum plugin substitua ficheiros multimédia mantendo o mesmo nome.
Cloudflare e outras CDNs
O Browser Cache TTL da Cloudflare é de 4 horas por predefinição, em todos os planos. Quando o servidor não envia qualquer duração ou envia uma duração inferior, a Cloudflare envia 4 horas e o Lighthouse lista o ficheiro como "4h". Defina as durações no servidor e mude o Browser Cache TTL (Caching, Configuration) para Respect Existing Headers. Em alternativa, crie uma Cache Rule para os seus tipos de ficheiros estáticos que defina o TTL do browser. Não aumente a definição global da zona para um ano: passará a aplicar-se a todos os ficheiros que a Cloudflare sirva com um header mais curto, incluindo CSS sem versão. Mais detalhes sobre as restantes definições em configurar a Cloudflare para os Core Web Vitals.
A CloudFront e a Fastly transmitem o header do servidor diretamente para o browser; as suas definições de TTL apenas alteram o tempo durante o qual a CDN retém a sua cópia. No Bunny, uma Edge Rule com Override Browser Cache Time define a duração por extensão de ficheiro.
Shopify
O Shopify já atribui um ano aos ficheiros de tema, ficheiros carregados e imagens de produto (public, max-age=31557600), e não é possível alterar os headers do Shopify. O que o Lighthouse lista no Shopify provém do próprio Shopify e das suas aplicações: os botões de checkout dinâmico (portable-wallets, 5 minutos, no seu próprio domínio em /cdn/shopifycloud/), o loader shop-js (30 minutos) e o web pixels manager (60 segundos). Não há nada a corrigir. Ignore o aviso.
Next.js e outras ferramentas de build
O Next.js atribui um ano com immutable a tudo o que está em /_next/static/, e não é possível sobrepor essa regra. Os ficheiros em public/ recebem max-age=0 (na Vercel com must-revalidate) e o /_next/image envia must-revalidate, pelo que o insight ignora ambos. Num site em Next.js, os ficheiros que o Lighthouse lista provêm de terceiros, ou de um proxy ou CDN à frente que reescreve os headers. Para ficheiros em public/ cujo nome mude consoante o conteúdo, defina um ano no next.config.js:
module.exports = {
async headers() {
return [{
source: '/fonts/:path*',
headers: [{ key: 'Cache-Control', value: 'public, max-age=31536000, immutable' }],
}]
},
} Em qualquer outra stack, configure o bundler para incluir um hash no nome dos ficheiros (app.3f9a1c.js), para que cada alteração resulte num novo URL. Depois, envie um ano de cache nesses ficheiros.
Ficheiros de terceiros e da plataforma que não pode alterar
Os fornecedores mantêm a duração dos respetivos scripts curta para poderem atualizá-los em todos os sites em simultâneo, e não é possível alterar esses headers. O Lighthouse lista frequentemente estes ficheiros, com a duração que o fornecedor envia:
- Meta Pixel (fbevents.js): 20 minutos
- Hotjar: 60 segundos
- O antigo analytics.js do Google Analytics: 2 horas
- Google Maps (maps/api/js): 30 minutos
- Stripe (js.stripe.com/v3): 2 minutos
- Scripts próprios da Cloudflare no seu domínio (email-decode.min.js, Rocket Loader): 2 dias
Deixe-os ficar. Não aloje localmente loaders como o fbevents.js ou o gtag.js apenas para aplicar o seu próprio header: a sua cópia deixa de receber as atualizações do fornecedor. O que pode fazer:
- Carregue bibliotecas a partir de uma CDN pública com uma versão exata no URL. O jsDelivr atribui sete dias ao swiper@11 e um ano a uma versão exata. Em alternativa, aloje essa versão fixa localmente, com o seu próprio header.
- Desative funcionalidades da Cloudflare de que não necessita, como a Email Address Obfuscation.
- Remova tags que já ninguém utiliza.
Que duração de cache definir para cada ficheiro
- CSS, JavaScript e tipos de letra com versão ou hash no URL: um ano, com immutable:
Cache-Control: public, max-age=31536000, immutable. Uma nova versão constitui um novo URL, pelo que o browser a descarrega de imediato. - Imagens: o mesmo header. Atribua um novo nome de ficheiro a uma imagem alterada e ninguém verá a antiga.
- CSS, JavaScript e tipos de letra sem versão: adicione uma versão primeiro (conforme os passos acima para WordPress e ferramentas de build). Enquanto não o fizer, mantenha uma duração curta e aceite que o Lighthouse os liste: com uma duração longa numa folha de estilo que muda mantendo o mesmo nome, os visitantes de retorno recebem o novo HTML com o CSS antigo.
- O HTML:
Cache-Control: no-cacheou um max-age curto, porque com uma duração longa os visitantes ficariam retidos numa página desatualizada. - Nunca utilize no-store, no-cache ou must-revalidate em ficheiros estáticos para eliminar o aviso, porque cada visualização de página voltará a verificar ou a descarregar todos os ficheiros novamente (ver a página seguinte acima).
Como verificar se as novas durações de cache estão a funcionar?
Comece por verificar o header no ficheiro, com o curl ou no separador Headers (indicado acima): deve apresentar o novo max-age. Em seguida, execute o Lighthouse em mobile. Os ficheiros já não surgem listados e a pontuação e as métricas mantêm-se inalteradas, tal como nos quatro relatórios acima. Na página de produto, a pontuação variou entre 96 e 80 de execução para execução, e essa oscilação não teve qualquer relação com o header; portanto, uma pontuação diferente após a correção nada revela sobre a cache.
Os visitantes de retorno no CoreDash evidenciam os resultados primeiro, ao fim de poucos dias, à medida que regressam e recebem os ficheiros com a nova duração. O CrUX e o Search Console apresentam os últimos 28 dias; por isso, duas semanas após a correção, metade dos dados apresentados ainda corresponde ao site antigo.
Tem dúvidas sobre quais dos ficheiros listados são da sua responsabilidade ou se os visitantes de retorno estão a aguardar por ficheiros que já têm? Numa power hour de Core Web Vitals, analisamos em conjunto os seus headers e os seus field data, e recebe as regras para o seu servidor antes de terminarmos a chamada.
O score do Lighthouse não conta a história toda.
Os teus visitantes estão em Android sobre 4G. Eu analiso o que eles apanham na prática.
Analisar dados reais