DEV Community

Hackceleration
Hackceleration

Posted on • Originally published at hackceleration.com

Building AI-Powered RFP Evaluation with n8n and Google Gemini

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:

  1. Vendor submits proposal PDF via n8n Form Trigger → stores binary file data
  2. Parallel branch: Google Drive API fetches RFP document by file ID
  3. Extract text from both PDFs using Extract From File node
  4. Merge streams to provide AI agent with both documents
  5. Google Gemini API receives structured prompt with RFP + proposal text
  6. AI returns JSON-formatted evaluation with weighted scores
  7. 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"
}
Enter fullscreen mode Exit fullscreen mode

When triggered, returns:

{
  "Proposal_Document__PDF_only_": {
    "data": "[binary data]",
    "mimeType": "application/pdf",
    "fileName": "vendor-proposal.pdf"
  }
}
Enter fullscreen mode Exit fullscreen mode

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.readonly
  • https://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}"
}
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

Outputs:

{
  "text": "[extracted text content]",
  "pageCount": 15,
  "metadata": {...}
}
Enter fullscreen mode Exit fullscreen mode

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}"
}
Enter fullscreen mode Exit fullscreen mode

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"}
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Response:

{
  "candidates": [{
    "content": {
      "parts": [{
        "text": "{\"company_name\":\"Acme Corp\",\"score_price\":85,\"score_technical\":72}"
      }]
    },
    "finishReason": "STOP"
  }],
  "usageMetadata": {
    "promptTokenCount": 1250,
    "candidatesTokenCount": 180
  }
}
Enter fullscreen mode Exit fullscreen mode

Critical parameters:

  • response_mime_type: "application/json" forces JSON output
  • response_schema defines 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"
  ]]
}
Enter fullscreen mode Exit fullscreen mode

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 }}
Enter fullscreen mode Exit fullscreen mode

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.readonly scope
  • 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:

  1. Use n8n's "Split In Batches" node with batch size 10
  2. Add "Wait" node with 60-second delay between batches
  3. Implement retry logic with exponential backoff
  4. 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
}}


Enter fullscreen mode Exit fullscreen mode

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:

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)