You can connect GoHighLevel to Google Sheets, Drive, and Gmail without Make or Zapier — using a Google Apps Script web app as a free webhook receiver that GHL posts data to directly.
GoHighLevel handles CRM, pipelines, email sequences, and funnels well. But most service businesses running GHL haven't left Google Workspace — they still track deals in Sheets, share documents in Drive, and run team communication through Gmail. GHL becomes the front-end; Workspace stays the back-office.
The obvious way to connect them is Make or Zapier. Both work. But you're paying $16–$20/month for middleware that does one job: receive a GHL webhook and write a row to a Sheet. Google Apps Script does the same thing for free, runs on your Google account, and gives you complete control over the data shape.
Here's how to set it up properly — including the parts most tutorials skip over.
GHL has a built-in Custom Webhook workflow action. You configure a GHL workflow to fire when something happens (contact created, stage changed, form submitted, etc.), and it sends a POST request with a JSON payload to any URL you give it.
Google Apps Script can be deployed as a web app — a public HTTPS URL that accepts POST requests. Your Script receives the GHL payload, parses it, and writes to any Google service: Sheets, Drive, Gmail, Calendar, Docs.
No third-party platform sitting in the middle. GHL talks directly to your script.
Open Google Sheets → Extensions → Apps Script. Replace the default code:
function doPost(e) {
try {
var data = JSON.parse(e.postData.contents);
var sheet = SpreadsheetApp
.getActiveSpreadsheet()
.getSheetByName("GHL Leads");
sheet.appendRow([
new Date(),
data.contact_id || "",
data.first_name || "",
data.last_name || "",
data.email || "",
data.phone || "",
data.pipeline_stage_name || "",
data.source || "",
data.tags ? data.tags.join(", ") : ""
]);
return ContentService
.createTextOutput(JSON.stringify({ status: "ok" }))
.setMimeType(ContentService.MimeType.JSON);
} catch (err) {
return ContentService
.createTextOutput(JSON.stringify({ status: "error", message: err.toString() }))
.setMimeType(ContentService.MimeType.JSON);
}
}
A few things happening here that matter:
In Apps Script: Deploy → New Deployment → Web App.
Critical settings:
Copy the web app URL. It looks like: https://script.google.com/macros/s/ABC.../exec
Every time you redeploy after code changes, you get a new URL. If you've already configured GHL with the old URL, you need to update it. This is the single most common cause of silent webhook failures — the script was updated, the URL changed, GHL is still sending to the old one.
To avoid this: keep a named bookmark of the current URL, and whenever you redeploy, update the GHL workflow immediately.
In GoHighLevel: Automation → Workflows → create or open a workflow.
Test with GHL's built-in "Test Workflow" feature. Check your Sheet for a new row within a few seconds.
GHL sends different payloads depending on the trigger. For a contact-based trigger, the typical payload structure is:
{
"contact_id": "abc123",
"first_name": "Jane",
"last_name": "Smith",
"email": "jane@example.com",
"phone": "+1234567890",
"source": "Facebook Ad",
"pipeline_stage_name": "New Lead",
"tags": ["inbound", "facebook"],
"custom_fields": {
"company": "Acme Corp",
"budget": "5000"
}
}
Custom fields are nested under custom_fields. If you need them in your Sheet:
data.custom_fields ? (data.custom_fields.company || "") : ""
Log the raw payload first if you're unsure of the structure. Add a temporary line to your script:
Logger.log(JSON.stringify(data));
Then check Apps Script → Executions to see what GHL actually sent.
1. Apps Script execution quotas
Free Google Workspace accounts get 90 minutes of total script execution time per day. Paid Workspace accounts get 6 hours. Each GHL webhook hit takes roughly 1–3 seconds to run. At 100 webhook events/day you're using 5 minutes — well under the limit. At 2,000 events/day, you're at ~100 minutes. Know your volume before assuming this is free at any scale.
2. GHL doesn't guarantee delivery order
If two webhook events fire within milliseconds of each other (which happens on bulk imports), GHL sends them both immediately. Apps Script is single-threaded per execution, so concurrent writes to the same Sheet can result in rows being interleaved or one write failing. For low-volume use (<500 events/day) this almost never happens. For high-volume, add a Utilities.sleep(200) or use a queue via PropertiesService.
3. GHL retries on non-200 responses — but not always
If your script returns an error, GHL may retry. But if the script times out and returns nothing, GHL marks it as delivered. Build explicit error handling (the try/catch above) so failures are visible in GHL's webhook log, not silently lost.
4. The web app URL is not secret
Anyone with the URL can POST to your script. For internal pipelines this is usually fine — the URL is a long random string and practically unguessable. If you need real security, add a shared secret: send a custom header from GHL and validate it in the script before processing the payload.
The same webhook → Apps Script pattern extends to anything in Google Workspace:
The direction also runs the other way. A Google Form submission, a row added to a Sheet, or a Calendar event can trigger a GHL workflow via GHL's inbound webhook or API. That's a separate setup but the same principle — Apps Script fires a POST to GHL's API endpoint when the Workspace event occurs.
The Apps Script approach isn't always better. Use Make or Zapier when:
For a business fully in Google Workspace that wants GHL data flowing into Sheets — Apps Script is the leaner path. For anything that touches a third platform, the middleware tools earn their cost.
If you're also evaluating whether GHL is the right platform at all, see our breakdown of GoHighLevel vs. a custom build — including the cost math for businesses already in Google Workspace.
Need GHL and Google Workspace talking to each other? We set this up regularly — from simple lead logging to full bidirectional sync. Tell us what you're trying to connect.
Talk to usOne-page reference: which tool to use, production failure modes, and break-even timelines — from 120+ real projects.