Learning ngrok: Inspect and Replay
Tags: ngrok, webhook, beginners, learning
Published: 2023-02-16 22:46:36

My first post on Dev.to, written back in 2019, was about [creating a local web server using Python and ngrok](https://dev.to/stmcallister/create-a-quick-local-web-server-with-python-and-ngrok-k0). Little did I know that four years later I would be an [crew member](https://www.linkedin.com/posts/ngrok_werehiring-ngrok-activity-7032015967375282176-fs3g?utm_source=share&utm_medium=member_desktop) on the rocket ship that is ngrok.

I joined the company a couple weeks ago, and I'm in the middle of ramping up with the organization and learning more about the product. While I explore the features that are new to me I'm going to write about things I learn that may be valuable to the community. This post is going to cover the [Inspect and Replay](https://blog.ngrok.com/posts/how-to-inspect-log-replay-traffic-with-ngrok) feature.

A popular use case of ngrok is to receive webhooks on your local machine. As explained in the post I mentioned above, you can spin up a lightweight web server and run `ngrok http 80` on your command line to provide a destination for incoming webhooks to land. For this exercise, I wrote the following code in [Go](https://go.dev/) to receive webhooks at the root endpoint of the domain. 

```go
func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Printf("Webhook: %v", r)
	})

	port := ":80"
	err := http.ListenAndServe(port, nil)
	if err != nil {
		fmt.Println(err)
	}
}
```

The server is listening for requests on port 80, and prints the raw `http.Request` which ends up looking something like this for a webhook received from [PagerDuty](https://developer.pagerduty.com/docs/db0fa8c8984fc-overview).

```go
Webhook: &{POST / HTTP/1.1 1 1 map[Accept:[application/json]
 Accept-Encoding:[gzip] Content-Length:[1438] Content-Type:[application/json] User-Agent:[PagerDuty-Webhook/V3.0] 
X-Forwarded-For:[44.222.99.999] X-Forwarded-Proto:[https] 
X-Pagerduty-Signature:[v1=e3d475277secret24919127safe26759d684anotreal6285b25c4e15a89b7ccb9] 
X-Webhook-Id:[eec61a23-d1af-4b1b-8fe3-afea6fdead49] 
X-Webhook-Subscription:[PXXXXX]] 0x140001582c0 <nil> 1438 
[] false tunnel.ngrokpaperscissors.com map[] map[] <nil> 
map[] [::1]:57318 / <nil> <nil> <nil> 0x14000158300}
```

There is definitely more I could do to my code to get a better view of the incoming webhook. However, it appears ngrok already does a lot of that for us out the box. I've recently discovered the [ngrok inspector](https://ngrok.com/docs/secure-tunnels/ngrok-agent/web-inspection-interface?utm_medium=email&_hsmi=238290781&_hsenc=p2ANqtz-_u2UNVPIhd2gDqOvrq54-_ONDvd5JFDJm0Jx9_5aZhd8tgdfzUkI4SiQ_weScA1yawac7aDlv5cj2O3x2TFylGbaxGWw&utm_content=238290781&utm_source=hs_automation). It can be accessed while ngrok is running by opening [http://localhost:4040/](http://localhost:4040/) where you're shown a view like this.

![Screenshot of ngrok inspector](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6a69r1lrvxlrmvi5npqi.png)

All the HTTP requests are listed down the left side, and on right is a nicely formatted representation of the webhook JSON payload. There are also tabs to look at the Headers, the Raw request, and even the Binary (though, I'm not entirely sure why I would want that :thinking_face: If you know, please share in the comments).

There's also a Replay button that not only lets me replay the selected HTTP request, but you can also choose to modify the replayed request. For example, in my current situation I'm consuming webhooks from PagerDuty incidents. The webhooks are fired depending on whether the state of an incident changes. Some examples of incident state include triggered, acknowledged, and resolved. If my code that's consuming these webhooks behaves differently depending on what type of action occurring on the incident then to speed up my debugging I could select `Replay with Modifications`.


![Screenshot of the Replay with Modifications button in the ngrok inspector](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ydbkgidqoietr7zpmnhm.png)

Find the `event_type` in the JSON body of the request and change it from `incident.triggered` to `incident.acknowledged` and click Replay.


![Screenshot of request modification window in the ngrok inspector](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zajgaqekv4bgvqcf7d5q.png)

That seems pretty handy. I could see myself using that in the future. Hopefully you found this useful. If you have any questions or constructive suggestions please feel free to leave a comment.