System Design — Camada Cliente (Event SDK)
Event SDK, dataLayer (GA4), batching + sendBeacon, Pixel App da VTEX IO. Onde o evento nasce.
Definição
A camada cliente é onde o evento é capturado. Componentes: (1) Storefront VTEX IO — React/SSR via Store Framework. (2) Event SDK / Pixel App — biblioteca que escuta cliques, scroll, page views e monta o objeto do evento já com event_id (UUID). (3) dataLayer / GTM — padroniza num schema único (GA4) antes de sair do browser. (4) Batching + sendBeacon — agrupa em lote, mantém fila local com retry, envia com navigator.sendBeacon que sobrevive ao fechamento da aba.
Diagrama do fluxo
Camada Cliente — captura ao envio
Problema → Solução
Problema
Cada página instrumentando do seu jeito gera schema inconsistente. Eventos perdidos quando o usuário fecha a aba antes do request terminar. fetch() bloqueia o unload da página. Volume de requests excessivo se enviar um por evento.Solução
SDK centralizado padroniza captura. dataLayer padroniza schema (GA4). sendBeacon não bloqueia unload — sobrevive ao fechamento. Batching reduz requests (10-30 eventos por lote). Fila local com backoff exponencial garante entrega mesmo se a rede oscilar.Dica de entrevista
Tip
Na VTEX IO o conceito nativo é Pixel App — uma extensão que escuta eventos da storefront. Use o Pixel App em vez de instrumentar manualmente. event_id (UUID) gerado no cliente é crítico para idempotência depois.Código
// Event SDK — instrumentação na storefront VTEX IO
class EventSDK {
private queue: Event[] = []
private timer: ReturnType<typeof setTimeout> | null = null
track(name: string, params: Record<string, unknown>) {
this.queue.push({
event_id: crypto.randomUUID(),
event_name: name,
client_timestamp: Date.now(),
session_id: this.session(),
user_id: this.user(),
...params,
})
this.scheduleFlush()
}
private scheduleFlush() {
if (this.queue.length >= 20) return this.flush()
if (!this.timer) {
this.timer = setTimeout(() => this.flush(), 5000)
}
}
private flush() {
if (this.queue.length === 0) return
const batch = this.queue.splice(0)
if (this.timer) { clearTimeout(this.timer); this.timer = null }
// sendBeacon não bloqueia o unload da página
const blob = new Blob([JSON.stringify(batch)], { type: 'application/json' })
const ok = navigator.sendBeacon('/collect', blob)
if (!ok) this.queue.unshift(...batch) // retry
}
}
// Hook no unload — garantia final
window.addEventListener('pagehide', () => sdk.flush())Perguntas de entrevista
Q.Por que sendBeacon e não fetch?▾
A.sendBeacon é assíncrono, não bloqueia o unload da página e o browser garante o envio mesmo se a aba fechar. fetch() durante unload é cancelado pelo browser. Para purchase event (crítico), sendBeacon evita perda quando o usuário fecha a aba após confirmar compra.
Q.O que é o dataLayer e por que padronizar?▾
A.dataLayer é uma camada intermediária (geralmente injetada pelo GTM) onde todo evento passa antes de sair do browser. Padronizar no schema GA4 desacopla a página das ferramentas de destino — você troca o GA por outra ferramenta sem mexer no código da página.
Q.Como funciona batching no cliente?▾
A.Fila local em memória (com persistência em sessionStorage para sobreviver a navegação). Flush em 3 triggers: tamanho máximo (ex: 20 eventos), tempo máximo (ex: 5s) e antes do unload (com sendBeacon). Retry com backoff exponencial se o request falhar.
Termos relacionados
105/122← →