The lead form now posts to /api/leads. The API does the following for every submission:
- Appends lead data to Google Sheets (through a Google Apps Script webhook)
- Sends an instant Telegram alert
- Applies IP-based rate limiting
- Suppresses duplicate submissions by phone within a cooldown window
Create .env.local from .env.example and fill values:
LEADS_GOOGLE_SCRIPT_URL: deployed Google Apps Script Web App URLTELEGRAM_BOT_TOKEN: bot token from BotFatherTELEGRAM_CHAT_ID: target chat/channel id for notificationsLEADS_RATE_LIMIT_WINDOW_MS: rate-limit window in milliseconds (optional)LEADS_RATE_LIMIT_MAX_REQUESTS: max submissions per IP within window (optional)LEADS_DUPLICATE_WINDOW_MS: duplicate suppression window by phone in milliseconds (optional)
Create a Google Sheet with a tab named Leads, then open Apps Script and use:
function doPost(e) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('Leads');
const body = JSON.parse(e.postData.contents || '{}');
sheet.appendRow([
body.timestamp || '',
body.name || '',
body.phone || '',
body.language || '',
body.pageUrl || '',
body.utm_source || '',
body.utm_medium || '',
body.utm_campaign || '',
body.utm_content || '',
body.utm_term || '',
body.ip || '',
body.userAgent || '',
body.origin || '',
]);
return ContentService
.createTextOutput(JSON.stringify({ ok: true }))
.setMimeType(ContentService.MimeType.JSON);
}Deploy as Web App:
- Execute as:
Me - Who has access:
Anyone
Copy the Web App URL into LEADS_GOOGLE_SCRIPT_URL.
npm install
npm run devVite dev server includes /api/leads middleware, so local form testing works without extra backend setup.
This repo includes netlify.toml and a Netlify function at netlify/functions/leads.mjs.
- Frontend calls
/api/leads - Netlify redirects it to
/.netlify/functions/leads
Set the same environment variables in Netlify Site Settings -> Environment variables.
Each alert includes:
- Name
- Click-to-call phone link
- Language code
- Landing page URL
- Condensed UTM summary
- Submission timestamp