Você já usa uma planilha para controlar suas contas, mas continua precisando abrir o arquivo para descobrir o que vence nos próximos dias?
Foi exatamente esse problema que me levou a criar esta automação.
Eu tinha uma planilha com minhas despesas, vencimentos, valores e status de pagamento. Ela funcionava bem para registrar e atualizar as informações, mas não era o melhor lugar para consultar o que precisava ser pago.
A solução foi transformar o Google Sheets na fonte dos dados e o Google Calendar na interface para acompanhar os vencimentos.
O resultado é que hoje consigo simplesmente olhar o widget do Calendário no iPhone — ou perguntar à Siri — quais são os próximos vencimentos.
Nota
As imagens e valores utilizados neste artigo representam um projeto real testado. Informações pessoais podem ser ocultadas ou alteradas antes da publicação.
O problema: a planilha funciona, mas não é onde eu quero consultar minhas contas
Minha planilha possui basicamente quatro informações para cada despesa:
| Informação | Exemplo |
|---|---|
| Item | Faculdade |
| Vencimento | 12/08/2026 |
| Valor | R$ 260,00 |
| Status | A VENCER |
Ela é excelente para gerenciar as contas.
Posso alterar o status de uma despesa quando ela é paga, adicionar uma nova conta ou alterar um vencimento.
O problema é outro: eu não queria precisar abrir a planilha toda vez que quisesse saber o que estava próximo de vencer.

A ideia: deixar o calendário cuidar dos lembretes
Calendário é uma ferramenta que eu já consulto naturalmente durante o dia.
Então, em vez de criar mais um aplicativo ou uma interface para acompanhar as contas, a ideia foi simples:
Planilha → Apps Script → Google Calendar → Calendário do iPhone
A planilha continua sendo responsável pelos dados.
O calendário passa a ser responsável pela visualização dos próximos vencimentos e pelos alertas.
E o melhor: o Google Calendar sincroniza com o aplicativo Calendário do iPhone.
Como funciona a automação
A automação foi feita utilizando o Google Apps Script, que permite executar JavaScript integrado aos serviços do Google.
O fluxo ficou assim:
Google Sheets
↓
Apps Script
↓
Google Calendar
↓
Calendário do iPhone
↓
Widget / Siri / notificações
O script lê cada linha da planilha, verifica se já existe um evento correspondente e:
- cria o evento se ele ainda não existir;
- atualiza o evento se ele já existir;
- evita eventos duplicados;
- mantém um identificador único para cada despesa;
- coloca o valor e o status dentro do evento;
- configura um lembrete para um dia antes do vencimento.
1. Prepare sua planilha
No projeto utilizado neste artigo:
E → ITEM
F → VENCIMENTO
G → VALOR
H → STATUS
I → ID_CALENDAR
Exemplo:
| ITEM | VENCIMENTO | VALOR | STATUS |
|---|---|---|---|
| Faculdade | 12/08/2026 | R$ 260,00 | A VENCER |
| Seguro | 13/08/2026 | R$ 235,00 | A VENCER |
| Condomínio | 15/08/2026 | R$ 150,00 | A VENCER |
A coluna ID_CALENDAR é utilizada para identificar permanentemente cada despesa.

2. Crie o Apps Script
Na planilha, acesse:
Extensões → Apps Script
Crie o projeto e cole o código completo abaixo.
O script cria automaticamente um menu chamado 📅 Calendário Financeiro, com opções como:
- 🔄 Sincronizar agora
- 🧹 Limpar duplicados
- 🔎 Diagnosticar planilha
- 📋 Ver calendário configurado

Código completo (Apps Script)
/*******************************************************
* SINCRONIZAÇÃO DE DESPESAS COM GOOGLE CALENDAR
*
* E = ITEM
* F = VENCIMENTO
* G = VALOR
* H = STATUS
* I = ID_CALENDAR
*******************************************************/
const CONFIG = {
CALENDAR_NAME: '💰 Vencimentos Financeiros',
ITEM_COL: 5,
VENCIMENTO_COL: 6,
VALOR_COL: 7,
STATUS_COL: 8,
ID_COL: 9,
FIRST_DATA_ROW: 2,
REMINDER_DAYS_BEFORE: 1,
EVENT_PREFIX: '💰 Vencimento — ',
EVENT_ID_PREFIX: 'ID_CALENDAR: ',
OLD_EVENT_ID_PREFIX: 'ID_DESPESA: '
};
function onOpen() {
SpreadsheetApp
.getUi()
.createMenu('📅 Calendário Financeiro')
.addItem('🔄 Sincronizar agora', 'sincronizarDespesas')
.addItem('🧹 Limpar duplicados', 'limparEventosDuplicados')
.addItem('🔎 Diagnosticar planilha', 'diagnosticarPlanilha')
.addItem('📋 Ver calendário configurado', 'mostrarCalendario')
.addToUi();
}
function sincronizarDespesas() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const calendar = obterOuCriarCalendario();
const sheets = ss.getSheets();
let totalCriados = 0;
let totalAtualizados = 0;
let totalIgnorados = 0;
let totalEncontrados = 0;
let totalDuplicadosRemovidos = 0;
let totalIdsCriados = 0;
sheets.forEach(function(sheet) {
const nomeAba = sheet.getName();
const ultimaLinha = sheet.getLastRow();
if (ultimaLinha < CONFIG.FIRST_DATA_ROW) {
return;
}
const quantidadeLinhas =
ultimaLinha - CONFIG.FIRST_DATA_ROW + 1;
const dados =
sheet
.getRange(
CONFIG.FIRST_DATA_ROW,
CONFIG.ITEM_COL,
quantidadeLinhas,
5
)
.getValues();
dados.forEach(function(linha, index) {
const linhaPlanilha =
CONFIG.FIRST_DATA_ROW + index;
const item = linha[0];
const vencimento = linha[1];
const valor = linha[2];
const status = linha[3];
let idCalendar = linha[4];
if (
item === null ||
item === undefined ||
String(item).trim() === ''
) {
totalIgnorados++;
return;
}
if (
String(item)
.trim()
.toUpperCase() === 'TOTAL'
) {
totalIgnorados++;
return;
}
if (
!vencimento ||
!(vencimento instanceof Date) ||
isNaN(vencimento.getTime())
) {
totalIgnorados++;
return;
}
totalEncontrados++;
const idAntigo =
criarIdDespesaAntigo(
nomeAba,
linhaPlanilha,
item
);
if (
idCalendar === null ||
idCalendar === undefined ||
String(idCalendar).trim() === ''
) {
idCalendar = Utilities.getUuid();
sheet
.getRange(
linhaPlanilha,
CONFIG.ID_COL
)
.setValue(idCalendar);
totalIdsCriados++;
} else {
idCalendar = String(idCalendar).trim();
}
const eventos =
buscarEventosNaData(
calendar,
vencimento
);
let eventosEncontrados =
eventos.filter(function(evento) {
const descricao =
evento.getDescription() || '';
const id =
extrairId(
descricao,
CONFIG.EVENT_ID_PREFIX
);
return id === idCalendar;
});
if (eventosEncontrados.length === 0) {
eventosEncontrados =
eventos.filter(function(evento) {
const descricao =
evento.getDescription() || '';
const id =
extrairId(
descricao,
CONFIG.OLD_EVENT_ID_PREFIX
);
return id === idAntigo;
});
}
if (eventosEncontrados.length > 0) {
const eventoPrincipal =
eventosEncontrados[0];
if (eventosEncontrados.length > 1) {
for (
let i = 1;
i < eventosEncontrados.length;
i++
) {
try {
eventosEncontrados[i]
.deleteEvent();
totalDuplicadosRemovidos++;
} catch (erro) {
Logger.log(
'Erro ao remover duplicado: ' +
erro
);
}
}
}
atualizarEvento(
eventoPrincipal,
item,
vencimento,
valor,
status,
nomeAba,
linhaPlanilha,
idCalendar
);
totalAtualizados++;
} else {
criarEvento(
calendar,
item,
vencimento,
valor,
status,
nomeAba,
linhaPlanilha,
idCalendar
);
totalCriados++;
}
});
});
SpreadsheetApp
.getUi()
.alert(
'✅ Sincronização concluída!\n\n' +
'📊 Despesas encontradas: ' +
totalEncontrados +
'\n\n🟢 Eventos criados: ' +
totalCriados +
'\n🔄 Eventos atualizados: ' +
totalAtualizados +
'\n🧹 Duplicados removidos: ' +
totalDuplicadosRemovidos +
'\n🆔 IDs criados: ' +
totalIdsCriados +
'\n⚪ Linhas ignoradas: ' +
totalIgnorados
);
}
function buscarEventosNaData(calendar, data) {
const inicio = new Date(data);
inicio.setHours(0, 0, 0, 0);
const fim = new Date(data);
fim.setHours(23, 59, 59, 999);
return calendar.getEvents(
inicio,
fim
);
}
function obterOuCriarCalendario() {
const calendars =
CalendarApp.getCalendarsByName(
CONFIG.CALENDAR_NAME
);
if (calendars.length > 0) {
return calendars[0];
}
return CalendarApp.createCalendar(
CONFIG.CALENDAR_NAME
);
}
function criarIdDespesaAntigo(
nomeAba,
linha,
item
) {
return (
nomeAba +
'|' +
linha +
'|' +
String(item).trim()
);
}
function extrairId(
descricao,
prefixo
) {
const linhas =
String(descricao || '')
.split('\n');
for (
let i = 0;
i < linhas.length;
i++
) {
const linha =
linhas[i].trim();
if (
linha.indexOf(prefixo) === 0
) {
return linha
.substring(prefixo.length)
.trim();
}
}
return null;
}
function criarEvento(
calendar,
item,
vencimento,
valor,
status,
nomeAba,
linhaPlanilha,
idCalendar
) {
const titulo =
CONFIG.EVENT_PREFIX +
String(item).trim();
const descricao =
criarDescricao(
item,
valor,
status,
nomeAba,
linhaPlanilha,
idCalendar
);
const evento =
calendar.createAllDayEvent(
titulo,
vencimento,
{
description: descricao
}
);
evento.addPopupReminder(
CONFIG.REMINDER_DAYS_BEFORE *
24 *
60
);
return evento;
}
function atualizarEvento(
evento,
item,
vencimento,
valor,
status,
nomeAba,
linhaPlanilha,
idCalendar
) {
evento.setTitle(
CONFIG.EVENT_PREFIX +
String(item).trim()
);
evento.setDescription(
criarDescricao(
item,
valor,
status,
nomeAba,
linhaPlanilha,
idCalendar
)
);
evento.setAllDayDate(
vencimento
);
evento.removeAllReminders();
evento.addPopupReminder(
CONFIG.REMINDER_DAYS_BEFORE *
24 *
60
);
}
function criarDescricao(
item,
valor,
status,
nomeAba,
linhaPlanilha,
idCalendar
) {
let valorFormatado;
if (
typeof valor === 'number'
) {
valorFormatado =
valor.toLocaleString(
'pt-BR',
{
style: 'currency',
currency: 'BRL'
}
);
} else {
valorFormatado =
String(valor || '');
}
return (
'💰 DESPESA FINANCEIRA\n\n' +
'Item: ' +
item +
'\nValor: ' +
valorFormatado +
'\nStatus: ' +
(status || 'A VENCER') +
'\n\nOrigem:\n' +
'Aba: ' +
nomeAba +
'\nLinha: ' +
linhaPlanilha +
'\n\n' +
CONFIG.EVENT_ID_PREFIX +
idCalendar
);
}
function limparEventosDuplicados() {
const calendar =
obterOuCriarCalendario();
const hoje =
new Date();
const inicio =
new Date(hoje);
inicio.setMonth(
inicio.getMonth() - 12
);
const fim =
new Date(hoje);
fim.setMonth(
fim.getMonth() + 24
);
const eventos =
calendar.getEvents(
inicio,
fim
);
const grupos = {};
eventos.forEach(function(evento) {
const descricao =
evento.getDescription() || '';
const id =
extrairId(
descricao,
CONFIG.EVENT_ID_PREFIX
);
if (!id) {
return;
}
if (!grupos[id]) {
grupos[id] = [];
}
grupos[id].push(evento);
});
let removidos = 0;
Object.keys(grupos).forEach(function(id) {
const grupo =
grupos[id];
if (grupo.length <= 1) {
return;
}
for (
let i = 1;
i < grupo.length;
i++
) {
try {
grupo[i].deleteEvent();
removidos++;
} catch (erro) {
Logger.log(erro);
}
}
});
SpreadsheetApp
.getUi()
.alert(
'🧹 Limpeza concluída!\n\n' +
'Duplicados removidos: ' +
removidos
);
}
function diagnosticarPlanilha() {
const ss =
SpreadsheetApp
.getActiveSpreadsheet();
const sheets =
ss.getSheets();
let resultado =
'DIAGNÓSTICO DA PLANILHA\n\n';
sheets.forEach(function(sheet) {
const nome =
sheet.getName();
const ultimaLinha =
sheet.getLastRow();
resultado +=
'ABA: ' +
nome +
'\n';
resultado +=
'Última linha: ' +
ultimaLinha +
'\n';
if (
ultimaLinha >=
CONFIG.FIRST_DATA_ROW
) {
const quantidade =
Math.min(
ultimaLinha,
10
) -
CONFIG.FIRST_DATA_ROW +
1;
const dados =
sheet
.getRange(
CONFIG.FIRST_DATA_ROW,
CONFIG.ITEM_COL,
quantidade,
5
)
.getValues();
dados.forEach(function(linha, i) {
resultado +=
'Linha ' +
(
i +
CONFIG.FIRST_DATA_ROW
) +
': ITEM=' +
linha[0] +
' | DATA=' +
linha[1] +
' | VALOR=' +
linha[2] +
' | STATUS=' +
linha[3] +
' | ID=' +
linha[4] +
'\n';
});
}
resultado +=
'\n----------------------\n\n';
});
Logger.log(resultado);
SpreadsheetApp
.getUi()
.alert(
resultado.substring(
0,
5000
)
);
}
function mostrarCalendario() {
const calendars =
CalendarApp.getCalendarsByName(
CONFIG.CALENDAR_NAME
);
if (
calendars.length === 0
) {
SpreadsheetApp
.getUi()
.alert(
'Calendário não encontrado.'
);
return;
}
SpreadsheetApp
.getUi()
.alert(
'Calendário encontrado:\n\n' +
calendars[0].getName()
);
}
3. O calendário é criado automaticamente
Uma das partes da implementação é a criação automática do calendário.
O script procura por:
💰 Vencimentos Financeiros
Se o calendário já existir, utiliza o existente. Caso contrário, cria um novo.
4. A primeira sincronização
Depois de autorizar o Apps Script a acessar o Google Sheets e o Google Calendar, basta utilizar:
📅 Calendário Financeiro → 🔄 Sincronizar agora
O script percorre as abas e verifica os registros.
Linhas vazias e a linha TOTAL são ignoradas.
Para cada despesa válida:
- se não existir evento correspondente, cria;
- se existir, atualiza.
5. Como fica o evento
O título segue este padrão:
💰 Vencimento — FACULDADE
O evento é criado como evento de dia inteiro.
A descrição contém o item, valor, status, origem na planilha e o identificador ID_CALENDAR.
Além disso, o script configura um lembrete para um dia antes do vencimento.

6. E finalmente: o iPhone
Depois que o Google Calendar está sincronizado com o Calendário do iPhone, os vencimentos aparecem junto com os outros compromissos.


Na prática, posso olhar o widget e já saber o que está próximo.
Também posso perguntar à Siri quais eventos tenho nos próximos dias.
Isso muda a experiência: não preciso abrir a planilha para descobrir o que vence nesta semana.
O que mudou no meu uso da planilha
A planilha não deixou de ser necessária. Ela simplesmente deixou de ser minha interface principal para consultar vencimentos.
- Para cadastrar ou alterar algo: Google Sheets.
- Para saber o que está vencendo: Calendário.
- Para receber lembretes: iPhone.
- Para consultar os próximos compromissos por voz: Siri.
E quando uma conta é paga?
A planilha continua sendo a fonte de verdade.
Quando uma conta é paga, altero:
STATUS: PAGO
e sincronizo novamente.
O evento correspondente é atualizado e passa a mostrar o novo status.
Por que usar um ID?
Cada linha recebe um identificador único com Utilities.getUuid().
Isso evita depender apenas do nome da despesa. Assim, mesmo que existam despesas com nomes semelhantes ou que um nome seja alterado, o script consegue relacionar o evento correto à linha correta.
E se aparecerem eventos duplicados?
O script possui a opção 🧹 Limpar duplicados.
Ela procura eventos que possuem o mesmo ID_CALENDAR e mantém apenas um.
O resultado
A arquitetura final é:
Google Sheets
↓
Apps Script
↓
Google Calendar
↓
iPhone
├── Widget
├── Alertas
└── Siri
O interessante é que não foi necessário criar um aplicativo financeiro.
A planilha continua fazendo aquilo que faz bem. O Google Calendar cuida da agenda e o iPhone vira a camada de consulta e notificações.
No meu caso, isso resolveu exatamente o problema: parei de depender da planilha para lembrar das contas.
Agora uso uma ferramenta que já faz parte da minha rotina todos os dias: o calendário.
O que você precisa
- Uma conta Google
- Google Sheets
- Google Calendar
- iPhone, caso queira usar Calendário/Siri
- Google Apps Script
- A planilha que você já utiliza
Para continuar
Se você está montando outras automações no ecossistema Google, explore também a categoria Google Workspace e a área de Tecnologia. Dúvidas ou correções: envie feedback.
