If you landed here, you probably typed something like “OpenClaw calendar integration with Google Calendar setup” into your search bar. Same. I spent last weekend wiring my personal Google Calendar into OpenClaw so I could yell “/meet with Sam next Tuesday” in Telegram and have the agent handle the messy bits. The official docs cover the basics, but gloss over a few foot-guns. This post is the blow-by-blow I wish I had.
Why bother marrying OpenClaw and Google Calendar?
Quick pitch:
- Unified chat-first workflow. I already live in Slack & Telegram; forcing myself into Google’s UI breaks flow.
- Cross-tool automations. OpenClaw can pull repo diffs, grep my shell, and now check whether I’m in a meeting before kicking off a deploy.
- Morning briefings. At 07:00 the agent DM’s me today’s agenda with weather and GitHub PRs requiring review. No more tab farming.
- “Find me a free slot” actually works. The scheduling assistant digs through free/busy blocks and proposes options in plain English.
Downsides? A bit of OAuth yak-shaving, and you’ll be storing a refresh token on disk or in ClawCloud’s Secrets Vault. If that scares you, stop here.
Prerequisites and sanity checks
- Node.js 22+ (OpenClaw 0.31.4 currently fails hard on earlier LTS releases)
- A Google account that can create OAuth credentials (G-Suite admin sometimes required)
- OpenClaw gateway ≥ 0.31.0 and daemon ≥ 0.17.0. Check with
npx openclaw --version - On-prem install or an active ClawCloud project. I’ll call out both paths.
- git, jq, and
gcloudCLI if you dislike web consoles.
Step 1 — Create Google Cloud project and enable Calendar API
1.1 Spin up a project
Head to console.cloud.google.com → IAM & Admin / Create Project. Name it “OpenClaw Calendar Bridge”. Don’t overthink the org/folder unless company policy forces you.
1.2 Enable the API
Inside the new project: APIs & Services / Library → search “Google Calendar API” → Enable.
1.3 OAuth consent screen
Still under APIs & Services choose OAuth consent screen.
- App type: Internal if you’re on Google Workspace; else External, testing mode is fine.
- Add yourself as a test user if external.
- Scopes: click “Add or remove scopes” → search calendar → check
.../auth/calendarand.../auth/calendar.events. - Save. Google will gripe about verification; ignore for personal use.
1.4 Create OAuth client ID
- Credentials → Create Credentials → OAuth client ID
- Application type: Web application
- Authorized redirect URI:
http://localhost:3000/auth/google/callback(OpenClaw default) + any ClawCloud URL you plan to use, e.g.https://myagent.claw.run/auth/google/callback - Download the JSON. Google names it
client_secret_XXXXXXXX.json. Keep it safe.
Step 2 — Feed the credentials to OpenClaw
You have two deployment modes. Pick one.
2.1 Local / self-hosted install
- Move the JSON to
~/.config/openclaw/google-oauth.json - Export env vars so the gateway can read them:
export GOOGLE_CLIENT_ID=$(jq -r '.installed.client_id' ~/.config/openclaw/google-oauth.json)
export GOOGLE_CLIENT_SECRET=$(jq -r '.installed.client_secret' ~/.config/openclaw/google-oauth.json)
export GOOGLE_REDIRECT_URI="http://localhost:3000/auth/google/callback"
openclaw gateway --port 3000- Visit
http://localhost:3000/integrations, click Google Calendar, follow the OAuth dance.
2.2 ClawCloud
- Open your project → Settings / Secrets Vault → add three keys:
GOOGLE_CLIENT_ID <value from JSON>
GOOGLE_CLIENT_SECRET <value from JSON>
GOOGLE_REDIRECT_URI https://YOUR_AGENT_ID.claw.run/auth/google/callback
- Redeploy the gateway from the dashboard. The container picks up secrets automatically.
- From the web UI, open Integrations and connect Google Calendar.
If the callback bombs with redirect_uri_mismatch, double-check that the URI is identical in all three places (Google console, env var, and actual browser address).
Step 3 — Validating OAuth and first read
OpenClaw stores the access + refresh token in its encrypted keychain (~/.openclaw/keychain.json for self-host, or ClawCloud’s KMS). To verify:
openclaw shell
> claw integrations list
✔ google-calendar connected
Now ask the agent in chat:
/cal list --next 3
Response should include the next three events with start/end ISO timestamps. If you see 403 insufficient permissions, your scope list in Step 1.3 is incomplete.
Step 4 — Creating and modifying events via chat
The calendar plugin ships with four intents: create_event, update_event, delete_event, find_free_slot. They’re ordinary JSON tools exposed to the agent. Example prompt:
@clawbot book 1h with Alice and Ben tomorrow afternoon about "Q3 roadmap"
Under the hood the LLM will:
- Call
find_free_slotwith constraints (duration 60 min, participants busy times, window 12:00-18:00) - Pick the first free block, then call
create_event
You’ll see a proposed time; reply "yes" to confirm or suggest “make it 3 PM instead”. If confirmation is on (OPENCLAW_REQUIRE_CONFIRM=true), the agent waits. Power users flip it off and trust the bot.
4.1 Updating an event
/cal move "Q3 roadmap" to Friday 10am
The agent does a fuzzy match on the summary plus an events.list query, grabs the eventId, and issues events.patch with new start/end. It will re-run conflict detection (next section) before saving.
Step 5 — Conflict detection & busy-time sanity
OpenClaw treats conflicts in three tiers:
- Hard – you’re explicitly busy. Event creation is aborted.
- Soft – you’re tentatively busy (maybe). Bot asks for confirmation unless overridden.
- Free – no conflict. Proceed.
Internally it calls the freebusy.query endpoint covering your primary calendar + any others listed in OPENCLAW_CAL_FREEBUSY_CALENDARS (comma-sep IDs). Example env var:
export OPENCLAW_CAL_FREEBUSY_CALENDARS="primary,team@company.com"
If you need stricter rules — say, block lunchtimes even when the calendar is blank — create a secondary calendar called Focus, insert recurring events, and add it to the list.
Step 6 — Morning briefing integration
OpenClaw’s scheduler (daemon process) can fire cron-like jobs. I use this crontab to drop a daily agenda in Telegram:
// ~/.openclaw/cron.json
[
{
"id": "morning-briefing",
"schedule": "0 7 * * *",
"tool": "morning_briefing",
"config": {
"channels": ["telegram://@p_stone"],
"include_weather": true,
"include_pending_prs": true,
"days_ahead": 1
}
}
]
The morning_briefing tool bundles:
calendar.events.listfor the nextdays_ahead- Calls to Composio’s GitHub connector (
pulls.list) - Open-weather API (optional)
Output is a nicely formatted message:
⏰ Today: 09:00-09:30 1:1 with Dana 11:00-12:00 Backend sync (Zoom) PRs waiting on you: 3 Temp in Vienna: 16°C, light rain
Good enough that I haven’t opened Google Calendar on mobile in weeks.
Step 7 — Scheduling assistant: "find me a free slot"
The find_free_slot tool accepts:
durationMinuteswindowStart/windowEnd(RFC 3339)participantEmails(optional; requires their calendars to be shared free/busy)minGap(buffer between meetings)
Sample manual call via the gateway’s REST interface (good for testing):
curl -X POST http://localhost:3000/tools/find_free_slot \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"durationMinutes": 60,
"windowStart": "2024-05-20T08:00:00Z",
"windowEnd": "2024-05-24T18:00:00Z",
"participantEmails": ["alice@example.com", "ben@example.com"],
"minGap": 15
}'
The response is an array of RFC 3339 start times. Feed the first entry back into create_event or let the agent handle it automatically.
Edge cases I hit:
- Time-zones matter. The API returns Zulu; convert with
moment.tzor rely on the chat client to localise. - If a participant’s calendar isn’t shared, Google returns HTTP 404 rather than empty busy slots. The tool suppresses those but logs a warning.
- Large windows (months) can breach Google’s quota. Cap at one week or paginate.
Troubleshooting cheat-sheet
- ERR_BAD_REQUEST 400 “invalid_grant”
Token expired or revoked. Re-link the integration. - Bot says it booked, but event missing
Check if you’re using a secondary calendar. Add"calendarId": "primary"to tool config or env varOPENCLAW_CAL_DEFAULT_ID. - Events off by one hour
Your server TZ != Google account TZ. ExportTZin the gateway’s environment. - OAuth screen stuck on “app not verified”
Click “Advanced → Go to <app> (unsafe)”. For org-wide installs, you’ll need Google to verify scopes; not worth it for internal use.
Next steps
Add GitHub Issues or Notion tasks to the morning briefing. Or wire the scheduling assistant into your CI pipeline so deploys only run when you’re not in a meeting. The building blocks are here; the rest is YAML and a bit of perseverance.