Pine Script webhook alerts: send clean JSON with alert()
A webhook sends your alert to another program instead of your phone. That program needs a message it can read. JSON is the usual format, and one missing quote breaks it. Here's how to build it safely.
What a webhook is
Most alerts go to you: a pop-up, an email, a phone notification.
A webhook sends the alert to a web address instead. A program waiting at that address reads the message and does something with it. It might log it, post it to a chat, or pass it to other software.
The message is plain text. But programs read JSON best. JSON looks like this:
{"ticker": "AAPL", "side": "buy", "price": 182.4}
Names in double quotes, a colon, then a value. Text values in double quotes too. Numbers without quotes. Commas between pairs.
This page builds that message in Pine Script. The basics of alerts are in Pine Script alerts. What happens on the receiving side is in TradingView webhook alerts to a bot.
What you need first
- A computer, to write the code in the Pine Editor.
- A paid TradingView plan. Webhooks aren't on the free plan. Check TradingView's current plans for which ones include them.
- 2-factor sign-in turned on. TradingView asks for it before it sends webhooks.
- A web address that accepts the message. You paste it into the alert's notification settings, in a box usually called "Webhook URL".
The script
This indicator sends a JSON message when a candle closes above its 20-candle average:
//@version=6
indicator("Webhook JSON example", overlay=true)
avg = ta.sma(close, 20)
plot(avg, "Average", color=color.orange)
crossUp = ta.crossover(close, avg)
q = '"'
msg = "{" + q + "ticker" + q + ": " + q + syminfo.ticker + q + ", " + q + "event" + q + ": " + q + "close_above_avg" + q + ", " + q + "price" + q + ": " + str.tostring(close) + ", " + q + "avg" + q + ": " + str.tostring(avg) + ", " + q + "tf" + q + ": " + q + timeframe.period + q + "}"
if crossUp
alert(msg, alert.freq_once_per_bar_close)
Every line, in plain words
- Line 1 says this is Pine Script version 6.
- Line 2 names the script and puts it on the price chart.
- Lines 3 and 4 work out the average and draw it.
- Line 5 is true on the candle where the close crosses above the average.
- Line 6 stores one double-quote mark in q. It's written inside single quotes, so Pine Script doesn't get confused. This one trick makes the next line much easier to get right.
- Line 7 glues the message together with + signs. str.tostring() turns numbers into text. syminfo.ticker is the symbol's name. timeframe.period is the chart's timeframe, like "15" or "D".
- Line 8 says "only when the cross happened…"
- Line 9 sends the message. alert.freq_once_per_bar_close means once, after the candle has closed.
The result looks like this:
{"ticker": "AAPL", "event": "close_above_avg", "price": 182.4, "avg": 180.95, "tf": "15"}
Notice that price and avg have no quotes. They're numbers. ticker, event and tf do. They're text.
Turning it on
- Save the script and add it to a chart.
- Open TradingView's Alerts panel and create a new alert.
- For the condition, pick your script, then look for Any alert() function call.
- In the notification settings, tick the webhook option and paste your web address.
- Save.
The message comes from your code, so leave the alert's own message box alone.
Why build it in code?
TradingView has placeholders like {{ticker}} and {{close}}. They work well in the message box of an alertcondition() alert.
With alert(), the message is built by your script while it runs. So you can include any value it works out, like the average, a stop price or a size. The safe habit is to build every value in code with str.tostring(), as above. That way, what you test is exactly what gets sent.
Why "once per bar close" matters here
A webhook may trigger other software. Firing it on a live candle can send a message for a cross that undoes itself a minute later.
alert.freq_once_per_bar_close waits until the candle is finished. That matches a rule we use for every level: only a candle body closing past it counts.
The other choices, alert.freq_once_per_bar and alert.freq_all, can fire mid-candle. Use them only if you've thought through what happens on a false start.
Test before you send it anywhere
- Copy a real message from the alert log. TradingView keeps a list of fired alerts.
- Paste it into any JSON checker. It should say "valid".
- Point the webhook at a test address first, one that only logs what arrives.
- Check the numbers against the chart. Same price? Same timeframe?
Then remember: an edited script needs a new alert. The old alert keeps running the old code.
A message is not a decision. A webhook carries information. If anything acts on it automatically, that thing needs its own limits: a size from the stop, a daily loss limit, and a way to switch it off. See trading bot risk controls.
Keep it safe
- No passwords or keys in the script. Anyone with the code can read them. Keep secrets on the receiving side. See API key security for trading bots.
- Test on paper first. Any setup that places orders should run on a practice account for a good while. See paper trading a bot.
- Log everything. Every message received, every action taken.
Short names travel well. "tf" and "avg" are fine. Spaces, quotes or line breaks inside names are where JSON breaks.
Learning from a real script
Our course includes the full source code of the StructureX chart tool to learn from and customize, including adding your own alerts and messages. It's source code, not a ready-made trading bot.
Common mistakes
- Missing or extra quotes. Use the q trick, then check the output in a JSON checker.
- Quoting numbers. "182.4" in quotes is text, not a number. Some receivers mind.
- A comma after the last item. JSON doesn't allow it.
- Firing mid-candle. Use alert.freq_once_per_bar_close.
- Forgetting to recreate the alert after an edit. It keeps the old message.
Questions
How do I send JSON from a TradingView alert?
Build the JSON text in Pine Script with + and str.tostring(), send it with alert(), then create an alert on "Any alert() function call" with a webhook URL.
Do TradingView webhooks need a paid plan?
Yes. Webhook notifications aren't on the free plan, and TradingView also asks for 2-factor sign-in. Check its current plans for details.
Why is my webhook JSON invalid?
Usually a missing quote, a quoted number, or a comma after the last item. Copy a fired message from the alert log into a JSON checker to find it.
Can I use {{close}} in a Pine Script alert() message?
Placeholders are made for alertcondition() and the alert message box. With alert(), build the value in code with str.tostring(close) instead.
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: