ngrok Free Tier Limits: What 1 GB and 20,000 Requests Cover
Published on November 11, 2026   •   10 min read

ngrok Free Tier Limits: What 1 GB and 20,000 Requests Cover

Jarek CeborskiJarek Ceborski

ngrok's free plan costs $0, needs no card for HTTPS endpoints, and keeps an endpoint online for as long as your machine runs it. In exchange it caps data transfer at 1 GB and HTTP requests at 20,000 a month, allows 3 online endpoints and one assigned dev domain, and shows browser visitors a warning page before your app (ngrok's free plan limits↗). Measured through a tunnel, a first visit to a fresh Vite dev server costs about 3.8 MB and a reload costs 16 requests, so a demo to new visitors runs into the transfer cap first and a developer reloading alone runs into the request cap first.

I build LocalCan, so weigh the comparison with that in mind. Prices and limits checked November 2026, and the tables link their sources. An AI assistant helped draft this post. The commands and numbers come from my own runs.

What are ngrok's free tier limits?

ngrok groups the free plan into monthly quotas, per-minute rate limits, and limits that apply at all times (Free Plan Limits↗):

Limitngrok free planKind
Data transfer1 GB a monthMonthly quota
HTTP requests20,000 a month, more from the $5 creditMonthly quota
TCP connections5,000 a monthMonthly quota
Logs and events10,000 a monthMonthly quota
Webhook verifications500 a monthMonthly quota
OAuth or OIDC users (traffic identities)3 a monthMonthly quota
HTTP request rate4,000 a minuteRate limit
TCP connection rate100 a minuteRate limit
Online endpointsUp to 3At all times
Concurrent agents3At all times
Users1At all times
Domains1 assigned dev domainAt all times
Traffic Policy rules5 per policyAt all times
Endpoint timeoutNoneAt all times

The transfer quota is "Data transfer out (includes traffic to agents)" on ngrok's pricing page↗, so request bodies on their way to your machine count as well as responses on their way to visitors. The free plan also comes with a $5 one-time usage credit, which lasts a year and cannot be spent on data transfer out (the FAQ on the same page). ngrok's machine-readable pricing↗ says it can buy HTTP requests past the 20,000 at $2 per 100,000, so up to 250,000 more if nothing else draws on it. The table on ngrok's Pricing and Limits page leaves that option out.

The dev domain looks like your-assigned-name.ngrok-free.app and stays the same when you restart the agent. TCP endpoints are included, but ngrok asks for a credit or debit card before the first one (ERR_NGROK_8013 in ngrok's error reference↗). Raw TLS endpoints, custom domains and wildcard domains need a paid plan. ngrok custom domain: price, CNAME setup and alternatives covers what your own domain costs.

When do ngrok's free limits reset?

The monthly quotas reset once a month, and ngrok words it two ways. Its free plan limits page says they "reset at the start of each monthly billing cycle", and its Pricing and Limits↗ page says "Your usage refreshes on the first day of each month". The Usage page in the ngrok dashboard shows what is left. Rate limits clear within a minute. The endpoint limit counts endpoints online at the same time, so it never resets: you free a slot by stopping an endpoint.

What happens when you go over?

ngrok's error reference↗ has a message for the transfer and request caps. ERR_NGROK_725 reads "This ngrok account has reached its network bandwidth limit for the month." and ERR_NGROK_727 reads "This ngrok account has reached its HTTP requests limit for the month." Going over the per-minute request rate is ERR_NGROK_734, which "will reset within 1 minute". Past the request cap, the $5 credit buys more requests until it runs out. The credit cannot buy transfer, so past the transfer cap the options are waiting for the reset or a paid plan. The cheapest is Hobbyist at $10 a month, or $96 a year, with 5 GB, 100,000 requests and no warning page. Your own domain needs Pay-as-you-go, at $20 a month plus usage (ngrok pricing↗). Nothing on the pricing page or in ngrok's terms of service↗ ties commercial use to a paid plan, though ngrok pitches Pay-as-you-go as the plan "for teams shipping production traffic".

Does the free plan show a warning page?

Yes. Browser visitors to a free endpoint get a warning page (ngrok calls it an interstitial) that says the site is served by ngrok. Clicking Visit sets a cookie that hides it on that domain for 7 days. Requests from code skip it, and so does any request with an ngrok-skip-browser-warning header or a non-standard User-Agent (Removing the interstitial page↗). Every paid plan removes it. Is ngrok safe? covers what a free ngrok URL shows a visitor and how company networks spot tunnels.

How far do 1 GB and 20,000 requests go?

To turn the caps into page loads, I scaffolded two fresh apps, a Vite 8.3.8 React app and a Next.js 16.4.6 app, and opened each dev server through a LocalCan Public URL (also called a tunnel) with the JSON event stream on:

Bash
localcan http 5390 -H "Host: {{target_host}}" --json > vite-tunnel.jsonl

Every request line in that stream carries the response size (response_bytes, see scripting quick tunnels with --json). Headless Chromium opened each page with an empty cache and then reloaded it, three runs per app, and the three runs matched within 4 bytes. The totals below are response bodies only. Headers and TLS overhead are not in them, so ngrok's meter may read higher for the same traffic.

PageRequestsResponse bytesLoads per 1 GBLoads per 20,000 requests
Vite dev server, first visit213,761,358About 270About 950
Vite dev server, reload160No body bytes1,250
Next.js dev server, first visit24871,553About 1,150About 830
Next.js dev server, reload224,455About 224,000About 910
Vite production build, first visit789,267About 11,200About 2,860
Vite production build, reload70No body bytesAbout 2,860

"Loads per 1 GB" counts 1 GB as 1,000,000,000 bytes. The Next.js rows were measured with allowedDevOrigins set, which the next section explains.

First visits spend transfer. In the Vite dev page, react-dom's development build is 3,132,085 of the 3,761,358 bytes, and Vite's dev server sends it uncompressed. Each person who opens a Vite dev-server link for the first time costs about 3.8 MB, so a demo to a group of new visitors reaches 1 GB after roughly 270 of them. A production build of the same page (vite build, then vite preview) came to 89,267 bytes, 42 times less. The Next.js dev server compresses its responses, so its first visit is lighter at 871,553 bytes, and there the request cap runs out first, after about 830 first visits.

Reloads spend requests. Once the browser has cached the dependencies, a reload asks the dev server about every source module and gets a 304 with no body for each. That sends no body bytes and costs 16 requests, so a developer reloading alone runs into the 20,000-request cap first, after about 1,250 reloads in a month.

Webhooks spend requests too. Each delivery, retries included, is one HTTP request, and its payload counts toward transfer on its way in to your machine. If nothing else uses the endpoint, 20,000 requests is about 670 deliveries a day over a 30-day month. Testing webhooks on a Public URL has a guide per provider.

Can an idle tab use up the request cap?

It can when hot reload is broken. With the default config, the Next.js 16 dev server refuses its dev resources to any origin it does not know, and its log said so during the first runs:

Text
Cross-origin access to Next.js dev resources is blocked by default for safety.

To allow this host in development, add it to "allowedDevOrigins" in next.config.js and restart the dev server:

Behind a tunnel, that guard blocks the hot reload (HMR) websocket, and the dev client keeps trying to reconnect. One tab left open and untouched for 10 minutes made 243 requests: 96 failed websocket attempts, plus 7 full page reloads of 21 requests each that the dev client triggered by itself. That is about 1,460 requests an hour, so one forgotten tab would spend 20,000 requests in about 14 hours.

The fix is one line in next.config.ts, a hostname pattern for your tunnel (allowedDevOrigins↗):

next.config.ts
TS next.config.ts
const nextConfig: NextConfig = {
  allowedDevOrigins: ['*.localcan.dev'],
}

On ngrok's free plan the entry is your dev domain (your-assigned-name.ngrok-free.app), and LocalCan's Free plan URLs need '*.trylocalcan.com'. After the change and a restart, an idle Next.js tab made 0 requests in 120 seconds.

Vite needed no config change because the tunnel rewrote the Host header to localhost (the -H flag above), and an idle Vite tab also stayed at 0. Without that rewrite Vite refuses the request because the host is not on its allowed list. Invalid Host header behind a tunnel has the fix for Vite, Next.js and other frameworks.

How do the ngrok, Pinggy and LocalCan free plans compare?

ngrok free planPinggy free planLocalCan Free plan
Price$0 (pricing↗)$0 (pricing↗)$0 (pricing↗)
Data transfer1 GB a month (pricing↗)No cap (pricing↗)1 GB a calendar month (Free plan)
HTTP requests20,000 a month, more from the $5 credit, 4,000 a minute (limits↗, pricing↗)None listed (pricing↗)No cap (Free plan)
Session lengthNo timeout (limits↗)60 minutes (pricing↗)60 minutes (Free plan)
URL1 dev domain, kept across restarts (limits↗)Random subdomain (pricing↗)New random URL each session (Free plan)
URLs online at once1 dev domain, up to 3 endpoints on it (limits↗)Not listed (pricing↗)1 (Free plan)
Browser warning pageYes, hidden for 7 days after Visit (limits↗)Yes, once per browser (screening page↗)None (Free plan, tested October 2026)
TCPYes, after card verification (errors↗)TCP, UDP and TLS (pricing↗)Paid plans only (Free plan)
First paid planHobbyist, $10 a month or $96 a year: 5 GB, 100,000 requests, no warning page (pricing↗)Pro, $3 a month per seat or $2.50 a month yearly: persistent tunnels (pricing↗), no screening page (screening page↗)Solo, $10 a month or $96 a year: no fixed transfer or request cap (fair use), 5 live Public URLs, TCP, 2 custom domains (pricing↗, terms↗, comparison)

Each free plan wins somewhere. ngrok's is the only one of the three without a session limit, and its dev domain stays put, which matters for a webhook URL you paste into a provider's dashboard once and forget. Pinggy lists no transfer cap on its free plan, includes TCP, UDP and TLS tunnels, and Pinggy Pro is the cheapest way off a free plan. LocalCan's Free plan has the same 1 GB as ngrok and a 60-minute session like Pinggy, but no request cap and no page in front of your app, so the reloads and idle-tab retries measured above count only against its 1 GB. That makes it the better fit for showing a dev server to someone for an hour, and the weaker fit for a webhook endpoint that has to keep one address for weeks. Its first paid plan, Solo, costs the same as ngrok's Hobbyist and sets no fixed transfer or request cap. Six ngrok alternatives compared on free tiers and prices covers Cloudflare Tunnel, zrok, localtunnel and the rest.

How do you check what your own app costs?

Open the browser's developer tools, tick Disable cache in the Network tab, and load the page through the tunnel: the status bar shows the request count and the bytes transferred for a first visit (headers included, so a little above the body-only table). Untick it and reload for the reload cost.

To measure from the tunnel side, save the LocalCan event stream while you click through the app, stop it with Ctrl+C, and add it up with jq:

Bash
localcan http 5391 -H "Host: {{target_host}}" --json > visit.jsonl
jq -s '[.[] | select(.event=="request")] | {requests: length, response_bytes: (map(.response_bytes) | add)}' visit.jsonl

For one first visit to the Vite production build it printed:

JSON
{
  "requests": 7,
  "response_bytes": 89267
}

More posts