ngrok-unofficial-webhook-skill
Start an ngrok tunnel to receive incoming webhooks and process them via the LLM.
Installation
npx clawhub@latest install ngrok-unofficial-webhook-skillView the full skill documentation and source below.
Documentation
Ngrok Webhook Listener
Start a public webhook endpoint via ngrok. Incoming webhooks are auto-routed to matching skills or presented to the user for manual handling.
Prerequisites
cd skills/ngrok-unofficial-webhook-skill
npm install
Environment Variables
Set in the skill's .env file (copy from .env.example).
Required:
NGROK_AUTHTOKEN— ngrok auth token from
Optional:
NGROK_DOMAIN— stable ngrok domain for consistent URLsWEBHOOK_PORT— local port (default:4040)WEBHOOK_PATH— webhook path (default:/webhook)OPENCLAW_BIN— path to openclaw binary (default:openclaw)OPENCLAW_NOTIFY_CHANNEL— notification channel (default:whatsapp)OPENCLAW_NOTIFY_TARGET— phone number / target for notifications
Usage
Start the webhook listener
Run as a background process:
cd skills/ngrok-unofficial-webhook-skill
node scripts/webhook-server.js
The server prints its public URL to stderr:
NGROK_URL=
Webhook endpoint:
For long-running use, launch with nohup:
nohup node scripts/webhook-server.js >> /tmp/ngrok-webhook.log 2>&1 &
What happens when a webhook arrives
webhookEvents in their skill.json- If a matching skill has
forwardPort → HTTP POST to the local service- If a matching skill has
webhookCommands → runs the configured shell command- If no auto-route is available, sends a WhatsApp notification with the payload and a numbered list of matching skills
- User replies with their choice
Skill discovery
Skills opt into webhook handling by adding webhookEvents to their skill.json:
{
"openclaw": {
"webhookEvents": ["meeting.rtms_started", "meeting.rtms_stopped"],
"forwardPort": 4048,
"forwardPath": "/"
}
}
For command-based auto-handling (no running service required):
{
"openclaw": {
"webhookEvents": ["recording.completed"],
"webhookCommands": {
"recording.completed": {
"command": "python3 scripts/download.py {{meeting_id}}",
"description": "Download cloud recording",
"meetingIdPath": "payload.object.id"
}
}
}
}
command— shell command to run;{{meeting_id}}is replaced with the extracted valuemeetingIdPath— dot-separated path to extract the meeting ID from the webhook payloaddescription— human-readable description for notifications
skill.json files with these fields.
Stdout output
The server also writes each webhook as a JSON line to stdout for process polling:
{
"id": "uuid",
"timestamp": "ISO-8601",
"method": "POST",
"path": "/webhook",
"query": {},
"body": {}
}
Health check
curl
Stop the listener
Kill the background process when done.
Integration with Zoom
Typical flow:
meeting.rtms_started → auto-forwarded to the RTMS Meeting Assistantmeeting.rtms_stopped → auto-forwarded, triggers cleanup