Google Sheets + Google Chat: milestone posts done
Someone forgets a birthday. Or an anniversary. It’s never malicious, but it always lands the same way: awkward silence, then a rushed “oops” message that feels… thin.
This Sheets Chat automation hits People Ops first, but office managers and agency leads feel it too. You want consistent culture moments without babysitting a calendar every morning.
This workflow scans your employee sheet daily, uses Gemini to write a fresh celebration note, posts it to Google Chat, and logs what happened so you don’t double-post. You’ll see exactly how it works, what you need, and where teams usually trip up.
How This Automation Works
The full n8n workflow, from trigger to final output:
n8n Workflow Template: Google Sheets + Google Chat: milestone posts done
flowchart LR
subgraph sg0["Scheduled Anniversary Start Flow"]
direction LR
n4@{ icon: "mdi:play-circle", form: "rounded", label: "Scheduled Anniversary Start", pos: "b", h: 48 }
n5@{ icon: "mdi:swap-vertical", form: "rounded", label: "Iterate Anniversary Records", pos: "b", h: 48 }
n6@{ icon: "mdi:brain", form: "rounded", label: "Gemini Chat Engine 2", pos: "b", h: 48 }
n7@{ icon: "mdi:robot", form: "rounded", label: "Compose Anniversary Note", pos: "b", h: 48 }
n9@{ icon: "mdi:swap-vertical", form: "rounded", label: "Assign Anniversary Settings", pos: "b", h: 48 }
n11@{ icon: "mdi:swap-vertical", form: "rounded", label: "Capture Today Date", pos: "b", h: 48 }
n12["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Post Anniversary Chat"]
n15@{ icon: "mdi:database", form: "rounded", label: "Retrieve Anniversary Dates", pos: "b", h: 48 }
n17["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Parse Anniversary Data"]
n18@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Anniversary Status Check", pos: "b", h: 48 }
n20@{ icon: "mdi:database", form: "rounded", label: "Log Anniversary Event", pos: "b", h: 48 }
n11 --> n17
n12 --> n20
n15 --> n11
n20 --> n5
n5 --> n7
n17 --> n18
n9 --> n15
n4 --> n9
n7 --> n12
n18 --> n5
n6 -.-> n7
end
subgraph sg1["Scheduled Automation Start Flow"]
direction LR
n0@{ icon: "mdi:play-circle", form: "rounded", label: "Scheduled Automation Start", pos: "b", h: 48 }
n1@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Birthday Status Check", pos: "b", h: 48 }
n2@{ icon: "mdi:swap-vertical", form: "rounded", label: "Iterate Birthday Records", pos: "b", h: 48 }
n3@{ icon: "mdi:brain", form: "rounded", label: "Gemini Chat Engine", pos: "b", h: 48 }
n8@{ icon: "mdi:robot", form: "rounded", label: "Compose Birthday Note", pos: "b", h: 48 }
n10@{ icon: "mdi:swap-vertical", form: "rounded", label: "Assign Birthday Settings", pos: "b", h: 48 }
n13["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Post Birthday Chat"]
n14["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Parse Birthday Data"]
n16@{ icon: "mdi:database", form: "rounded", label: "Retrieve Birthday Dates", pos: "b", h: 48 }
n19@{ icon: "mdi:database", form: "rounded", label: "Log Birthday Event", pos: "b", h: 48 }
n13 --> n19
n10 --> n16
n19 --> n2
n16 --> n14
n14 --> n1
n2 --> n8
n8 --> n13
n0 --> n10
n1 --> n2
n3 -.-> n8
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n4,n0 trigger
class n7,n8 ai
class n6,n3 aiModel
class n18,n1 decision
class n15,n20,n16,n19 database
class n12,n13 api
class n17,n14 code
classDef customIcon fill:none,stroke:none
class n12,n17,n13,n14 customIcon
The Problem: Milestones Get Missed (or Feel Copy-Pasted)
Employee milestones are “small” until they’re not. A missed birthday can sit with someone all day, especially in smaller teams where recognition is part of retention. Even when you do remember, writing a thoughtful note every time becomes one more open tab in a morning that already has too many. And if you reuse last month’s message template, people notice. The worst version is the double-post: a well-meaning follow-up that turns a celebration into noise.
It adds up fast. Here’s where it usually breaks down in real teams.
- You end up checking the same Google Sheet over and over, because nobody trusts that “someone else has it.”
- Messages get written at the last minute, which means they sound generic or slightly wrong.
- People post in Google Chat manually, then forget to track it, so duplicates happen the next day.
- Anniversaries are easy to overlook because they don’t live in the same mental calendar as birthdays.
The Solution: Daily Milestone Checks + AI-Written Posts in Google Chat
This workflow acts like an automated HR assistant that never forgets. Each morning, it pulls your employee milestone data from Google Sheets and compares it to today’s date. If birthdays match, it loops through those records, asks Gemini to draft a warm, non-repetitive message, then posts it directly into your chosen Google Chat space. It does the same for work anniversaries on its own daily schedule. After each post, it logs the event back to Google Sheets, which means you have a simple audit trail and far fewer “did we already do this?” moments. Frankly, it’s the kind of background automation that makes a team feel more cared for without adding work.
The workflow starts with two scheduled triggers (one for birthdays, one for anniversaries). It then parses your sheet data, checks status with simple If logic, generates the message with Gemini, posts via an HTTP Request to Google Chat, and finally logs the result so tomorrow’s run stays clean.
What You Get: Automation vs. Results
| What This Workflow Automates | Results You’ll Get |
|---|---|
|
|
Example: What This Looks Like
Say you have 25 employees and you post celebrations in one Google Chat space. Manually, the routine is usually: check the sheet (about 5 minutes), write a message (about 10 minutes), post it, then note somewhere that it’s done (another 5 minutes). That’s roughly 20 minutes per milestone, and in a typical month you might have 6–8 birthdays and anniversaries combined, so you’re spending about 2 hours just keeping up. With this workflow, you spend about 10 minutes once to confirm the sheet columns and Google Chat Space ID, then it runs daily on its own.
What You’ll Need
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Google Sheets for the employee milestone source of truth.
- Google Chat to post celebrations into a Space.
- Google Gemini (PaLM/Gemini) API access for message writing.
- Google Chat API key/token (from Google Cloud Console API credentials).
Skill level: Beginner. You’ll connect accounts, paste IDs/tokens, and confirm your sheet columns match what the workflow expects.
Don’t want to set this up yourself? Talk to an automation expert (free 15-minute consultation).
How It Works
A daily schedule kicks things off. The workflow runs on a schedule (separately for birthdays and anniversaries), so you’re not relying on someone to “remember to run it.”
Your milestone data is pulled from Google Sheets. It retrieves birthday and joining-date columns, then normalizes the dates against “today” so matching is reliable even if your sheet formatting is a little inconsistent.
Gemini writes the message for each person. Records are processed in batches, and each milestone gets a fresh prompt-driven message. That’s how you avoid the same stale line showing up every month.
Google Chat gets the post, then the run is logged. The workflow sends the final text into your chosen Space via an HTTP request, and then writes a log row back to Google Sheets so you can trace what was sent and when.
You can easily modify the message style to match your brand voice based on your needs. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Scheduled Trigger
Set up the two schedule triggers to run daily so the workflow checks birthdays and anniversaries at the correct time.
- Open Scheduled Automation Start and set the schedule rule to run at
9(Trigger at hour 9). - Open Scheduled Anniversary Start and set the schedule rule to run at
9(Trigger at hour 9). - Confirm the execution flow: Scheduled Automation Start → Assign Birthday Settings and Scheduled Anniversary Start → Assign Anniversary Settings.
Step 2: Connect Google Sheets
Connect the Google Sheets data sources and logging destinations for birthdays, anniversaries, and event tracking.
- Open Retrieve Birthday Dates and select your Google Sheets file and sheet list. The Document is
Copy of N8N Wishes Exceland the Sheet isBirthday List. - Open Retrieve Anniversary Dates and select your Google Sheets file and sheet list. The Document is
Copy of N8N Wishes Exceland the Sheet isWork Anni. - Open Log Birthday Event and confirm Operation is set to
appendwith fields: TimeStamp ={{ $now }}, Event Type =Birthday, Employee Name ={{ $('Iterate Birthday Records').first().json["EMPLOYEE NAME "] }}. - Open Log Anniversary Event and confirm Operation is set to
appendwith fields: TimeStamp ={{ $now }}, Event Type =Anniversary, Employee Name ={{ $('Iterate Anniversary Records').first().json.matches[0].name }}. - Credential Required: Connect your googleSheetsOAuth2Api credentials to Retrieve Birthday Dates, Retrieve Anniversary Dates, Log Birthday Event, and Log Anniversary Event.
Step 3: Set Up Settings and Data Parsing
Configure organization settings and ensure date parsing logic is aligned with your sheet headers.
- Open Assign Birthday Settings and set: Agency Name to
[YOUR_AGENCY], google chat api key to[CONFIGURE_YOUR_API_KEY], google chat space id to[YOUR_ID], and google chat token to[CONFIGURE_YOUR_TOKEN]. - Open Assign Anniversary Settings and set the same four fields with your anniversary-specific values.
- Open Capture Today Date and confirm todayIso is set to
{{$today}}and Include Other Fields is enabled. - Open Parse Birthday Data and verify your birthday column header matches
Employee DOBin the code. - Open Parse Anniversary Data and verify your join date header matches
Date Joined \n(dd-MMM-yyyy)orDate Joined. - Confirm conditional routing: Parse Birthday Data → Birthday Status Check and Parse Anniversary Data → Anniversary Status Check.
Employee DOB or Date Joined \n(dd-MMM-yyyy), the parsing nodes will return no matches.Step 4: Set Up AI Message Generation
Connect Gemini and ensure each LLM node uses the correct prompt and data references.
- Open Compose Birthday Note and keep the prompt text as-is, including expressions like
{{ $json['EMPLOYEE NAME '] }}and{{ $('Assign Birthday Settings').item.json['Agency Name'] }}. - Open Compose Anniversary Note and keep the prompt text as-is, including expressions like
{{ $json.matches[0].name }},{{ $json.matches[0].yearsOfService }}, and{{ $('Assign Anniversary Settings').first().json['Agency Name'] }}. - Confirm the language model connections: Gemini Chat Engine is connected to Compose Birthday Note and Gemini Chat Engine 2 is connected to Compose Anniversary Note.
- Credential Required: Connect your googlePalmApi credentials to Gemini Chat Engine and Gemini Chat Engine 2. These credentials are added to the parent nodes, not the chain nodes.
Step 5: Configure Message Posting and Logging
Ensure messages post to Google Chat and each event is logged for auditing.
- Open Post Birthday Chat and confirm URL uses
https://chat.googleapis.com/v1/spaces/{{ $('Assign Birthday Settings').item.json['google chat space id'] }}/messages?key={{ $('Assign Birthday Settings').item.json['google chat api key'] }}&token={{ $('Assign Birthday Settings').item.json['google chat token'] }}. - In Post Birthday Chat, set Method to
POSTand JSON Body to{"text": {{ JSON.stringify($json.text) }}}. - Open Post Anniversary Chat and confirm URL uses
https://chat.googleapis.com/v1/spaces/{{ $('Assign Anniversary Settings').item.json['google chat space id'] }}/messages?key={{ $('Assign Anniversary Settings').item.json['google chat api key'] }}&token={{ $('Assign Anniversary Settings').item.json['google chat token'] }}. - In Post Anniversary Chat, set Method to
POSTand JSON Body to{"text": {{ JSON.stringify($json.text) }}}. - Verify the loop order: Iterate Birthday Records → Compose Birthday Note → Post Birthday Chat → Log Birthday Event and Iterate Anniversary Records → Compose Anniversary Note → Post Anniversary Chat → Log Anniversary Event.
Step 6: Test and Activate Your Workflow
Run a manual test to verify the end-to-end flow before scheduling it for production use.
- Click Execute Workflow and trigger Scheduled Automation Start or Scheduled Anniversary Start manually to test each branch.
- Confirm successful execution looks like: a generated message in Post Birthday Chat or Post Anniversary Chat, followed by a new row in Log Birthday Event or Log Anniversary Event.
- If no events are found, validate that Birthday Status Check and Anniversary Status Check are correctly matching
NO_BIRTHDAY_TODAYandNO_ANNIVERSARY_TODAY. - Once tests pass, switch the workflow to Active so the schedules run daily at 9 AM.
Common Gotchas
- Google Sheets credentials can expire or lack access to the right spreadsheet. If things break, check the n8n credential connection status and the sheet sharing permissions first.
- If you’re using Wait nodes or external rendering, processing times vary. Bump up the wait duration if downstream nodes fail on empty responses.
- Default prompts in AI nodes are generic. Add your brand voice early or you’ll be editing outputs forever.
Frequently Asked Questions
About 30 minutes if your Google accounts and sheet are ready.
No. You will mainly connect accounts and paste a few IDs and tokens.
Yes. n8n has a free self-hosted option and a free trial on n8n Cloud. Cloud plans start at $20/month for higher volume. You’ll also need to factor in Gemini API usage costs, which are usually small for short messages.
Two options: n8n Cloud (managed, easiest setup) or self-hosting on a VPS. For self-hosting, Hostinger VPS is affordable and handles n8n well. Self-hosting gives you unlimited executions but requires basic server management.
Yes, and it’s the best part. You can adjust the wording inside the “Compose Birthday Note” and “Compose Anniversary Note” Gemini chain nodes, then reuse the same structure to post into a different Google Chat Space. Common customizations include adding your company values, including emojis or not, and tagging a manager for anniversaries. If you want to post somewhere else (like Slack), you keep the Google Sheets + date logic and swap the posting node.
Usually it’s an API key/token issue or the Space ID is wrong. Regenerate or recheck your Google Chat API credentials in Google Cloud, then update the values in the workflow settings nodes (the ones where you enter the Space ID, key, and token). Also confirm the API is enabled for the right Google Cloud project. If it works once and then fails later, rate limits can show up when you process a lot of records in one run.
For most small teams, it handles the full employee list easily because it only posts when dates match. On n8n Cloud Starter, you can run thousands of executions per month, and this workflow usually uses just a handful per day unless you have many milestones at once. If you self-host, there’s no execution cap (it mainly depends on your server). Practically, even a few hundred employees is fine for daily scans and a small batch of posts.
Often, yes, because this workflow needs looping, conditional checks, and clean logging without paying extra for every branch. n8n also gives you a self-hosting option, which matters when you want predictable costs. Zapier or Make can still work if you keep it very simple, but AI + batching + logging tends to get messy fast. If you’re already deep in Google Workspace, n8n’s flexibility is a real advantage. Talk to an automation expert if you want a quick recommendation for your setup.
Once this is running, milestones stop being a thing you “try to remember.” The workflow handles the repetitive parts, and your team gets the consistency they deserve.
Need Help Setting This Up?
Our automation experts can build and customize this workflow for your specific needs. Free 15-minute consultation—no commitment required.