Código e Automação

19 de ago. de 2026

Go back

Como integrei Mailchimp, Google Apps Script e Looker Studio para monitorar inscrições de um projeto LATAM

Autor: Rafael Lins

Veja como integrei Mailchimp, Google Apps Script, Google Sheets, GA4 e Looker Studio para automatizar inscrições e análises de um projeto LATAM.

Vibrant reggae art featuring a monkey

Fique por dentro do que há de mais relavante no Marketing Digital, assine a nossa newsletter:

Fique por dentro do que há de mais relavante no Marketing Digital, assine a nossa newsletter:

Projetos digitais que operam em vários países costumam esbarrar em um problema que parece simples até chegar a hora de construir o relatório: os dados existem, mas não necessariamente estão estruturados da forma necessária para análise.

Foi exatamente esse o cenário de um projeto educacional com atuação em toda a América Latina.

As inscrições para um curso estavam sendo realizadas por meio de landing pages no Mailchimp, separadas entre português e espanhol. O Mailchimp armazenava corretamente os contatos, países, estados e demais informações coletadas pelos formulários.

O desafio era outro.

Precisávamos transformar esses registros em uma fonte de dados automaticamente atualizada e utilizável no Looker Studio, antigo Google Data Studio, permitindo acompanhar:

  • total de inscritos;

  • inscrições em português;

  • inscrições em espanhol;

  • evolução diária das inscrições;

  • distribuição por país;

  • quantidade de países alcançados;

  • inscrições fora do Brasil;

  • distribuição dos inscritos brasileiros por estado;

  • identificação dos países e estados com maior participação.

Em vez de exportar CSVs manualmente do Mailchimp e alimentar relatórios periodicamente, desenvolvi uma integração usando a API do Mailchimp, Google Apps Script, Google Sheets e Looker Studio.

O resultado foi uma pequena pipeline de dados serverless, automatizada e praticamente sem infraestrutura própria.

O problema: Mailchimp é a origem dos dados, não a camada analítica

O Mailchimp funciona muito bem para captura e gerenciamento dos contatos.

Para esse projeto, existiam dois fluxos principais de inscrição:

Landing Page PT
        
Mailchimp
        
Tag de inscritos em português
Landing Page PT
        
Mailchimp
        
Tag de inscritos em português
Landing Page PT
        
Mailchimp
        
Tag de inscritos em português

e:

Landing Page ES
        
Mailchimp
        
Tag de inscritos em espanhol
Landing Page ES
        
Mailchimp
        
Tag de inscritos em espanhol
Landing Page ES
        
Mailchimp
        
Tag de inscritos em espanhol

Os contatos também possuíam campos personalizados contendo informações como país e, no formulário brasileiro, estado.

O problema aparece quando queremos responder perguntas analíticas como:

Quantas pessoas se inscreveram no curso até agora?

Quantas vieram da landing page em português?

Quantas vieram da versão em espanhol?

Quantos países diferentes já participaram?

Qual país possui mais inscrições?

Quantos inscritos são brasileiros?

Dentro do Brasil, quais estados concentram mais participantes?

O Mailchimp possui esses dados, mas não necessariamente na estrutura que queremos entregar para uma ferramenta de Business Intelligence.

Foi necessário criar uma camada intermediária.

A arquitetura escolhida

A arquitetura implementada ficou conceitualmente assim:

Mailchimp
    
Mailchimp Marketing API
    
Google Apps Script
    
Tratamento e consolidação
    
Google Sheets
    
Looker Studio
    
Dashboard LATAM
Mailchimp
    
Mailchimp Marketing API
    
Google Apps Script
    
Tratamento e consolidação
    
Google Sheets
    
Looker Studio
    
Dashboard LATAM
Mailchimp
    
Mailchimp Marketing API
    
Google Apps Script
    
Tratamento e consolidação
    
Google Sheets
    
Looker Studio
    
Dashboard LATAM

O Google Sheets funciona nesse desenho como uma camada intermediária de armazenamento e exposição dos dados.

O Apps Script é responsável pela integração e pelo processamento.

Já o Looker Studio fica responsável pelo que ele faz melhor: visualização e exploração dos dados.

Essa separação foi importante porque evitou concentrar regras de negócio dentro do dashboard.

Identificando os inscritos por idioma

As duas landing pages utilizavam a mesma Audience do Mailchimp, mas os inscritos eram separados por tags.

No projeto, a lógica ficou assim:

PT
3ed - inscritos 2026 curso pbl portugues
PT
3ed - inscritos 2026 curso pbl portugues
PT
3ed - inscritos 2026 curso pbl portugues
ES
3ed - inscritos 2026 curso pbl espanhol
ES
3ed - inscritos 2026 curso pbl espanhol
ES
3ed - inscritos 2026 curso pbl espanhol

Cada tag possui um ID interno na API.

No Apps Script, defini essas configurações de forma centralizada:

function obterTagsPBL_() {
  return [
    {
      idioma: 'PT',
      id: '3081892',
      nome: '3ed - inscritos 2026 curso pbl portugues'
    },
    {
      idioma: 'ES',
      id: '3081893',
      nome: '3ed - inscritos 2026 curso pbl espanhol'
    }
  ];
}
function obterTagsPBL_() {
  return [
    {
      idioma: 'PT',
      id: '3081892',
      nome: '3ed - inscritos 2026 curso pbl portugues'
    },
    {
      idioma: 'ES',
      id: '3081893',
      nome: '3ed - inscritos 2026 curso pbl espanhol'
    }
  ];
}
function obterTagsPBL_() {
  return [
    {
      idioma: 'PT',
      id: '3081892',
      nome: '3ed - inscritos 2026 curso pbl portugues'
    },
    {
      idioma: 'ES',
      id: '3081893',
      nome: '3ed - inscritos 2026 curso pbl espanhol'
    }
  ];
}

Isso permite consultar cada segmento separadamente e consolidar os resultados posteriormente.

Segurança: credenciais fora do código

Um ponto que considerei desde o início foi não colocar a API Key do Mailchimp diretamente no código.

As credenciais ficaram armazenadas nas propriedades do projeto do Google Apps Script:

MAILCHIMP_API_KEY
MAILCHIMP_DC
MAILCHIMP_LIST_ID
MAILCHIMP_API_KEY
MAILCHIMP_DC
MAILCHIMP_LIST_ID
MAILCHIMP_API_KEY
MAILCHIMP_DC
MAILCHIMP_LIST_ID

No código, elas são recuperadas assim:

function obterConfiguracaoMailchimp_() {
  const props = PropertiesService.getScriptProperties();

  const apiKey = props.getProperty('MAILCHIMP_API_KEY');
  const dc = props.getProperty('MAILCHIMP_DC');
  const listId = props.getProperty('MAILCHIMP_LIST_ID');

  if (!apiKey || !dc || !listId) {
    throw new Error(
      'MAILCHIMP_API_KEY, MAILCHIMP_DC ou MAILCHIMP_LIST_ID não encontrados.'
    );
  }

  return {
    apiKey: apiKey,
    dc: dc,
    listId: listId
  };
}
function obterConfiguracaoMailchimp_() {
  const props = PropertiesService.getScriptProperties();

  const apiKey = props.getProperty('MAILCHIMP_API_KEY');
  const dc = props.getProperty('MAILCHIMP_DC');
  const listId = props.getProperty('MAILCHIMP_LIST_ID');

  if (!apiKey || !dc || !listId) {
    throw new Error(
      'MAILCHIMP_API_KEY, MAILCHIMP_DC ou MAILCHIMP_LIST_ID não encontrados.'
    );
  }

  return {
    apiKey: apiKey,
    dc: dc,
    listId: listId
  };
}
function obterConfiguracaoMailchimp_() {
  const props = PropertiesService.getScriptProperties();

  const apiKey = props.getProperty('MAILCHIMP_API_KEY');
  const dc = props.getProperty('MAILCHIMP_DC');
  const listId = props.getProperty('MAILCHIMP_LIST_ID');

  if (!apiKey || !dc || !listId) {
    throw new Error(
      'MAILCHIMP_API_KEY, MAILCHIMP_DC ou MAILCHIMP_LIST_ID não encontrados.'
    );
  }

  return {
    apiKey: apiKey,
    dc: dc,
    listId: listId
  };
}

Isso permite versionar o projeto no GitHub sem expor credenciais.

Testando a conexão com a API

Antes de construir qualquer lógica, validei a autenticação usando o endpoint /ping.

function testarMailchimp() {
  const config = obterConfiguracaoMailchimp_();

  const url =
    `https://${config.dc}.api.mailchimp.com/3.0/ping`;

  const options = {
    method: 'get',
    headers: {
      Authorization:
        'Basic ' +
        Utilities.base64Encode(
          'user:' + config.apiKey
        )
    },
    muteHttpExceptions: true
  };

  const response =
    UrlFetchApp.fetch(url, options);

  Logger.log(
    'HTTP Status: ' +
    response.getResponseCode()
  );

  Logger.log(
    response.getContentText()
  );
}
function testarMailchimp() {
  const config = obterConfiguracaoMailchimp_();

  const url =
    `https://${config.dc}.api.mailchimp.com/3.0/ping`;

  const options = {
    method: 'get',
    headers: {
      Authorization:
        'Basic ' +
        Utilities.base64Encode(
          'user:' + config.apiKey
        )
    },
    muteHttpExceptions: true
  };

  const response =
    UrlFetchApp.fetch(url, options);

  Logger.log(
    'HTTP Status: ' +
    response.getResponseCode()
  );

  Logger.log(
    response.getContentText()
  );
}
function testarMailchimp() {
  const config = obterConfiguracaoMailchimp_();

  const url =
    `https://${config.dc}.api.mailchimp.com/3.0/ping`;

  const options = {
    method: 'get',
    headers: {
      Authorization:
        'Basic ' +
        Utilities.base64Encode(
          'user:' + config.apiKey
        )
    },
    muteHttpExceptions: true
  };

  const response =
    UrlFetchApp.fetch(url, options);

  Logger.log(
    'HTTP Status: ' +
    response.getResponseCode()
  );

  Logger.log(
    response.getContentText()
  );
}

O retorno esperado da API é:

{
  "health_status": "Everything's Chimpy!"
}
{
  "health_status": "Everything's Chimpy!"
}
{
  "health_status": "Everything's Chimpy!"
}

Só depois dessa validação comecei a trabalhar nas consultas de dados.

Criando o snapshot atual das inscrições

A primeira camada do relatório precisava responder apenas:

PT
ES
TOTAL
PT
ES
TOTAL
PT
ES
TOTAL

A API retorna o número total de membros de cada segmento, então o Apps Script coleta esses valores e atualiza uma aba chamada:

status_atual
status_atual
status_atual

Estrutura:

idioma | inscritos | ultima_atualizacao
PT     | 629       | 19/08/2026 12:21:56
ES     | 241       | 19/08/2026 12:21:56
TOTAL  | 870       | 19/08/2026 12:21:56
idioma | inscritos | ultima_atualizacao
PT     | 629       | 19/08/2026 12:21:56
ES     | 241       | 19/08/2026 12:21:56
TOTAL  | 870       | 19/08/2026 12:21:56
idioma | inscritos | ultima_atualizacao
PT     | 629       | 19/08/2026 12:21:56
ES     | 241       | 19/08/2026 12:21:56
TOTAL  | 870       | 19/08/2026 12:21:56

Essa aba é utilizada diretamente nos scorecards do Looker Studio.

Criando um histórico diário

Além do status atual, eu precisava acompanhar a curva de crescimento das inscrições.

Para isso criei a aba:

historico
historico
historico

Ela armazena um snapshot diário:

data       | idioma | inscritos | ultima_atualizacao
17/08/2026 | PT     | 375       | ...
17/08/2026 | ES     | 211       | ...
17/08/2026 | TOTAL  | 586       | ...

18/08/2026 | PT     | 498       | ...
18/08/2026 | ES     | 235       | ...
18/08/2026 | TOTAL  | 733       | ...

19/08/2026 | PT     | 629       | ...
19/08/2026 | ES     | 241       | ...
19/08/2026 | TOTAL  | 870       | ...
data       | idioma | inscritos | ultima_atualizacao
17/08/2026 | PT     | 375       | ...
17/08/2026 | ES     | 211       | ...
17/08/2026 | TOTAL  | 586       | ...

18/08/2026 | PT     | 498       | ...
18/08/2026 | ES     | 235       | ...
18/08/2026 | TOTAL  | 733       | ...

19/08/2026 | PT     | 629       | ...
19/08/2026 | ES     | 241       | ...
19/08/2026 | TOTAL  | 870       | ...
data       | idioma | inscritos | ultima_atualizacao
17/08/2026 | PT     | 375       | ...
17/08/2026 | ES     | 211       | ...
17/08/2026 | TOTAL  | 586       | ...

18/08/2026 | PT     | 498       | ...
18/08/2026 | ES     | 235       | ...
18/08/2026 | TOTAL  | 733       | ...

19/08/2026 | PT     | 629       | ...
19/08/2026 | ES     | 241       | ...
19/08/2026 | TOTAL  | 870       | ...

Se a rotina executa várias vezes no mesmo dia, ela atualiza a linha daquele dia em vez de criar duplicidades.

Isso permitiu construir no Looker Studio um gráfico real de evolução diária das inscrições.

Distribuição dos inscritos por país

A próxima necessidade foi entender a distribuição geográfica.

Aqui surgiu um detalhe importante.

Os formulários PT e ES utilizavam campos diferentes do Mailchimp para armazenar o país informado.

No formulário em português:

PAIS
PAIS
PAIS

No formulário em espanhol:

PAISESP
PAISESP
PAISESP

Também existia um campo COUNTRY, mas ele não era confiável para essa análise porque alguns contatos já possuíam dados anteriores dentro da Audience.

A regra ficou:

PT merge_fields.PAIS
ES merge_fields.PAISESP
PT merge_fields.PAIS
ES merge_fields.PAISESP
PT merge_fields.PAIS
ES merge_fields.PAISESP

O script percorre todos os inscritos dos dois segmentos, lê o campo correto e consolida:

pais | idioma | inscritos
pais | idioma | inscritos
pais | idioma | inscritos

Exemplo:

Brasil     | PT | 625
Brasil     | ES | 2
Argentina  | ES | 44
México     | ES | 40
Paraguai   | ES | 33
Perú       | ES | 29
Chile      | ES | 18
Brasil     | PT | 625
Brasil     | ES | 2
Argentina  | ES | 44
México     | ES | 40
Paraguai   | ES | 33
Perú       | ES | 29
Chile      | ES | 18
Brasil     | PT | 625
Brasil     | ES | 2
Argentina  | ES | 44
México     | ES | 40
Paraguai   | ES | 33
Perú       | ES | 29
Chile      | ES | 18

Essa base alimenta a aba:

inscricoes_pais
inscricoes_pais
inscricoes_pais

Paginação da API

Uma preocupação importante foi não assumir que os segmentos sempre teriam menos de mil inscritos.

Por isso, as consultas utilizam paginação.

let offset = 0;
const count = 1000;
let totalItems = 0;

do {
  const url =
    `https://${dc}.api.mailchimp.com/3.0/lists/${listId}/segments/${segmentId}/members` +
    `?count=${count}` +
    `&offset=${offset}`;

  const response =
    UrlFetchApp.fetch(url, options);

  const data =
    JSON.parse(
      response.getContentText()
    );

  totalItems =
    data.total_items;

  // processamento

  offset += count;

} while (offset < totalItems);
let offset = 0;
const count = 1000;
let totalItems = 0;

do {
  const url =
    `https://${dc}.api.mailchimp.com/3.0/lists/${listId}/segments/${segmentId}/members` +
    `?count=${count}` +
    `&offset=${offset}`;

  const response =
    UrlFetchApp.fetch(url, options);

  const data =
    JSON.parse(
      response.getContentText()
    );

  totalItems =
    data.total_items;

  // processamento

  offset += count;

} while (offset < totalItems);
let offset = 0;
const count = 1000;
let totalItems = 0;

do {
  const url =
    `https://${dc}.api.mailchimp.com/3.0/lists/${listId}/segments/${segmentId}/members` +
    `?count=${count}` +
    `&offset=${offset}`;

  const response =
    UrlFetchApp.fetch(url, options);

  const data =
    JSON.parse(
      response.getContentText()
    );

  totalItems =
    data.total_items;

  // processamento

  offset += count;

} while (offset < totalItems);

Isso torna a solução escalável para volumes maiores sem alterar a lógica posteriormente.

Descobrindo o estado dos inscritos brasileiros

Depois da visão LATAM, surgiu uma necessidade mais específica: criar uma página exclusiva do Brasil.

O formulário brasileiro também coletava o estado.

No Mailchimp, o campo estava configurado como:

Estado
Estado
Estado

com merge field:

MMERGE15
MMERGE15
MMERGE15

e fallback:

MERGE15
MERGE15
MERGE15

Antes de incorporar isso à automação, criei uma função de teste para validar se o campo realmente estava preenchido.

O resultado mostrou:

Brasileiros encontrados: 624
Brasileiros com estado: 624
Brasileiros sem estado: 0
Brasileiros encontrados: 624
Brasileiros com estado: 624
Brasileiros sem estado: 0
Brasileiros encontrados: 624
Brasileiros com estado: 624
Brasileiros sem estado: 0

Ou seja, cobertura completa naquele snapshot.

Consolidando inscrições brasileiras por estado

Com o campo validado, criei uma nova rotina:

function atualizarInscricoesBrasilPBL() {
  // consulta os segmentos PT e ES
  // filtra pais = Brasil
  // lê MMERGE15
  // consolida estado + idioma
  // grava no Google Sheets
}
function atualizarInscricoesBrasilPBL() {
  // consulta os segmentos PT e ES
  // filtra pais = Brasil
  // lê MMERGE15
  // consolida estado + idioma
  // grava no Google Sheets
}
function atualizarInscricoesBrasilPBL() {
  // consulta os segmentos PT e ES
  // filtra pais = Brasil
  // lê MMERGE15
  // consolida estado + idioma
  // grava no Google Sheets
}

A estrutura gerada ficou:

estado                  | idioma | inscritos
São Paulo (SP)          | PT     | 215
Minas Gerais (MG)       | PT     | 59
Rio de Janeiro (RJ)     | PT     | 39
Paraíba (PB)            | PT     | 36
Bahia (BA)              | PT     | 35
Rio Grande do Sul (RS)  | PT     | 34
Pernambuco (PE)         | PT     | 32
Pará (PA)               | ES     | 2
estado                  | idioma | inscritos
São Paulo (SP)          | PT     | 215
Minas Gerais (MG)       | PT     | 59
Rio de Janeiro (RJ)     | PT     | 39
Paraíba (PB)            | PT     | 36
Bahia (BA)              | PT     | 35
Rio Grande do Sul (RS)  | PT     | 34
Pernambuco (PE)         | PT     | 32
Pará (PA)               | ES     | 2
estado                  | idioma | inscritos
São Paulo (SP)          | PT     | 215
Minas Gerais (MG)       | PT     | 59
Rio de Janeiro (RJ)     | PT     | 39
Paraíba (PB)            | PT     | 36
Bahia (BA)              | PT     | 35
Rio Grande do Sul (RS)  | PT     | 34
Pernambuco (PE)         | PT     | 32
Pará (PA)               | ES     | 2

A nova aba recebeu o nome:

inscricoes_brasil
inscricoes_brasil
inscricoes_brasil

O detalhe curioso: brasileiros também entraram pelo formulário em espanhol

Quando comecei a consolidar o Brasil por estado apareceu um comportamento interessante.

Dois inscritos classificados como brasileiros tinham entrado pelo formulário em espanhol.

Isso ficou visível porque mantive a estrutura:

estado | idioma | inscritos
estado | idioma | inscritos
estado | idioma | inscritos

em vez de simplesmente somar tudo em uma única coluna.

Esse tipo de detalhe mostra por que manter granularidade suficiente na camada de dados é importante.

Se eu tivesse agregado apenas por estado, essa informação teria desaparecido.

Uma única função para atualizar tudo

Depois que as rotinas começaram a crescer, eu não queria manter vários acionadores independentes.

Criei uma função orquestradora:

function atualizarTudoPBL() {
  const lock =
    LockService.getScriptLock();

  try {
    lock.waitLock(30000);

    atualizarPlanilhaPBL();

    atualizarInscricoesPorPaisPBL();

    atualizarInscricoesBrasilPBL();

  } finally {
    lock.releaseLock();
  }
}
function atualizarTudoPBL() {
  const lock =
    LockService.getScriptLock();

  try {
    lock.waitLock(30000);

    atualizarPlanilhaPBL();

    atualizarInscricoesPorPaisPBL();

    atualizarInscricoesBrasilPBL();

  } finally {
    lock.releaseLock();
  }
}
function atualizarTudoPBL() {
  const lock =
    LockService.getScriptLock();

  try {
    lock.waitLock(30000);

    atualizarPlanilhaPBL();

    atualizarInscricoesPorPaisPBL();

    atualizarInscricoesBrasilPBL();

  } finally {
    lock.releaseLock();
  }
}

Ela executa:

status_atual
historico
inscricoes_pais
inscricoes_brasil
status_atual
historico
inscricoes_pais
inscricoes_brasil
status_atual
historico
inscricoes_pais
inscricoes_brasil

em sequência.

Também adicionei LockService para impedir que duas execuções concorrentes tentem modificar as mesmas abas ao mesmo tempo.

Automação horária

No Google Apps Script, configurei um acionador baseado no tempo:

Função:
atualizarTudoPBL

Origem:
Baseado no tempo

Tipo:
Contador de horas

Intervalo:
A cada 1 hora
Função:
atualizarTudoPBL

Origem:
Baseado no tempo

Tipo:
Contador de horas

Intervalo:
A cada 1 hora
Função:
atualizarTudoPBL

Origem:
Baseado no tempo

Tipo:
Contador de horas

Intervalo:
A cada 1 hora

A partir daí, a pipeline passou a funcionar de maneira automática:

Mailchimp API
    
Google Apps Script
    
Processamento
    
Google Sheets
    
Looker Studio
Mailchimp API
    
Google Apps Script
    
Processamento
    
Google Sheets
    
Looker Studio
Mailchimp API
    
Google Apps Script
    
Processamento
    
Google Sheets
    
Looker Studio

Estrutura final das bases

A solução terminou com quatro abas principais:

status_atual
historico
inscricoes_pais
inscricoes_brasil
status_atual
historico
inscricoes_pais
inscricoes_brasil
status_atual
historico
inscricoes_pais
inscricoes_brasil

Cada uma tem uma função específica.

status_atual

Usada para:

  • total de inscritos;

  • inscritos PT;

  • inscritos ES.

historico

Usada para:

  • evolução diária;

  • crescimento acumulado;

  • comparação PT x ES ao longo do tempo.

inscricoes_pais

Usada para:

  • inscritos por país;

  • países alcançados;

  • país líder;

  • inscrições fora do Brasil;

  • distribuição PT x ES.

inscricoes_brasil

Usada para:

  • total de inscritos brasileiros;

  • estados alcançados;

  • estado líder;

  • distribuição por estado;

  • quebra PT x ES dentro do Brasil.

O dashboard no Looker Studio

Com as bases prontas, o Looker Studio ficou muito mais simples.

Não foi necessário colocar lógica complexa de transformação dentro do dashboard.

Os gráficos passaram a consumir dados já preparados.

Entre os indicadores criados estavam:

Total de inscritos
Inscritos PT
Inscritos ES
Países alcançados
País com mais inscrições
Inscrições fora do Brasil
Estados brasileiros alcançados
Estado com mais inscrições
Total de inscritos
Inscritos PT
Inscritos ES
Países alcançados
País com mais inscrições
Inscrições fora do Brasil
Estados brasileiros alcançados
Estado com mais inscrições
Total de inscritos
Inscritos PT
Inscritos ES
Países alcançados
País com mais inscrições
Inscrições fora do Brasil
Estados brasileiros alcançados
Estado com mais inscrições

Também foi possível construir tabelas dinâmicas como:

País | PT | ES
País | PT | ES
País | PT | ES

e:

Estado | PT | ES
Estado | PT | ES
Estado | PT | ES

O papel do GA4 nessa arquitetura

O Mailchimp respondeu pela camada de inscrição.

Já o Google Analytics 4 ficou responsável pela camada de aquisição e comportamento.

Isso permitiu analisar:

utm_source
utm_medium
utm_campaign
utm_term
utm_content
utm_id
utm_source
utm_medium
utm_campaign
utm_term
utm_content
utm_id
utm_source
utm_medium
utm_campaign
utm_term
utm_content
utm_id

e cruzar a performance das landing pages com:

  • usuários;

  • sessões;

  • visualizações;

  • campanhas;

  • peças;

  • canais.

Existe, porém, uma limitação histórica importante neste projeto.

As páginas de confirmação do Mailchimp inicialmente estavam sem o GA4 configurado.

Isso significava que o GA4 conseguia acompanhar:

campanha
peça
usuário
sessão
landing page
campanha
peça
usuário
sessão
landing page
campanha
peça
usuário
sessão
landing page

mas não conseguia observar corretamente o último passo:

landing page
inscrição confirmada
landing page
inscrição confirmada
landing page
inscrição confirmada

Quando identifiquei o problema, corrigi a configuração das páginas de confirmação.

A partir desse momento, o projeto passou a construir também uma camada de atribuição mais confiável entre origem do tráfego e inscrição.

Por que não usei um conector pago

Uma alternativa seria contratar um conector de terceiros para levar dados do Mailchimp ao Looker Studio.

Para alguns projetos isso faz sentido.

Neste caso, porém, os dados necessários eram bastante específicos.

Eu precisava de:

tags específicas
merge fields específicos
consolidação por idioma
consolidação por país
consolidação por estado
histórico diário
tags específicas
merge fields específicos
consolidação por idioma
consolidação por país
consolidação por estado
histórico diário
tags específicas
merge fields específicos
consolidação por idioma
consolidação por país
consolidação por estado
histórico diário

Com Apps Script foi possível controlar exatamente a lógica de negócio sem adicionar um custo recorrente de integração.

Além disso, o projeto passou a ter uma integração que pode ser versionada, documentada e reutilizada.

O Google Sheets não é o banco de dados definitivo

Para este contexto, o Sheets funcionou muito bem.

O volume é pequeno, a frequência de atualização é horária e o Looker Studio possui integração nativa.

Mas é importante entender o limite da arquitetura.

Se esse projeto evoluísse para centenas de milhares ou milhões de registros, múltiplas fontes e transformações complexas, eu provavelmente migraria a camada intermediária para algo como:

BigQuery
PostgreSQL
Cloud SQL
ou outro data warehouse
BigQuery
PostgreSQL
Cloud SQL
ou outro data warehouse
BigQuery
PostgreSQL
Cloud SQL
ou outro data warehouse

A arquitetura conceitual continuaria semelhante:

Fonte
ingestão
transformação
armazenamento
visualização
Fonte
ingestão
transformação
armazenamento
visualização
Fonte
ingestão
transformação
armazenamento
visualização

O que mudaria seria a tecnologia utilizada em cada camada.

Uma pequena pipeline de dados pode resolver um problema grande

Esse projeto é um bom exemplo de algo que aparece constantemente no trabalho de analytics.

Nem sempre o problema é ausência de dados.

Muitas vezes o problema é a distância entre:

onde o dado nasce
onde o dado nasce
onde o dado nasce

e:

como o negócio precisa analisá-lo
como o negócio precisa analisá-lo
como o negócio precisa analisá-lo

Nesse caso, os dados já estavam no Mailchimp.

O trabalho foi construir uma camada confiável entre:

Mailchimp
Google Apps Script
Google Sheets
GA4
Looker Studio
Mailchimp
Google Apps Script
Google Sheets
GA4
Looker Studio
Mailchimp
Google Apps Script
Google Sheets
GA4
Looker Studio

para transformar registros operacionais em uma visão analítica utilizável por equipes que acompanham um projeto educacional em escala LATAM.

Esse tipo de implementação faz parte da abordagem que utilizo na Ad Rock Digital Mkt: não tratar analytics apenas como instalação de tags ou criação de dashboards, mas como arquitetura de dados aplicada ao problema real do projeto.

Quando necessário, isso envolve código, APIs, automação, modelagem de dados, mensuração e visualização trabalhando como uma única solução.

Conclusão

O resultado final foi uma integração automatizada que permite acompanhar um projeto LATAM praticamente em tempo real, sem depender de exportações manuais do Mailchimp.

A solução passou a responder perguntas que antes exigiriam manipulação manual de dados:

  • quantas pessoas estão inscritas;

  • como as inscrições evoluem;

  • como PT e ES se distribuem;

  • quais países estão participando;

  • qual é a participação fora do Brasil;

  • quais estados brasileiros concentram mais inscritos.

Tecnicamente, a implementação utilizou ferramentas relativamente simples.

O valor veio da arquitetura.

Mailchimp API
+
Google Apps Script
+
Google Sheets
+
GA4
+
Looker Studio
Mailchimp API
+
Google Apps Script
+
Google Sheets
+
GA4
+
Looker Studio
Mailchimp API
+
Google Apps Script
+
Google Sheets
+
GA4
+
Looker Studio

Quando essas peças são bem conectadas, é possível construir uma camada de analytics bastante robusta sem necessariamente introduzir uma infraestrutura pesada ou um grande stack de engenharia de dados.

Conteúdo original pesquisado e redigido pelo autor. Ferramentas de IA podem ter sido utilizadas para auxiliar na edição e no aprimoramento.

Conteúdo original pesquisado e redigido pelo autor. Ferramentas de IA podem ter sido utilizadas para auxiliar na edição e no aprimoramento.

Posts relacionados:

Posts relacionados:

Compartilhe!

Go back

Deixe a IA fazer o trabalho para Você Crescer Mais Rápido

Agende uma conversa hoje e comece a automatizar.

Deixe a IA fazer o trabalho para Você Crescer Mais Rápido

Agende uma conversa hoje e comece a automatizar.

© 2010 - 2026 Copyright

All Rights Reserved - Develop by Ad Rock Digital Mkt

Tecnologias utilizadas

© 2010 - 2026 Copyright

All Rights Reserved - Develop by
Ad Rock Digital Mkt

Tecnologias utilizadas