TradingView Webhook Not Working?
A complete debugging flowchart
You set the alert, the condition clearly fired on the chart, and nothing happens downstream — or something happens, but no order shows up on the exchange. A TradingView webhook not working problem can break at five different layers, and guessing which one it is wastes hours.
This post is a layer-by-layer diagnostic flow: plan eligibility, whether the alert actually triggered, whether TradingView actually sent the request, whether your server actually received it, and whether the exchange actually accepted the order. Work through them in order from the top — most people are stuck on layer 0 or layer 1 and don't know it yet.
The five-layer diagnostic flow
Follow this top to bottom. Each step tells you whether to keep going or where the fix is.
Layer 0 — Can this alert even send a webhook?
Before you touch your server or your Pine script, confirm the alert is structurally capable of sending a webhook at all. Two separate gates apply here, and either one alone is enough to explain "nothing ever happens."
Plan eligibility
Webhook notifications are gated by subscription tier. The free Basic plan does not include webhook notifications — it's absent from the feature entirely, not limited. As of July 2026, TradingView's plan comparison shows:
| Plan | Webhook | Price + technical alerts | Alert lifetime |
|---|---|---|---|
| Basic (free) | No | 3 + 0 | 1 month |
| Essential | Yes | 20 + 20 | 2 months |
| Plus | Yes | 100 + 100 | 2 months |
| Premium | Yes | 400 + 400 (+2 watchlist) | Open-ended option |
| Ultimate | Yes | 1,000 + 1,000 (+15 watchlist) | Open-ended option |
TradingView pricing comparison table, as verified July 2026 — check tradingview.com/pricing for current figures.
Alert expiration and dormancy
Alerts are not permanent. The default maximum lifetime is two months; Premium and Ultimate plans can enable an "open-ended" option so the alert never expires. An expired alert shows a red Stopped — Expired status in Alert Manager and simply won't fire again — you have to delete it and create a new one.
There's a second, separate rule worth knowing: an alert gets automatically deactivated if all three of these are true at once — it was created more than a year ago, it hasn't triggered in over a year, and it hasn't been edited in over a year. If your alert has been quietly sitting untouched for a long time, check this before assuming the problem is technical.
- Confirmed your plan is Essential or above (Basic has no webhook notifications)
- Checked Alert Manager and confirmed the status is green Active, not red Stopped — Expired
- 2FA is enabled on your TradingView account
- If the alert is over a year old, confirmed it hasn't been auto-deactivated from a year of inactivity
Layer 1 — Did the alert actually trigger?
This is the layer with the most confusion, because TradingView uses two different frequency systems that people constantly mix up: the Frequency dropdown in the alert creation dialog, and the freq parameter of Pine's alert() function. They are not the same options.
| Setting | Where it lives | What it means |
|---|---|---|
| Once only | UI dropdown only | Fires exactly once, ever, when conditions exactly match |
| Once per bar | UI dropdown, or alert.freq_once_per_bar in code | Checks every bar, fires as soon as the condition is met — does not wait for the bar to close |
| Once per bar close | UI dropdown, or alert.freq_once_per_bar_close in code | Same check, but only fires after the bar has actually closed |
| Once per minute / every time | UI dropdown only | Re-checks the condition every minute |
| alert.freq_all | alert() function only | Fires every time the alert() call runs, no per-bar limit |
The alert() function's freq argument only accepts three values (once_per_bar, once_per_bar_close, all) — there is no code-level equivalent of 'Once only' or 'Once per minute'.
If your Pine script uses the alert() function, the frequency is decided in code and only has three possible values. There is no way to make an alert() call behave like "Once only" or "Once per minute" — those two only exist for the UI-configured alert dialog on alertcondition()-based indicator alerts. Mixing the two mental models up is one of the most common reasons a webhook "should have fired but didn't."
Repainting can make a working alert look broken
Scripts that depend on the current bar's high, low, or close — or that pull data from another timeframe — can have values that shift while the realtime bar is still forming. If your frequency isn't set to Once Per Bar Close, the alert can fire on a value that later changes, which either looks like a false trigger or like a trigger that "should have happened" but didn't match what you see after the fact. Setting the frequency to Once Per Bar Close is the standard fix for this class of problem.
Strategy alerts have their own rules
If the alert is attached to a strategy rather than an indicator, a few extra rules apply. By default, a strategy only recalculates at the bar's close — so even if alert() is called with alert.freq_all or alert.freq_once_per_bar inside a strategy, it still only actually fires once per bar close, unless you explicitly enable calc_on_every_tick = true. Separately, strategy order-fill alerts only notify on realtime order fills — orders that would have filled on historical bars never generate a notification, so testing against historical data alone will never show you a live alert firing.
One more easy mistake: alertcondition() only works inside indicators. Put it in a strategy and it compiles fine — it just silently does nothing, with no error to tell you why.
- Alert Manager's trigger log shows at least one past trigger for this alert
- Frequency setting matches what you actually want (Once Per Bar vs. Once Per Bar Close vs. Once Per Minute)
- If using alert() in code, confirmed the freq value is one of the three valid options
- If it's a strategy alert, confirmed calc_on_every_tick is set correctly for your intended timing
- Ruled out repainting by testing with Once Per Bar Close
Layer 2 — Did the request actually leave TradingView's servers?
If Alert Manager confirms the alert triggered, the next question is whether TradingView successfully sent the webhook request at all. A few strict technical requirements apply to the URL and payload:
| Requirement | Detail |
|---|---|
| Ports | Only 80 and 443 are accepted — any other port is rejected outright |
| Protocol | Non-HTTPS / broken TLS is listed as an explicit send failure |
| IPv6 | Not currently supported for webhook URLs |
| Message size | 4,000 characters max typed into the Message field; 40,960 characters max via alert() or alert_message — the same limit applies to request body size |
| Content-Type | Auto-detected: application/json if the message is valid JSON, otherwise text/plain |
Delivery isn't retried the way people often assume. If your server returns a 5xx error, TradingView resends after 5 seconds, up to 3 times (4 attempts total). But a 4xx response or a timeout is treated as delivered and simply discarded — there's no automatic retry for either of those cases. There's also a hard rate limit: an alert that triggers more than 15 times within 3 minutes gets automatically stopped.
- Webhook URL uses port 80 or 443 (no custom ports)
- URL is HTTPS with a valid certificate
- URL is a public IPv4 hostname, not IPv6
- Alert message is under the size limit for how it was set (4,000 or 40,960 characters)
- Not accidentally triggering more than 15 times in 3 minutes
Layer 3 — Did your server actually receive it?
This is where most genuine "webhook not working" reports actually live: the alert fired, TradingView sent the request, and it never reached your application. Two TradingView-side constraints matter here.
First, your server must respond within 3 seconds or the request is cancelled — and per the delivery rules above, a timeout is not retried. If your endpoint does slow synchronous work (placing an order, waiting on an exchange API response) before responding, that's a common way to silently lose signals under load. The fix is to acknowledge the webhook immediately and process the actual order asynchronously in the background.
Second, if you use an IP allowlist, TradingView's webhook requests currently come from a fixed list of IPs — as verified July 2026:
52.89.214.238
34.212.75.30
54.218.53.128
52.32.178.7CN = webhook-server@tradingview.com. If your framework can inspect the client certificate, that's a sturdier signal than hardcoding IPs.A URL that resolves to localhost or any private/internal IP address is an explicit, documented failure case — TradingView's servers can't reach your laptop directly. During local development you need a public tunnel (like ngrok) in front of your server.
How to actually test this
Isolate "is my server even listening" from "is TradingView's request arriving" by hitting your own endpoint directly first:
curl -X POST https://your-domain.com/webhook/your-token \
-H "Content-Type: application/json" \
-d '{"secret":"your-secret","symbol":"BTCUSDT","side":"buy"}'If that curl call gets a fast 200, your server is fine and the problem is upstream (IP allowlist, timeout, or TradingView-side). If curl itself can't connect, it's a network or firewall issue that has nothing to do with TradingView at all.
- Server responds (any status code) in well under 3 seconds — heavy work happens after responding, not before
- Firewall or security group allows inbound traffic from TradingView's sending IPs, or authentication uses the SSL certificate instead of an IP allowlist
- Webhook URL resolves to a public address, not localhost or a private IP
- A direct curl test to your own endpoint returns 200
Layer 4 — It arrived, but no order shows up on the exchange
If your server logs confirm the payload arrived and your code processed it, the last layer is the exchange itself rejecting or ignoring the resulting order. TradingView doesn't control this part at all — it's entirely between your server and the exchange's API. Without a specific error code in front of you, the usual suspects are:
| Cause | What to check |
|---|---|
| API key permissions | The key needs trading permission enabled; a read-only key or one missing futures trading access will reject every order |
| Quantity precision | Exchanges require order size in specific step increments per symbol — a raw signal quantity that doesn't match the symbol's precision gets rejected |
| Minimum order size | Every symbol has a minimum notional or minimum quantity; small test signals often fall below it |
| Position mode mismatch | An account set to hedge mode when your automation assumes one-way (or vice versa) can cause close/reduce orders to behave unexpectedly |
| Exchange-side IP allowlist | If you've restricted the API key to specific IPs on the exchange itself, your automation server's IP has to be on that list too — separate from anything TradingView-related |
If your order sizing produces a different notional than you expected rather than a flat rejection, that's usually not this layer at all — see the qty_type semantic trap for that specific and very common case. And if the API key itself is the suspect, our Binance API key security guide covers exactly which permissions to enable and which to leave off.
- API key has trading permission enabled (not read-only)
- Order quantity matches the exchange's precision/step size for that symbol
- Order size is above the exchange's minimum notional/quantity for that symbol
- Account position mode (one-way vs. hedge) matches what your automation expects
- Exchange-side API key IP restrictions (if any) include your server's IP
If you're still stuck
Once you've worked through all five layers, you've at minimum narrowed the problem down to one specific side — TradingView's alert configuration, the network path, or the exchange account. That alone turns "it just doesn't work" into a concrete, fixable problem. For the full setup walkthrough from scratch, see our TradingView webhook tutorial.
My TradingView alert fired on the chart but my server got nothing — where do I start?
Why did my webhook stop working after it ran fine for a while?
What's the actual difference between Once Per Bar and Once Per Bar Close?
Does TradingView automatically retry a failed webhook?
How do I test whether my webhook URL is actually reachable?
Get started
TVSBot turns a working TradingView webhook into live orders across 7 exchanges — non-custodial, with async signal processing, dry-run testing, and a full signal replay log so you can see exactly what happened to every alert.
Start free