The Google Drive integration enables your Cognest assistant to manage files and folders in Google Drive. Upload and download files, create folder structures, control sharing permissions, search across your drive, and watch for real-time changes via push notifications. Cognest manages the OAuth 2.0 flow, token refresh, and batches Google API requests to stay within quota limits.
drive.file scope. For full drive access, add drive to the scope list.http://localhost:3000/auth/google/callback as an authorized redirect URI..env file:GOOGLE_DRIVE_CLIENT_ID=123456789-abc.apps.googleusercontent.com
GOOGLE_DRIVE_CLIENT_SECRET=GOCSPX-abcdefghijklmnopOAuth 2.0 Flow
Google Drive uses OAuth 2.0 with authorization code grant. On first run, Cognest opens a browser window for you to authorize access. Tokens are stored encrypted locally and refreshed automatically. Refresh tokens do not expire unless revoked.
Add the Google Drive integration to your cognest.config.yaml:
integrations:
google-drive:
enabled: true
credentials:
client_id: ${GOOGLE_DRIVE_CLIENT_ID}
client_secret: ${GOOGLE_DRIVE_CLIENT_SECRET}
settings:
# OAuth redirect URI (must match Google Cloud Console)
redirect_uri: http://localhost:3000/auth/google/callback
# Scopes to request during authorization
scopes:
- https://www.googleapis.com/auth/drive
- https://www.googleapis.com/auth/drive.file
# Root folder ID to scope operations (optional, defaults to entire drive)
root_folder_id: ""
# Enable push notifications for real-time file change events
watch_changes: true
# Webhook URL for change notifications (required if watch_changes is true)
webhook_url: https://your-domain.com/webhooks/google-drive
# Maximum file upload size in MB (default 100)
max_upload_size_mb: 100import { Cognest } from '@cognest/sdk'
const cognest = new Cognest()
const drive = cognest.integration('google-drive')
// List files in the root folder
const files = await drive.listFiles({ pageSize: 20 })
console.log(files.map((f) => f.name))
await cognest.start()| Method | Parameters | Description |
|---|---|---|
| uploadFile(options) | { name, content, mimeType, folderId?, description? } | Upload a file to Google Drive. Content can be a Buffer, ReadableStream, or file path string. |
| downloadFile(fileId, options?) | fileId: string, options?: { outputPath? } | Download a file by ID. Returns a Buffer or writes to outputPath if provided. |
| listFiles(options?) | options?: { folderId?, pageSize?, query?, orderBy? } | List files in a folder or the entire drive. Supports Google Drive query syntax for filtering. |
| createFolder(options) | { name, parentId?, description? } | Create a new folder. Returns the folder ID and URL. |
| shareFile(fileId, options) | fileId: string, { email, role, type, sendNotification? } | Share a file with a user or group. Role can be 'reader', 'commenter', or 'writer'. |
| deleteFile(fileId, options?) | fileId: string, options?: { permanent? } | Move a file to trash or permanently delete it if permanent is true. |
| searchFiles(query, options?) | query: string, options?: { pageSize?, fields? } | Full-text search across file names and content. Uses the Google Drive search query syntax. |
| watchChanges(options?) | options?: { folderId?, pageToken? } | Start watching for changes on a file or folder. Events are emitted through the event system. |
When watch_changes is enabled, Google Drive sends push notifications to your webhook URL. Cognest processes these notifications and emits typed events:
| Event | Payload | Description |
|---|---|---|
| file:created | { fileId, name, mimeType, createdBy, folderId, createdAt } | Fired when a new file is created in the watched scope. |
| file:modified | { fileId, name, mimeType, modifiedBy, version, modifiedAt } | Fired when a file's content or metadata is updated. |
| file:deleted | { fileId, name, deletedBy, trashedAt } | Fired when a file is moved to trash or permanently deleted. |
| file:shared | { fileId, name, sharedWith, role, sharedBy, sharedAt } | Fired when a file's sharing permissions change. |
drive.on('file:created', async (event) => {
console.log(`New file: ${event.name} (by ${event.createdBy})`)
})
drive.on('file:modified', async (event) => {
console.log(`File updated: ${event.name} — version ${event.version}`)
})
drive.on('file:deleted', async (event) => {
console.log(`File trashed: ${event.name}`)
})
drive.on('file:shared', async (event) => {
console.log(`${event.name} shared with ${event.sharedWith} as ${event.role}`)
})A complete example that automates document management: organizes uploaded files into date-based folders, backs up important changes, and notifies the team via Slack:
import { Cognest } from '@cognest/sdk'
import { readFile } from 'fs/promises'
const cognest = new Cognest()
const drive = cognest.integration('google-drive')
const slack = cognest.integration('slack')
const INBOX_FOLDER = '1AbCdEfGhIjKlMnOpQrStUvWxYz' // "Inbox" folder ID
const ARCHIVE_FOLDER = '0ZyXwVuTsRqPoNmLkJiHgFeDcBa' // "Archive" folder ID
// Auto-organize: move files from inbox to date-based folders
drive.on('file:created', async (event) => {
if (event.folderId !== INBOX_FOLDER) return
const today = new Date()
const folderName = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}`
// Find or create the monthly folder
const existing = await drive.searchFiles(
`name = '${folderName}' and '${ARCHIVE_FOLDER}' in parents and mimeType = 'application/vnd.google-apps.folder'`
)
let targetFolderId: string
if (existing.length > 0) {
targetFolderId = existing[0].id
} else {
const folder = await drive.createFolder({
name: folderName,
parentId: ARCHIVE_FOLDER,
description: `Auto-organized files for ${folderName}`,
})
targetFolderId = folder.id
}
// Move the file (upload a copy and delete original)
const content = await drive.downloadFile(event.fileId)
await drive.uploadFile({
name: event.name,
content,
mimeType: event.mimeType,
folderId: targetFolderId,
})
await drive.deleteFile(event.fileId)
console.log(`Organized ${event.name} into ${folderName}/`)
})
// Notify Slack when important files are shared externally
drive.on('file:shared', async (event) => {
// Only alert if shared with someone outside the organization
if (!event.sharedWith.endsWith('@your-company.com')) {
await slack.sendMessage({
channel: '#security-alerts',
text: `External share detected: "${event.name}" shared with ${event.sharedWith} (${event.role}) by ${event.sharedBy}`,
})
}
})
// Daily backup report
cognest.skill('drive-report', {
schedule: '0 18 * * 1-5', // 6 PM weekdays
handler: async () => {
const recentFiles = await drive.listFiles({
pageSize: 50,
orderBy: 'modifiedTime desc',
})
const todayStart = new Date()
todayStart.setHours(0, 0, 0, 0)
const modifiedToday = recentFiles.filter(
(f) => new Date(f.modifiedTime) >= todayStart
)
await slack.sendMessage({
channel: '#team-updates',
text: [
':file_folder: *Daily Drive Summary*',
`Files modified today: ${modifiedToday.length}`,
...modifiedToday.slice(0, 10).map(
(f) => ` - ${f.name} (last edited by ${f.lastModifyingUser?.displayName ?? 'unknown'})`
),
modifiedToday.length > 10 ? ` ...and ${modifiedToday.length - 10} more` : '',
].filter(Boolean).join('\n'),
})
},
})
// Skill: Upload a local file to a specific Drive folder
cognest.skill('upload-to-drive', {
handler: async ({ params }) => {
const { filePath, folderId, shareWith } = params
const content = await readFile(filePath)
const name = filePath.split('/').pop() ?? 'upload'
const file = await drive.uploadFile({
name,
content,
mimeType: 'application/octet-stream',
folderId,
})
// Optionally share with a collaborator
if (shareWith) {
await drive.shareFile(file.id, {
email: shareWith,
role: 'writer',
type: 'user',
sendNotification: true,
})
}
return { fileId: file.id, url: file.webViewLink }
},
})
await cognest.start()
console.log('Google Drive automation is running...')Common Issues
403 "Insufficient Permission": The OAuth token does not have the required scope. Re-authorize with the correct scopes listed in your config. The drive.file scope only grants access to files created by your app; use the drive scope for full access. 404 "File not found": The file may have been deleted, or the authenticated user does not have access. Shared Drive files require the supportsAllDrives parameter, which Cognest enables automatically. Watch channel expired: Google Drive push notification channels expire after a maximum of 24 hours. Cognest automatically renews the watch channel before expiry. If events stop arriving, check your webhook_url is publicly accessible. Upload quota exceeded: Google Drive API has a limit of 750 GB uploaded per user per 24 hours, and 10 million files per Shared Drive. For bulk uploads, use the rate_limit_strategy: queue setting to spread requests over time. OAuth consent screen "unverified app" warning: During development, your app shows a warning screen. For production, submit your app for Google verification. This is required if you use sensitive scopes like the full drive scope.
Search Query Syntax
Google Drive supports powerful search queries. Examples: - Files by type: mimeType = 'application/pdf' - Files in folder: '1ABC' in parents - Full-text search: fullText contains 'quarterly report' - Modified after: modifiedTime > '2024-01-01T00:00:00' - Combine with AND/OR: mimeType = 'application/pdf' and modifiedTime > '2024-01-01' See the Google Drive API search documentation for the full query reference.