![Search icon](https://hackernoon.imgix.net/search-new.png?w=19&h=19)
ngrok is great. It's been the go-to for many a web developer who wants to be able to expose a locally running web application to the public Internet for many years. And it's still a great solution. However, as ngrok has changed in ways that have resulted in a much poorer developer experience and there are now better tools for some of the jobs that ngrok was originally the go-to for.
ngrok used to be free and only required an account for "premium features". Now, you need an ngrok account no matter your use case.
There's a 1GB limit a month on data transfer (in all fairness, this should be more than enough for development)
The free ephemeral/random domains (the domain name changes every time you restart ngrok) have always been a bit of a pain. The first paid plan used to come with 3 subdomains but now only comes with one, making exposing multiple services at the same time more costly.
More broadly, Their product focus has shifted reasonably dramatically from supporting use cases such as:
- Temporarily sharing a website that is only running on your development machine
- Demoing an app at a hackathon without deploying
- Developing any services that consume webhooks (HTTP callbacks) by allowing you to replay those requests
- Debugging and understanding any web service by inspecting the HTTP traffic
- Running networked services on machines that are firewalled off from the internet
To:
All-in-one API gateway, Kubernetes Ingress, DDoS protection, firewall, and global load balancing as a service.
So, ngrok has shifted focus away from supporting development use cases. Therefore, it's likely time to try an alternative tool that has been built to specifically support your use case.
The rest of this post will show how the Hookdeck CLI can be used to receive asynchronous events (a.k.a. webhooks) from third-party services such as Stripe, Shopify, or Twilio. If you're looking for a tool that solves the other use cases, take a look at the awesome tunneling repo.
As per the title of this post, the Hookdeck CLI is built to support asynchronous web development. By this, I mean requests, such as webhooks from an API service, are received and proxied onto the application running locally. However, the response from the local service is not passed back to the API service that made the request.
The Hookdeck CLI and the Hookdeck Event Gateway are built to support asynchronous messaging with event-driven applications and not the request/response paradigm. Therefore, you can't use the Hookdeck CLI to expose and serve a locally running website or request/response API. If you want to send the result of some work to another service, you should make a separate request to that service.
The next section walks through installing the Hookdeck CLI, creating and running a local web server (which you can skip if you already have this running), creating a localtunnel using the CLI, sending test webhook events, and replaying webhooks using the Hookdeck Console.
This guide will use the Node.js runtime. If you prefer to use Python, you can run through a using the Hookdeck CLI with a Python server to receive webhooks guide.
Via NPM:
npm i hookdeck-cli -g
On Mac:
brew install hookdeck/hookdeck/hookdeck
On Windows:
scoop bucket add hookdeck https://github.com/hookdeck/scoop-hookdeck-cli.git
scoop install hookdeck
There are also instructions for installing on Linux.
Open your terminal and navigate to a directory for your project.
Install Express to use as the web server:
npm i --save express
Create a server.js
file in the project root:
const express = require('express')
const app = express()
app.use(express.json());
const port = 3030;
app.post("/", (req, res) => {
console.log({ webhook_received: new Date().toISOString(), body: req.body });
res.json({ status: "ACCEPTED" });
});
app.listen(port, () => {
console.log(`🪝 Server running at http://localhost:${port}`);
});
Run the server:
node server.js
Run the following command in a new terminal window to create a localtunnel:
hookdeck listen 3030 my-webhook
The output will be similar to the following:
Dashboard
👤 Console URL: https://api.hookdeck.com/signin/guest?token={token}
Sign up in the Console to make your webhook URL permanent.
Sources
🔌 my-webhook URL: https://hkdk.events/wggd60fl5cxw20
Connections
my-webhook -> my-webhook-to-cli forwarding to /
> Ready! (^C to quit)
Run the following cURL command to act as an inbound webhook, replacing the URL with the Event URL from the Hookdeck CLI output:
curl -X POST https://hkdk.events/cnzpo680rdhejk \
-H "Content-Type: application/json" \
-d '{"message": "Hello, World!"}'
The cURL command output will be similar to the following:
{"status":"SUCCESS","message":"Request handled by Hookdeck. Check your dashboard to inspect the request: https://dashboard.hookdeck.com/requests/req_[id]","request_id":"req_[id]"}%
You will see the terminal running the Hookdeck CLI log the inbound webhook:
2024-07-09 19:06:46 [200] POST http://localhost:3030/ | https://console.hookdeck.com/?event_id={id}
You will also see the Python server log the inbound webhook:
{
webhook_received: '2024-07-25T10:08:22.945Z',
body: { message: 'Hello, World!' }
}
Open the Console URL from your terminal in your browser.
Choose a Sample Webhook Provider from the list of Example Webhooks. For example, Stripe.
Select a Sample Webhook Type from the list on the right. For example, invoice.created.
Click Send.
The Hookdeck Console will show the test webhook has been triggered. You can also inspect the webhook payload and the localhost web server response.
You will see the terminal running the Hookdeck CLI log the inbound webhook:
2024-07-09 19:06:46 [200] POST http://localhost:3030/webhook | https://console.hookdeck.com/?event_id={id}
You will also see the Python server log the inbound webhook:
{
"id": "evt_1MhUT7E0b6fckueStwy86nfu",
"object": "event",
"api_version": "2022-11-15",
"created": 1677833999,
"data": {
...
},
"type": "invoice.created"
}
To replay the webhook, go to the Hookdeck Console and click on the Resend to destination button.
Copy the Event URL from the Hookdeck CLI output. You can also find the same URL in the Hookdeck Console.
Go to the API provider platform, such as Resend, Twilio, Shopify, or Stripe, and register the Hookdeck URL as the webhook URL with the provider.
Trigger a webhook from your selected API provider to see a log entry in the Hookdeck Console.
You will also see the webhook logged in the Hookdeck CLI:
2024-07-09 19:45:57 [200] POST http://localhost:3030/webhook | https://console.hookdeck.com/?event_id={id}
And by the Node.js server running in your local development environment:
{
"to": "{to_number}",
"from": "{from_number}",
"channel": "sms",
"message_uuid": "461c9502-3c2f-4af9-8862-c5a8eccf6cfe",
"timestamp": "2024-07-09T18:45:56Z",
"usage": {
"price": "0.0057",
"currency": "EUR"
},
"message_type": "text",
"text": "Inbound SMS from the Vonage API",
"context_status": "none",
"origin": {
"network_code": "23415"
},
"sms": {
"num_messages": "1",
"count_total": "1"
}
}
And that's it!
You have successfully received a webhook on your local development environment using the Hookdeck CLI. You also inspected the webhook payload and server response, and replayed a webhook using the Hookdeck Console.
This guide demonstrated how to use the Hookdeck CLI as a replacement for ngrok for local asynchronous web development. The Hookdeck CLI is free to use, and you don't need a Hookdeck account.
If you're interested in finding out more about Hookdeck, including features such as transformations, and filtering, benefitting from functionality like configurable retries, and generally using Hookdeck as your reliable inbound webhook infrastructure, head to hookdeck.com.