Google Drive sync to Graniite
Auto-ingest any file dropped into a watched Drive folder. PDFs, audio, video, and text routed by type.
Drop a PDF, audio clip, or video into a watched Google Drive folder. Within minutes, the content is searchable in your Graniite library. PDFs are text-extracted, media is transcribed, and everything is indexed.
What you are building
[New file lands in watched Drive folder]
|
v
[n8n Drive trigger fires with file metadata and download URL]
|
v
[n8n IF node: route by MIME type]
|
+--> URL-ingestable (audio, video, public PDF)
| |
| v
| [POST /api/v1/ingest with kind=url]
|
+--> Binary upload required (private file, image)
|
v
[Three-step upload: signed-URL, PUT, finalize]The branch matters because Drive files are not always publicly fetchable. If your file lives in a folder shared with "anyone with link," Graniite can fetch the URL directly. If it is truly private, you need to download via Drive's API (authenticated as you) and upload the bytes to Graniite via the binary flow.
Prerequisites
- Google Drive with a folder you will designate as the "auto-ingest" inbox. Create a new folder, for example Graniite intake.
- n8n with Google Drive credentials connected. Other no-code tools work (Make, Pipedream, Zapier). The trigger setup varies but the HTTP body shapes do not.
- A Graniite token. Mint at
/settings/integrations:- Capabilities:
readandwrite - Access: Whole library, so the workflow can file items into different folders based on content type.
- Auto-revoke after: 90 days
- Capabilities:
- Graniite credential in n8n: Header Auth, name
Graniite, headerAuthorization: Bearer lev_….
Step 1: n8n Drive trigger
- Create a new workflow with a Google Drive Trigger node.
- Event: File Created (or Files in Folder Created, depending on n8n version).
- Folder: select your Graniite intake folder.
- Watch For: Files in this Folder (not subfolders).
- Poll every: 1 minute is a sane default. Tighter is possible on paid n8n plans.
The trigger payload includes id, name, mimeType, webViewLink, webContentLink (sometimes), and size (in bytes).
Step 2: make the file fetchable
This is the one Drive-specific step. Two patterns work.
Pattern A: public link (simpler)
If you accept "anyone with the link" sharing for files in this folder:
-
Add a Google Drive: Update File Permissions node after the trigger.
-
Set Role to
readerand Type toanyone. -
The file is now fetchable at:
https://drive.google.com/uc?export=download&id={{ $json.id }}This is the URL you pass to Graniite's ingest endpoint.
Trade-off: anyone with the URL can download. Fine for personal notes. Not appropriate for anything sensitive.
Pattern B: download + binary upload (private)
If files must stay private:
- Add a Google Drive: Download File node. It pulls the bytes into n8n binary data.
- Then proceed with the three-step binary upload flow.
This adds three more nodes but never makes the file public. The recipe below uses Pattern A. Swap in Pattern B if your file sensitivity demands it.
Step 3: route by MIME type
Add an IF node after the Drive trigger:
| Condition | Branch |
|---|---|
mimeType starts with audio/ or video/ | Media branch |
mimeType is application/pdf or starts with image/ | Document branch |
| Otherwise (Google Docs, Sheets, text, and so on) | Text branch |
Each branch hits /api/v1/ingest with slightly different metadata. Merge them via a Merge node at the end.
Step 4: Media, Document, and Text ingest
For each branch, add an HTTP Request node:
| Field | Value |
|---|---|
| Method | POST |
| URL | https://graniite.co/api/v1/ingest |
| Authentication | Header Auth credential Graniite |
| Body Content Type | JSON |
Media branch (audio and video)
{
"kind": "url",
"url": "https://drive.google.com/uc?export=download&id={{ $json.id }}",
"in_kb": true,
"auto_transform": false
}Returns status: "transcribing". Graniite passes the URL to AssemblyAI. Transcription typically completes within 30 to 120 seconds depending on file length.
Document branch (PDF and image)
PDFs work the same way as audio. Pass the URL and Graniite extracts the text:
{
"kind": "url",
"url": "https://drive.google.com/uc?export=download&id={{ $json.id }}",
"in_kb": true,
"auto_transform": false
}Returns status: "ready" (no transcription needed). Images go through Claude vision OCR.
Text branch (Google Docs)
Google Docs are not directly URL-fetchable as plain text. Two options:
Option 1: Add a Google Drive: Export File node before the HTTP Request, exporting the Doc as text/plain. Then ingest with kind: "text":
{
"kind": "text",
"title": "{{ $json.name }}",
"text": "{{ $json.exported_content }}",
"in_kb": true,
"auto_transform": false
}Option 2: Skip Google Docs entirely. Only watch the folder for files that are not Docs, Sheets, or Slides. Simpler to maintain.
Step 5 (optional): auto-file into folders
Multi-folder and whole-library tokens do not auto-file by default. To land files in specific Graniite folders by content type, add a follow-up HTTP Request after each ingest:
| Field | Value |
|---|---|
| Method | POST |
| URL | https://graniite.co/api/v1/items/{{ $json.user_item_id }}/folders |
| Auth | the same Graniite credential |
| Body (Media branch) | { "folder_ids": ["<your-audio-folder-uuid>"] } |
| Body (Document branch) | { "folder_ids": ["<your-reading-folder-uuid>"] } |
| Body (Text branch) | { "folder_ids": ["<your-notes-folder-uuid>"] } |
Get folder UUIDs by hitting GET /api/v1/folders once and noting the IDs, or via the Graniite UI's URL bar when viewing a folder.
Step 6: test it
Drop a file into your watched Drive folder:
- Wait up to 1 minute (the trigger poll interval).
- Check the n8n Executions tab for a green success run.
- Inspect the HTTP Request output for
user_item_id. - Visit graniite.co/feed. Your item should be there.
Test cases worth covering:
| File type | Expected response | Time to "ready" |
|---|---|---|
| 3 MB PDF | status: ready | About 5 seconds |
| 30 MB MP4 | status: transcribing | About 60 seconds (poll /items/{id} to track) |
| Screenshot PNG | status: ready (Claude vision OCR) | About 10 seconds |
| Google Doc | depends on chosen text branch | About 5 seconds |
Trade-offs and gotchas
File visibility (Pattern A)
Setting anyone with link permission makes files reachable by anyone who guesses the URL. Drive URLs are long and unguessable in practice, but they are not authenticated. Do not drop highly confidential files into a Pattern A folder.
Poll cadence and quota
n8n Cloud free tier has a minimum 1-minute polling interval. Self-hosted n8n can poll faster, but Drive's API rate limits kick in below approximately 15-second intervals. 1 minute is fine for most use cases.
Each file ingest counts against Graniite's transcription quota (audio and video) or transforms quota (image OCR). Monitor at /settings under Usage.
Files that fail extraction
PDFs that are scans without an OCR layer cannot be text-extracted by unpdf. Graniite returns 422 extraction_failed. Fix on the Drive side: run the PDF through OCR (Drive's Open with → Google Docs will do this in-place) before dropping it into the watched folder.
Cleanup
Items ingested from Drive live forever in Graniite unless you delete them. If you treat the watched Drive folder as a temporary inbox (move-on-processed), consider adding a Google Drive: Move File node at the end of the workflow that shuffles the processed file to a "Done" sub-folder so you do not reprocess it on re-runs.
Idempotency
n8n's Drive trigger fires once per file. The file ID is the dedupe key. As long as you do not move files back into the folder, you will not get duplicates.
What this unlocks
- "Drop a research paper into Drive on my phone, then ask Claude about it from my desktop within minutes."
- Family voice memos as searchable family-call history.
- Photographed receipts that are OCR-extracted and searchable as an expense log.
- Combine with the Twilio recipe so business calls and business documents flow into the same library.
Related
- n8n quickstart: the URL-ingest pattern underneath.
- Binary upload quickstart: for Pattern B (private files).
- Folders + memberships API: the endpoint for the optional auto-file step.