TradingView Webhook Not Working? 8 Common Causes and a Fix Checklist
Your alert fired but nothing showed up in your chat? This post walks through the most common reasons a TradingView webhook fails — no delivery, 403/401 errors, the 3-second timeout, intermittent drops — ordered by how often they happen, plus a checklist you can tick off.

You set up an alert in TradingView, pasted in your webhook URL, and then… nothing. Or worse, the maddening version: it works sometimes and fails other times, with no obvious pattern.
I've hit all of these myself and debugged plenty for other people. The takeaway: 90% of "the webhook doesn't work" is not black magic — it falls into a handful of fixed causes. Below they're ordered from most to least common. Walk through them one by one and you'll almost always find the culprit.
1. Your TradingView plan doesn't include webhooks
The most common cause, and the easiest to miss. The free (Basic) plan does not support webhooks — you need Essential or higher.
How to check: when creating an alert, scroll to the Notifications tab at the bottom of the dialog. If there's no "Webhook URL" option at all, your plan is the problem — stop debugging everything else.
2. The URL isn't HTTPS, or uses a weird port
TradingView has a few hard requirements for the receiving URL. Break any one and nothing goes out:
- Must be
https://—http://is rejected outright; - Only ports 80 and 443 are accepted — a URL with any other port (e.g.
:3000,:8080) is rejected; - No IPv6 — the domain must resolve to an IPv4 address;
- No local addresses — TradingView's servers cannot reach
localhost,127.0.0.1, or192.168.x.x.
If you're testing a script on your own machine, this one almost always bites you — you assume it works locally, but TradingView can't reach your box from the outside.
3. Two-factor authentication isn't enabled
A sneaky one: TradingView only allows webhook alerts on accounts that have two-factor authentication (2FA) enabled. Without 2FA, the alert may refuse to save the webhook URL, or save it and never send. Turn on 2FA in your account security settings first.
4. Seeing 403 / 401: your own server is blocking it
If you run a self-hosted script or service and see 403 or 401 in the alert log, you can narrow it down fast:
- 403: the server "recognizes" TradingView but blocks it. Usually a firewall rule, CSRF check, or an IP allowlist that doesn't include TradingView. TradingView's webhooks come from a fixed set of IP addresses — add them to your allowlist.
- 401: authentication failed. Most likely a wrong/expired secret or token, or the 2FA issue above.
Order of attack: confirm the secret matches on both sides, confirm the firewall/allowlist lets TradingView through, then hit your endpoint directly with curl to see if it responds.
5. The 3-second timeout: the hidden cause of intermittent drops
TradingView has an easy-to-miss hard rule: your server must respond within 3 seconds, or the delivery is marked as failed.
This is the real reason behind most "works sometimes, fails other times" reports. Your server is usually fast, but every now and then it stalls — a slow DB query, a downstream API call, a cold start — crosses the 3-second line, and that alert is simply gone. TradingView won't retry it for you.
The right approach: return a 200 immediately on receipt, then process the forwarding asynchronously in the background. This step gets skipped in hand-rolled scripts all the time, and that's when sporadic drops start during busy periods.
6. The alert log shows 4xx / 5xx: the problem is on the receiving end
TradingView's alerts panel has a webhook-status column; hover it for the exact error. Rough read by status code:
- 400: your payload is malformed — usually broken JSON, or a missing field the receiver requires. Run it through a JSON validator.
- 404 / 410: wrong URL, or the destination (e.g. a Discord webhook) has been deleted.
- 5xx: the receiver itself crashed or had a transient failure — go read its logs.
A useful trick: temporarily point the webhook URL at a public test endpoint like webhook.site. If it arrives there but not at your own URL, the problem is 100% on your receiving end, not TradingView.
7. Payload format: plain text vs JSON
By default TradingView sends the alert body as plain text; only when your Message field contains valid JSON does it attach an application/json content-type.
If your receiver only accepts JSON but you typed a plain sentence in the Message, parsing fails. For field templating (symbol, action, price, etc.), use JSON:
{
"symbol": "{{ticker}}",
"action": "{{strategy.order.action}}",
"price": "{{close}}"
}
8. Not dropped — "spammed" or "phantom" alerts
A different class of problem: not "nothing arrived" but "too much arrived" or "things that shouldn't have":
- Duplicate spam: the alert condition uses
once_per_bar, firing repeatedly before the candle closes. Most strategy alerts should useonce_per_bar_close(fire once per closed candle). - Phantom / historical alerts: after Bar Replay or a restart, historical candles get recalculated and a flood of stale signals shows up.
- The same alert sent twice: on a network hiccup TradingView occasionally re-pushes the same alert; without dedup on the receiver, you send it twice.
A checklist you can tick off
Go in order — most issues resolve in the first few:
- ☐ Plan is Essential or higher? (the Webhook URL option appears in the alert)
- ☐ Two-factor authentication (2FA) enabled on the account?
- ☐ URL is
https://with no non-standard port? - ☐ URL is a publicly reachable domain, not localhost / a private IP?
- ☐ Tested with webhook.site — does it arrive? (yes → the problem is your receiver)
- ☐ Does the receiver "return 200 first, process async after" to stay under 3 seconds?
- ☐ Self-hosted: does the firewall/allowlist let TradingView's fixed IPs through?
- ☐ Is the Message valid JSON? (if your receiver expects JSON)
- ☐ Is the trigger
once_per_bar_closeto avoid spam? - ☐ Are failed alerts retried and logged — or do they vanish without a trace?
Better than debugging every time: a receiver that doesn't break
Items 5–10 above almost all point to the same root cause: your receiver (that forwarding script/service) isn't robust enough. A DIY Cloudflare Worker or VPS script usually "runs," but skips the details that actually decide reliability — the 3-second response, retry-on-failure, dedup, and an audit trail.
That's exactly what SignalTo handles: it gives you a ready-to-use receiving URL — HTTPS built in, instant response (it accepts first, forwards async, so it never blocks on the 3-second limit), automatic inbound dedup, automatic retries on failure, and a full delivery record for every message. The hardest items on that checklist, handled for you.