Home › Guides › Trading bots & code
TradingView webhook alerts to a bot: how the pieces connect
A webhook turns a TradingView alert into a message your own program can read. The chart spots the setup. Your code decides what happens next — and that's where the safety checks live.
What a webhook is
A normal alert pops up on your screen or phone. A webhook alert does something else: TradingView sends a short message to a web address you choose.
At that address, your own program is listening. It reads the message and acts on it — logs it, checks it, maybe places an order with your broker.
So there are 3 pieces:
- The alert on TradingView — the "something happened" part.
- The message — a small block of text, usually in JSON format.
- The receiver — your program, running on a server with a public web address.
What you need first
- A paid TradingView plan. Webhook alerts aren't on the free plan. Check tradingview.com for which plans include them today.
- Two-factor sign-in. TradingView may ask you to turn on two-factor authentication before the webhook box works.
- A server with a public address, using HTTPS. TradingView only sends to port 80 or 443 (the standard web ports).
- A broker account with an API, ideally a paper (fake money) one, if the bot will place orders.
TradingView's help page on webhooks lists the current rules. Read it before you build — details change.
Step 1: Make the alert condition in Pine Script
Your indicator needs a condition TradingView can alert on. Here's a small one.
Example code for learning — test it on paper first; it is not a ready-made trading system.
//@version=6
indicator("Webhook demo", overlay=true)
fast = ta.ema(close, 9)
slow = ta.ema(close, 21)
plot(fast, color=color.orange)
plot(slow, color=color.blue)
alertcondition(ta.crossover(fast, slow), "Fast above slow", "Fast EMA crossed above slow")
In plain words: work out a 9-candle and a 21-candle EMA (a moving average that weights recent candles more), draw them, and create a condition called "Fast above slow" for when the fast one crosses up.
For the full Pine side, see Pine Script alerts.
Step 2: Write the message
When you create the alert (look for the Alerts panel, then create alert, then pick your indicator and "Fast above slow"), there's a message box. Put JSON there:
{"secret": "a-long-random-string-only-you-know", "symbol": "{{ticker}}", "side": "buy", "price": {{close}}, "time": "{{time}}"}
What each part is:
- secret — a password your receiver checks. Anyone who finds your web address can send it messages. Without the secret, they'd be ignored.
- {{ticker}}, {{close}}, {{time}} — placeholders. TradingView swaps them for the real symbol, closing price and time when the alert fires.
- The quote marks and commas must be exact. If the text is valid JSON, TradingView sends it as JSON. If not, it sends plain text.
Then tick the Webhook URL option in the alert's notifications and paste your server's address, such as https://yourserver.example/tv-hook.
Set the alert to fire once per bar close, so it only fires on a finished candle — a candle that's still forming can cross and uncross.
Step 3: The receiver
Here's a small receiver in Python using Flask (install with pip install flask). It does only 4 things, on purpose.
import hmac, json, logging, os, queue
from flask import Flask, abort, request
app = Flask(__name__)
SECRET = os.environ["WEBHOOK_SECRET"] # set on the server, never in code
logging.basicConfig(filename="webhook.log", level=logging.INFO, format="%(asctime)s %(message)s")
jobs = queue.Queue() # a worker reads from here
@app.post("/tv-hook")
def tv_hook():
try:
data = json.loads(request.get_data(as_text=True))
except ValueError:
abort(400) # not JSON: ignore it
if not isinstance(data, dict):
abort(400)
if not hmac.compare_digest(str(data.get("secret", "")), SECRET):
abort(403) # wrong secret: reject
data.pop("secret")
logging.info("ALERT %s", data) # log every alert
jobs.put(data) # hand off the slow work
return "ok", 200 # answer fast
What it does, in plain words:
- Reads the raw text and parses it as JSON. It reads raw text on purpose, because the message may arrive as plain text instead of JSON.
- Rejects anything that isn't a JSON object, and anything without the right secret. hmac.compare_digest compares the secret safely.
- Logs every alert that passes, minus the secret.
- Puts the alert in a queue and answers right away. A separate worker (not shown) takes it from the queue and does the slow part.
Flask's built-in server is for testing on your own computer. On a real server, run it behind a proper web server with HTTPS.
Why "answer fast" matters
TradingView cancels a webhook request if your server takes more than 3 seconds to answer. Talking to a broker can easily take longer than that.
So the receiver never places the order itself. It says "got it" and hands the job to a worker. Delivery isn't guaranteed either, so check the alert log in TradingView — it shows whether each webhook went through.
Step 4: The worker — where the real rules live
The alert says "the averages crossed". It doesn't know your account. The worker must check everything before any order:
- Is this a duplicate? Skip an alert identical to one already handled.
- Is the daily loss limit hit? If so, log it and do nothing. See daily loss limit.
- Is there already an open position? Don't stack trades by accident.
- Where's the stop? Set it from the chart, then size the trade from it — the same math as our position size calculator.
- Send entry, stop and target together as one Bracket order, so the stop lives at the broker even if your server goes down.
- Check the result. If the broker errors or the connection drops, log it and check open orders before trying again — a blind retry can double the trade.
- Log the order, the broker's reply and the reason.
More on each: trading bot risk controls.
An alert is a signal, not a decision. The chart can't see your account, your open trades or today's losses. Your worker can. Put the rules there.
Security checklist
- Keep the webhook secret and broker API keys in environment variables, never in code or in a published script. See API key security.
- Use a broker key without withdrawal permission.
- Allow requests only from TradingView's published webhook IP addresses (listed on its help page), if your server or firewall supports it.
- Use HTTPS so the message isn't readable in transit.
- Start with a paper account and keep it there for weeks. See paper trading a bot.
Common mistakes
- Alerting on unfinished candles. The cross can vanish before the close. Use once per bar close.
- Placing the order inside the receiver. It can hit the 3-second limit and be marked failed even if the order went through.
- No secret. Anyone who guesses the URL can send fake alerts.
- Trusting "it fired" as "it filled". Always check the broker's reply.
Questions
Do TradingView webhooks need a paid plan?
Yes, webhook alerts aren't available on the free plan. Check TradingView's pricing page for which paid plans include them and how many alerts each allows.
Can TradingView place trades automatically?
TradingView can trade through brokers connected inside it, or send webhook alerts to your own program or a third-party service that places orders. Either way, test on a paper account first.
What format does a TradingView webhook send?
An HTTP POST with your alert message as the body. If the message is valid JSON, it's sent as JSON; otherwise as plain text.
Why did my TradingView webhook fail?
Common causes are a server that takes longer than 3 seconds to answer, a URL on a port other than 80 or 443, an IPv6-only server, or a typo in the JSON. Check the alert log in TradingView for the webhook status.
Want the next step? We'll walk you through it.
Four free lessons by email, one every few days — each with a 10-minute exercise on a real chart.
Send Me the Free Lessons 4 short emails · No spam · Unsubscribe anytimeOr see the whole method, step by step:
See What’s Inside the Course Try everything free first. Decide when you're ready. · Open the free chart tool (works in the TradingView phone app)One chart idea a day, in plain English. Follow along: