GitHub Repository Webhooks

Last updated December 27, 20253 min read
TL;DR

To integrate GitHub webhooks with Hooklistener local tunnel:

  • Start your local webhook: npm start
  • Log in to Hooklistener CLI: hooklistener login
  • Start a local tunnel: hooklistener tunnel --port 3000
  • Configure a GitHub webhook with your tunnel URL.
  • Trigger and review deliveries (push + Redeliver).

This guide shows how to use the Hooklistener CLI local tunnel to receive GitHub repository webhooks on your localhost server.

GitHub webhooks require a publicly reachable HTTPS endpoint. Hooklistener’s local tunnel provides a public HTTPS URL and forwards requests to your local server over a persistent connection.

By integrating Hooklistener local tunnel with GitHub, you can:

  • Develop and test GitHub webhooks locally without deploying your dev code to a public environment.
  • See live request outcomes while you build by watching the tunnel’s request log (method/path/status/duration).
  • Validate your end-to-end webhook handling because GitHub deliveries hit your public tunnel URL and are forwarded to your local server with the original response returned to GitHub.

1. Start your app

Run a local HTTP server that can receive a GitHub webhook (typically POST to a route like /webhook).

Start your application (example Node app):

npm start

Confirm it’s running locally. You can validate by visiting http://localhost:3000 (or whatever port your app uses).

Tip: If your webhook handler is on a path like /webhook, make sure your app accepts POST requests on that route (for example, http://localhost:3000/webhook).

2. Log in to Hooklistener CLI

Authenticate the CLI so it can create tunnels on your behalf.

In a terminal, run:

hooklistener login

Follow the device-code flow:

  • Open the URL shown in the terminal (for example, https://hooklistener.com/cli).
  • Enter the 8-character code displayed by the CLI to authorize it.

Once approved, the CLI can provision a tunnel URL tied to your account.

3. Start a local tunnel

Expose your local server to the internet through a public HTTPS URL.

Start the tunnel (example for port 3000):

hooklistener tunnel --port 3000

Copy the public HTTPS URL printed by the CLI (for example, https://{your-subdomain}.hook.events).

Confirm the mapping shown by the CLI: public URL → localhost:3000.

Info:Hooklistener terminates HTTPS at the edge and forwards traffic to your machine over a persistent outbound connection (commonly WebSockets). This avoids inbound firewall/NAT issues because your machine does not need to accept inbound internet connections directly.

Path forwarding behavior

Hooklistener forwards the request path “as-is” to your local server:

  • https://{your-subdomain}.hook.events/http://localhost:3000/
  • https://{your-subdomain}.hook.events/webhookhttp://localhost:3000/webhook

4. Configure the GitHub webhook

Point GitHub at your tunnel URL so it can deliver events to your local server.

  1. Sign in to GitHub and open your repository.
  2. Go to Settings → Webhooks.
  3. Click Add webhook.
  4. In Payload URL, paste your Hooklistener public URL.
  5. If your handler is on a route, include it (example: https://{your-subdomain}.hook.events/webhook).
  6. Set Content type to application/json.
  7. (Recommended) Set a Secret. You’ll use this to verify GitHub signatures in your local app.
  8. Under Which events would you like to trigger this webhook?, choose an event set (for example, Just the push event).
  9. Ensure Active is checked, then click Add webhook.

5. Trigger and debug deliveries

Generate a real webhook delivery and confirm it arrives at localhost through the tunnel.

  1. Trigger an event (for example, push a commit to the repository).
  2. In GitHub, open Settings → Webhooks → select your webhook.
  3. In Recent Deliveries, open the latest delivery and check:
    • The delivery Response status (your local server’s response is returned back through the tunnel).
  4. In your terminal, watch the Hooklistener tunnel output:
    • You should see the request appear with method/path/status and duration.

Inspecting requests

Use the tunnel’s live request log to quickly identify common integration issues:

  • Wrong path (GitHub is hitting / but your app expects /webhook)
  • Non-2xx responses (your handler threw an error or rejected the payload)
  • Slow responses (your handler is doing too much work synchronously)

Replaying requests

To resend a webhook without triggering another GitHub event:

  1. Open your webhook in GitHub (Settings → Webhooks → select webhook).
  2. In Recent Deliveries, choose a delivery.
  3. Click Redeliver.

Your local server will receive the same delivery again through the same tunnel URL.

Secure webhook requests

A tunnel URL is a public endpoint, so treat it like a secret and always verify webhook authenticity in your application.

  • In GitHub, set a Secret when creating the webhook (or edit the webhook to add one).
  • In your local webhook handler, verify GitHub’s signature header (X-Hub-Signature-256) using that secret before processing the payload.

Verify that:

  • Valid deliveries are accepted (your app returns 2xx)
  • Tampered/unsigned requests are rejected (your app returns 4xx)

Info:If your tunnel shows connection resets or “protocol” errors, it’s often caused by network changes (VPN/Wi-Fi roaming), sleep/wake, proxies, or firewalls interrupting the persistent connection. Restarting the tunnel usually restores delivery.