Integrating n8n, Google Gemini, and Google Sheets for Automated Tender Scoring
Procurement teams evaluating RFPs spend hours extracting data from vendor PDFs, cross-referencing requirements, and maintaining scoring consistency. Here's how to architect an n8n workflow that uses Google Gemini to evaluate tender proposals against RFP criteria and output structured scores to Google Sheets.
This integration combines n8n's webhook triggers, Google Drive's file retrieval, PDF text extraction, Google Gemini's AI analysis capabilities, and Google Sheets' data storage. Here's how to architect this integration in n8n.
Architecture Overview
The workflow follows this data flow:
- Vendor submits proposal PDF via n8n Form Trigger → stores binary file data
- Parallel branch: Google Drive API fetches RFP document by file ID
- Extract text from both PDFs using Extract From File node
- Merge streams to provide AI agent with both documents
- Google Gemini API receives structured prompt with RFP + proposal text
- AI returns JSON-formatted evaluation with weighted scores
- Google Sheets API appends evaluation row to dashboard
This architecture separates document retrieval, text processing, AI analysis, and data storage into discrete nodes. Alternative approaches like using OpenAI's API or Anthropic's Claude would require different credential configuration but similar overall structure.
API Integration Deep-Dive
n8n Form Trigger Webhook
The Form Trigger creates a public endpoint that accepts file uploads:
// Form configuration
{
"formTitle": "Tender Response Submission",
"formFields": [
{
"fieldLabel": "Proposal Document (PDF only)",
"fieldType": "file",
"acceptedFileTypes": ".pdf"
}
],
"authentication": "none"
}
When triggered, returns:
{
"Proposal_Document__PDF_only_": {
"data": "[binary data]",
"mimeType": "application/pdf",
"fileName": "vendor-proposal.pdf"
}
}
The binary field name matches the form label with special characters replaced by underscores. Critical for downstream PDF extraction.
Google Drive API Authentication
Requires OAuth2 credential with these scopes:
https://www.googleapis.com/auth/drive.readonlyhttps://www.googleapis.com/auth/drive.file
File download request structure:
GET https://www.googleapis.com/drive/v3/files/{fileId}?alt=media
Headers: {
"Authorization": "Bearer {access_token}"
}
Returns binary file content. The alt=media parameter is essential—without it, you get file metadata instead of content.
Rate limits: 1000 queries per 100 seconds per user. For batch processing, implement exponential backoff on 403 responses.
PDF Text Extraction
The Extract From File node processes binary PDF data:
// Node configuration
{
"operation": "extractFromPDF",
"binaryPropertyName": "data"
}
Outputs:
{
"text": "[extracted text content]",
"pageCount": 15,
"metadata": {...}
}
Gotcha: Text-based PDFs only. Scanned documents or image-heavy PDFs return empty strings. Validate text field length before proceeding to AI analysis.
Google Gemini API Integration
Authentication uses API key from Google Cloud Console:
POST https://generativelanguage.googleapis.com/v1/models/gemini-2.5-flash:generateContent
Headers: {
"Content-Type": "application/json",
"x-goog-api-key": "{API_KEY}"
}
Request body structure:
{
"contents": [{
"parts": [{
"text": "System: You are a rigorous tender evaluation specialist.\n\nUser: Evaluate this proposal against the RFP requirements: [RFP_TEXT]\n\nProposal: [PROPOSAL_TEXT]"
}]
}],
"generationConfig": {
"response_mime_type": "application/json",
"response_schema": {
"type": "object",
"properties": {
"company_name": {"type": "string"},
"score_price": {"type": "number"},
"score_technical": {"type": "number"}
}
}
}
}
Response:
{
"candidates": [{
"content": {
"parts": [{
"text": "{\"company_name\":\"Acme Corp\",\"score_price\":85,\"score_technical\":72}"
}]
},
"finishReason": "STOP"
}],
"usageMetadata": {
"promptTokenCount": 1250,
"candidatesTokenCount": 180
}
}
Critical parameters:
-
response_mime_type: "application/json"forces JSON output -
response_schemadefines exact structure expected - Temperature defaults to 1.0; reduce to 0.3 for more deterministic scoring
Rate limits:
- Free tier: 15 requests/minute
- Paid tier: 1000 requests/minute
- Token limits: 32k input, 8k output for Flash model
Error handling: HTTP 429 on rate limit, 400 on malformed schema. Always validate finishReason === "STOP" before parsing response.
Google Sheets API Data Append
Append operation uses values.append method:
POST https://sheets.googleapis.com/v4/spreadsheets/{spreadsheetId}/values/{range}:append
Headers: {
"Authorization": "Bearer {access_token}",
"Content-Type": "application/json"
}
Body: {
"values": [[
"Acme Corp",
"john@acme.com",
85,
72,
"2026-01-29"
]]
}
With n8n's automatic column mapping enabled, field names must match spreadsheet headers exactly. Case-sensitive.
Quota limits: 500 requests per 100 seconds per project. Batch multiple evaluations if processing bulk proposals.
Implementation Gotchas
Missing PDF Text Content
PDF extraction returns empty string when:
- Document is scanned image (no text layer)
- PDF is password protected
- File is corrupted
Implement validation:
{{ $json.text.length > 100 }}
If false, route to error handler or manual review queue.
Gemini JSON Parsing Failures
Even with structured output, AI occasionally returns malformed JSON:
- Extra markdown code fences ( ```json) - Escaped characters in wrong places - Truncated responses on token limit
The Output Parser's "Auto-Fix Format" handles minor issues. For consistent failures, adjust response_schema complexity or increase output token limit.
Google Drive Permission Errors
HTTP 403 when:
- Credential lacks
drive.readonlyscope - File sharing settings restrict access
- File is in shared drive requiring domain-wide delegation
Test with publicly accessible file first, then adjust sharing settings.
Rate Limiting Strategy
For batch processing 50+ proposals:
- Use n8n's "Split In Batches" node with batch size 10
- Add "Wait" node with 60-second delay between batches
- Implement retry logic with exponential backoff
- Monitor Gemini API usage in Google Cloud Console
Data Validation Before Sheets
Missing fields cause append failures. Validate required fields:
javascript
{{
$json.company_name &&
$json.score_price !== undefined &&
$json.score_technical !== undefined
}}
Route invalid data to separate error logging sheet.
Cost Optimization
Gemini API pricing:
- Input: $0.00025 per 1k characters
- Output: $0.0005 per 1k characters
Typical RFP (5000 chars) + proposal (8000 chars) = ~$0.007 per evaluation. For 100 proposals: ~$0.70.
Reduce costs by:
- Extracting only relevant RFP sections
- Limiting proposal text to first 5000 characters
- Using cached RFP content across evaluations
Prerequisites
Required Accounts:
- n8n instance (self-hosted or cloud)
- Google Cloud project with APIs enabled:
- Google Drive API
- Google Sheets API
- Generative Language API (Gemini)
API Credentials:
- Google OAuth2 credential for Drive/Sheets (setup guide)
- Google Gemini API key (get key)
Data Setup:
- RFP document uploaded to Google Drive (note file ID from URL)
- Google Sheet with headers:
company_name,contact_person,contact_email,total_cost_eur,score_price,score_technical,score_experience,score_timeline,score_warranty,score_innovation,weighted_total,gdpr_compliant,budget_compliant,mandatory_integrations_met,recommendation
Cost Estimates:
- Gemini API: ~$0.007 per evaluation
- Google Drive/Sheets API: Free (within quota limits)
Get the Complete Workflow Configuration
This tutorial covers the API integration architecture and key implementation patterns. For the complete n8n workflow JSON with all node configurations, credential setup instructions, and a video walkthrough, check out the full implementation guide.
Top comments (0)