Development with a tunnel
http://localhost:3000 exists on your machine and nowhere else. Telegram, Slack, GitHub
and Stripe all live on the internet, and the internet has never heard of your laptop.
A tunnel gives you a public address that forwards to your dev server. Nuxt ships with one, and it costs nothing and needs no account.
Copy this
Start Nuxt with a tunnel
pnpm dev --tunnel
It prints two addresses:
➜ Local: http://localhost:3000/
➜ Network: https://polite-badger-arrives.trycloudflare.com/
The second one works from anywhere in the world. It is temporary and it changes every time you restart.
Point the service at it
For Telegram, once:
export default defineEventHandler(async () => {
return telegram.setWebhook('https://polite-badger-arrives.trycloudflare.com')
})
For everything else, paste the address plus the route into that service's own settings page:
https://polite-badger-arrives.trycloudflare.com/api/_pigeon/webhook
Keep the page on localhost
Open your app at http://localhost:3000, not through the tunnel.
It works. Messages arrive, and your frontend updates.
Why the last step matters
This is the surprise, and it is the reason this page exists.
connected, your logs say the messages arrived, and
the page stays empty.It is not a bug and it will not be fixed by waiting. From the cloudflared maintainers, on issue #1449:
It works as expected with named tunnels. The reason it doesn't work with quick-tunnels is because we have some guardrails due to it being a demo product.
And a day later, in the same thread:
We will try to have SSE work on quick tunnels, but I can't give an ETA.
The same finding is in issue #199 from 2020, closed without a fix.
The way out costs nothing: the tunnel is only needed so the service can reach
you. Short incoming requests pass through it perfectly. Your own browser does not need
it at all, so open the page on localhost and let the tunnel do the one job it is good
at.
| Through the tunnel | On localhost | |
|---|---|---|
| Telegram delivering an update | ✅ | ❌ it cannot reach you |
| GitHub delivering a push event | ✅ | ❌ |
| Your page receiving the live stream | ❌ silently empty | ✅ |
What will cost you an hour
- The address changes on every restart. Telegram remembers the old one, so after a restart you register again, or nothing arrives and nothing errors.
- A proxy closes a connection nothing flows through. Cloudflare after 100 seconds with a 524, an AWS load balancer after 60 by default. The module sends an invisible heartbeat every 30 seconds so the stream survives an idle night.
--tunnelneeds a download on first use. Nuxt fetchescloudflaredonce. On a bad connection the first start looks like it is hanging when it is downloading.- Anyone with the address can reach your dev server while it runs. It is a public url. That is the whole point, and it is worth remembering when you leave it open.
When you are past experimenting
For anything that has to survive a restart, a named tunnel is worth the five minutes:
cloudflared tunnel login
cloudflared tunnel create nuxt-pigeon
cloudflared tunnel route dns nuxt-pigeon dev.example.com
cloudflared tunnel run --url http://localhost:3000 nuxt-pigeon
You get a stable address, so you register the webhook once and never again, and server sent events work.
Read more
How receiving works
Receive Telegram updates, Slack events and any webhook in Nuxt with one listener. Webhooks, polling and streams underneath, and which of them run on serverless.
In the browser
Show incoming Telegram, Slack and webhook messages live in your Nuxt frontend with one composable. Server sent events, no polling and no refresh button.