Connect your nself backend to Google Workspace. Read and send Gmail, manage Google Calendar events, browse Google Drive files, and read and write Google Sheets, all through a single OAuth flow stored server-side.
nself-google is part of the ɳClaw bundle. Set your key with nself license set nself_pro_... before installing.
nself license set nself_pro_...
nself plugin install google
nself build
nself starthttps://your-domain.com/google/auth/callback..env.| Variable | Required | Description |
|---|---|---|
PLUGIN_GOOGLE_CLIENT_ID | Yes | OAuth 2.0 Client ID from Google Cloud Console |
PLUGIN_GOOGLE_CLIENT_SECRET | Yes | OAuth 2.0 Client Secret from Google Cloud Console |
PLUGIN_GOOGLE_CLIENT_ID=123456789-xxxxx.apps.googleusercontent.com
PLUGIN_GOOGLE_CLIENT_SECRET=GOCSPX-xxxxx# Step 1: Get the OAuth URL (include the user_id you want to link)
curl "http://127.0.0.1:3719/google/auth/url?user_id=user-uuid"
# Returns: { "url": "https://accounts.google.com/o/oauth2/..." }
# Step 2: Redirect the user to that URL
# Step 3: After consent, Google redirects to /google/auth/callback
# The plugin stores the refresh token automatically, no further action needed# List Gmail messages
curl "http://127.0.0.1:3719/google/gmail/messages?user_id=user-uuid"
# List Calendar events
curl "http://127.0.0.1:3719/google/calendar/events?user_id=user-uuid"
# List Drive files
curl "http://127.0.0.1:3719/google/drive/files?user_id=user-uuid"
# Read a Google Sheet
curl "http://127.0.0.1:3719/google/sheets/SPREADSHEET_ID?user_id=user-uuid"| Endpoint | Method | Description |
|---|---|---|
/google/auth/url | GET | Get OAuth consent URL for a user |
/google/auth/callback | GET | OAuth callback, stores refresh token (called by Google) |
/google/gmail/messages | GET | List Gmail messages for a user |
/google/gmail/send | POST | Send an email via Gmail |
/google/calendar/events | GET | List upcoming calendar events |
/google/calendar/events | POST | Create a calendar event |
/google/drive/files | GET | List Drive files and folders |
/google/sheets/:id | GET | Read rows from a Google Sheet |
/google/sheets/:id | POST | Append rows to a Google Sheet |
/google/health | GET | Check plugin health and OAuth configuration |
| API | Capabilities | Scope required |
|---|---|---|
| Gmail | Read messages, send email, manage labels | gmail.modify |
| Google Calendar | List and create events across all calendars | calendar |
| Google Drive | List files, read metadata, download files | drive.readonly |
| Google Sheets | Read and append rows in any spreadsheet | spreadsheets |
The plugin requests all scopes during the initial OAuth consent. Users see a single permissions screen covering all enabled APIs.
The plugin creates a dedicated np_google schema. These tables are auto-tracked by Hasura and accessible via GraphQL.
| Table | Key Columns | Purpose |
|---|---|---|
np_google.tokens | user_id, access_token, refresh_token, scopes, expires_at, connected_at | Stores per-user OAuth tokens. One row per linked Google account. |
np_google.sync_log | id, user_id, api, operation, status, error_message, created_at | API call history for debugging and rate-limit analysis. |
# Check which users have connected Google accounts
query ConnectedAccounts {
np_google_tokens(where: { expires_at: { _gt: "now()" } }) {
user_id
scopes
connected_at
}
}
# Audit recent API calls
query RecentSync {
np_google_sync_log(
order_by: { created_at: desc }
limit: 20
where: { status: { _eq: "error" } }
) {
user_id
api
operation
error_message
created_at
}
}These events are published to the nself event bus and can be consumed by nself-mux rules.
| Event | Trigger | Payload fields |
|---|---|---|
google.auth.connected | User completes OAuth consent | user_id, scopes, connected_at |
google.auth.revoked | Token revoked or expired and not refreshable | user_id, reason |
google.gmail.sent | Email sent via /google/gmail/send | user_id, to, subject, message_id |
google.calendar.event.created | Event created via /google/calendar/events POST | user_id, event_id, title, start |
google.api.error | Any Google API call returns a 4xx/5xx | user_id, api, status_code, message |
| Option | Cost | Data ownership | Self-hostable |
|---|---|---|---|
| Google Workspace Marketplace app | Varies — $5–30/user/mo | Vendor holds tokens | No |
| Zapier Google integrations | $19–69/mo + per-task fees | Zapier holds tokens | No |
| n8n Google nodes (cloud) | $24–50/mo | n8n cloud holds tokens | Yes (self-hosted tier) |
| nself-google | $0.99/mo (ɳClaw bundle) | Your Postgres — full control | Yes — on your VPS |
Make sure the OAuth Client ID type is set to Web application (not Desktop or TV). The redirect URI must exactly match https://your-domain.com/google/auth/callback — trailing slashes matter.
invalid_grant after token storedThis means the refresh token was revoked — either by the user in their Google Account settings, or because your OAuth app is in “testing” mode (tokens expire after 7 days). Publish the app in Google Cloud Console to issue permanent tokens.
If you enabled the Gmail API after the user already authenticated, their stored token won't include gmail.modify scope. Delete the row from np_google.tokens for that user and have them re-authorize via /google/auth/url.
curl http://127.0.0.1:3719/google/health
# Check PLUGIN_GOOGLE_CLIENT_ID and PLUGIN_GOOGLE_CLIENT_SECRET are set
nself config get | grep PLUGIN_GOOGLEGmail and Calendar have per-user quotas (250 quota units/second for Gmail). Check np_google.sync_log for status: "error" rows with HTTP 429. Add exponential backoff in your calling code or use nself-cron to spread API calls across time.
nself plugin remove googlePort: 3719 | Bundle: ɳClaw ($0.99/mo) or ɳSelf+ ($3.99/mo) | Last Updated: May 2026 | Plugin Version 1.1.0