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êsLanding Page PT
↓
Mailchimp
↓
Tag de inscritos em portuguêsLanding Page PT
↓
Mailchimp
↓
Tag de inscritos em portuguêse:
Landing Page ES
↓
Mailchimp
↓
Tag de inscritos em espanholLanding Page ES
↓
Mailchimp
↓
Tag de inscritos em espanholLanding Page ES
↓
Mailchimp
↓
Tag de inscritos em espanholOs 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 LATAMMailchimp
↓
Mailchimp Marketing API
↓
Google Apps Script
↓
Tratamento e consolidação
↓
Google Sheets
↓
Looker Studio
↓
Dashboard LATAMMailchimp
↓
Mailchimp Marketing API
↓
Google Apps Script
↓
Tratamento e consolidação
↓
Google Sheets
↓
Looker Studio
↓
Dashboard LATAMO 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:
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:
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:
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:
No formulário em espanhol:
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:
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;
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;
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;
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:
com merge field:
e fallback:
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() {
}function atualizarInscricoesBrasilPBL() {
}function atualizarInscricoesBrasilPBL() {
}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:
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 StudioMailchimp API
↓
Google Apps Script
↓
Processamento
↓
Google Sheets
↓
Looker StudioMailchimp API
↓
Google Apps Script
↓
Processamento
↓
Google Sheets
↓
Looker StudioEstrutura 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:
e:
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:
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.