#I'm trying to have my agent respond to a google script webhook but I just can't get it to work.
1 messages · Page 1 of 1 (latest)
Happy to help — webhook setup has a few sharp edges. First: what does openclaw --version show?
For a basic Google Apps Script → OpenClaw trigger, the current docs pattern is:
{
hooks: {
enabled: true,
token: "use-a-dedicated-secret-not-gateway-token",
path: "/hooks",
mappings: [
{
match: { path: "google-script" },
action: "agent",
agentId: "main",
messageTemplate: "Google Script event:
{{text}}",
deliver: true,
channel: "discord",
to: "channel:1502954900626342018"
}
]
}
}
Then Apps Script should POST to:
UrlFetchApp.fetch("https://YOUR-GATEWAY.example.com/hooks/google-script", {
method: "post",
contentType: "application/json",
headers: {
Authorization: "Bearer YOUR_HOOK_TOKEN"
},
payload: JSON.stringify({ text: "hello from Apps Script" }),
muteHttpExceptions: true
});
Common gotchas:
- Token must be in a header:
Authorization: Bearer ...orx-openclaw-token. Query-string tokens are rejected. hooks.tokenmust not be the same asgateway.auth.token.hooks.pathcannot be/; use something like/hooks.- If your Gateway is local, Google Apps Script can’t reach
127.0.0.1; you need a public HTTPS URL, Tailscale Funnel/Serve, or a reverse proxy. - If you expect the HTTP response itself to contain the agent’s final answer, that’s probably the mismatch — hooks trigger a run; use
deliver: trueto send the result somewhere like Discord.
Can you paste these, with secrets redacted?
openclaw --version- Your
hooksconfig block - The Apps Script
UrlFetchApp.fetch(...)code - The HTTP status/body Apps Script gets, plus any
openclaw logs --followline when the request hits
Docs: https://docs.openclaw.ai/automation/cron-jobs#webhooks and https://docs.openclaw.ai/gateway/configuration-reference#hooks
Good, thanks — your /hooks/agent payload shape is basically right. Two things jump out:
tofor Discord should bechannel:<id>, not just the raw channel id. For this thread/channel it should look like:
to: "channel:1502954900626342018"
- If nothing appears to hit OpenClaw, separate “network reaches Gateway” from “agent delivery works”. On the machine running OpenClaw, try this first:
curl -i -X POST http://127.0.0.1:18789/hooks/agent \
-H 'Authorization: Bearer YOUR_HOOK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"name":"AlbumReview","deliver":true,"channel":"discord","to":"channel:1502954900626342018","message":"test from local curl"}'
Expected response if hooks are wired:
{"ok":true,"runId":"..."}
Then test the public URL from anywhere outside that box:
curl -i -X POST https://YOUR_PUBLIC_HOST/hooks/agent \
-H 'Authorization: Bearer YOUR_HOOK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"name":"AlbumReview","deliver":true,"channel":"discord","to":"channel:1502954900626342018","message":"test from public curl"}'
If local works but public doesn’t, the bug is your tunnel/reverse proxy/firewall/DNS path, not Apps Script or the hooks config. Make sure the proxy forwards /hooks/* to the Gateway port, usually 127.0.0.1:18789.
Also: Apps Script should log a response even if OpenClaw never sees it. The most useful missing bit is the actual Response code: / Response body: from Apps Script. If UrlFetchApp.fetch throws instead of logging, wrap it:
try {
const response = UrlFetchApp.fetch(WEBHOOK_URL, options);
Logger.log(response.getResponseCode());
Logger.log(response.getContentText());
} catch (e) {
Logger.log("Fetch failed: " + e);
}
Paste the local curl result + public curl result and we’ll know exactly which layer is broken. 🦞
Remote test returns ```HTTP/2 200
server: nginx
date: Sun, 10 May 2026 09:23:49 GMT
content-type: application/json; charset=utf-8
x-content-type-options: nosniff
referrer-policy: no-referrer
permissions-policy: camera=(), microphone=(self), geolocation=()
{"ok":true,"runId":"7608cf80-9b55-4be0-ac39-d397eb6b45ea"}```
Local test returns ```HTTP/1.1 200 OK
X-Content-Type-Options: nosniff
Referrer-Policy: no-referrer
Permissions-Policy: camera=(), microphone=(self), geolocation=()
Content-Type: application/json; charset=utf-8
Date: Sun, 10 May 2026 09:21:35 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Content-Length: 58
{"ok":true,"runId":"3dbcaeee-1b6d-40c7-94a4-7e5baf5e407c"}```
Hmmm... the appscript logs returns 9:25:54 Error TypeError: Cannot read properties of undefined (reading '0')
Nice, that narrows it down a lot: OpenClaw is reachable and accepting the hook. The Apps Script is failing before it sends anything.
This line is the culprit:
const artist = data[0];
data is undefined, so sendToDiscord(data) is being called without an array/row.
Add a quick guard first:
function sendToDiscord(data) {
if (!Array.isArray(data)) {
throw new Error("sendToDiscord expected a row array, got: " + JSON.stringify(data));
}
// existing code...
}
Then make sure your trigger passes a row. For example, if this is from an onEdit(e) spreadsheet trigger:
function onEdit(e) {
const sheet = e.range.getSheet();
const row = e.range.getRow();
// optional: skip header row
if (row === 1) return;
const data = sheet.getRange(row, 1, 1, 11).getValues()[0];
sendToDiscord(data);
}
And also update your Discord target to include the prefix:
to: "channel:1502954900626342018"
So the webhook/network side is good 🦞 — now it’s just Apps Script plumbing: pass the sheet row into sendToDiscord() instead of calling it empty.
Hmmm... I think I know where the appscript is going wrong. I'll get back to you.