An indicator that only draws arrows needs you to be watching. Alerts are what make a Pine Script useful while you're away: TradingView runs them on its servers and notifies you, or another system, when a condition is met.
Pine Script v6 has two alert functions, alertcondition() and alert(), plus order-fill alerts for strategies. They look similar and behave quite differently. This guide explains when to use each, how to write messages and webhook payloads, and which frequency setting stops alerts from firing on signals that later disappear.
Three ways a script can trigger alerts
| Mechanism | Where it works | Message | How you create the alert |
|---|---|---|---|
alertcondition() | Indicators | Constant text with placeholders | One alert per condition, picked in the alert dialog |
alert() | Indicators and strategies | Any string built in code | One alert, "Any alert() function call", covers every call |
| Order fills | Strategies | Default text, or alert_message from the order call | One alert on the strategy covers all its orders |
alertcondition(): one alert per condition
alertcondition(condition, title, message) registers a condition that you can pick in the Create Alert dialog. The title and message must be constant strings — you can't concatenate variables into them — but the message can contain placeholders that TradingView fills in when the alert fires:
| Placeholder | Replaced with |
|---|---|
{{ticker}}, {{exchange}} | The symbol and its exchange |
{{interval}} | The chart timeframe |
{{open}}, {{high}}, {{low}}, {{close}}, {{volume}} | Values of the bar that triggered the alert |
{{time}}, {{timenow}} | The bar's time and the time the alert fired |
{{plot_0}}, {{plot("RSI")}} | The value of a plot, by index or by title |
alertcondition() suits indicators that offer a few fixed events and users who want to choose which ones to be notified about. It is meant for indicators; in strategies, use alert() or order-fill alerts.
alert(): messages built in code
alert(message, freq) fires whenever it's executed, so you put it inside an if. The message is an ordinary string, so it can include any value your script knows: indicator readings, computed stop levels, a JSON payload. Placeholders aren't substituted in alert() messages, so build the text with string functions such as str.tostring() instead.
The freq argument sets how often it can fire: alert.freq_once_per_bar_close, alert.freq_once_per_bar or alert.freq_all. You create one alert on the script and choose Any alert() function call, and every call in the code can then trigger it.
A demo with both
//@version=6
indicator("Alert demo: alertcondition() and alert()", overlay = true)
fastLen = input.int(20, "Fast EMA", minval = 1)
slowLen = input.int(50, "Slow EMA", minval = 2)
rsiLen = input.int(14, "RSI length", minval = 2)
fast = ta.ema(close, fastLen)
slow = ta.ema(close, slowLen)
r = ta.rsi(close, rsiLen)
bullCross = ta.crossover(fast, slow)
bearCross = ta.crossunder(fast, slow)
plot(fast, "Fast EMA", color = color.new(color.teal, 0), linewidth = 2)
plot(slow, "Slow EMA", color = color.new(color.orange, 0), linewidth = 2)
plotshape(bullCross, "Bullish cross", shape.triangleup, location.belowbar, color.new(color.teal, 0), size = size.small)
plotshape(bearCross, "Bearish cross", shape.triangledown, location.abovebar, color.new(color.orange, 0), size = size.small)
// 1) alertcondition(): each call becomes a choice in the Create Alert dialog. Title and message are constant strings.
alertcondition(bullCross, "Bullish EMA cross", "{{ticker}}: fast EMA crossed above slow EMA at {{close}} ({{interval}})")
alertcondition(bearCross, "Bearish EMA cross", "{{ticker}}: fast EMA crossed below slow EMA at {{close}} ({{interval}})")
// 2) alert(): one alert covers every call, and the message is built at run time (here as JSON).
if bullCross or bearCross
side = bullCross ? "buy" : "sell"
msg = '{"symbol": "' + syminfo.ticker + '", "side": "' + side + '", "price": ' + str.tostring(close) + ', "rsi": ' + str.tostring(r, "#.##") + '}'
alert(msg, alert.freq_once_per_bar_close)
Pine accepts single-quoted strings, which is handy for JSON: the double quotes inside don't need escaping.
Alerts from strategies
A strategy can send an alert every time one of its orders fills. Create the alert on the strategy, and by default the message describes the order. To send your own text per order, pass alert_message to strategy.entry(), strategy.exit() or strategy.close(), and put {{strategy.order.alert_message}} in the alert dialog's message box:
//@version=6
strategy("Strategy alert messages (example)", overlay = true)
fast = ta.ema(close, 20)
slow = ta.ema(close, 50)
crossUp = ta.crossover(fast, slow)
crossDown = ta.crossunder(fast, slow)
if crossUp
strategy.entry("Long", strategy.long, alert_message = '{"action": "buy", "symbol": "' + syminfo.ticker + '"}')
if crossDown
strategy.close("Long", alert_message = '{"action": "close", "symbol": "' + syminfo.ticker + '"}')
plot(fast, "Fast EMA", color = color.new(color.teal, 0))
plot(slow, "Slow EMA", color = color.new(color.orange, 0))
Other strategy placeholders include {{strategy.order.action}}, {{strategy.order.contracts}}, {{strategy.order.price}} and {{strategy.position_size}}. This is an example of alert plumbing, not a strategy to trade.
Sending alerts to a webhook
In the alert dialog you can add a webhook URL. When the alert fires, TradingView sends an HTTP POST request to that URL with the alert message as the body; a message that is valid JSON is sent as JSON. Webhooks are a paid-plan feature on TradingView at the time of writing, so check your plan.
A few rules for anything that acts on webhooks:
- Validate everything. Treat the endpoint as public. Check the payload's shape, the symbol and the size before doing anything with it.
- Include an identifier in the message so the receiver knows which script and which version sent it.
- Expect duplicates and delays. Alerts are not an exchange connection. Make the receiver idempotent and decide what happens when a message arrives late.
- Test on a demo account end to end before anything touches real money.
Frequency: the setting that prevents false alerts
On the live bar, close is just the latest price. A cross can appear mid-bar and vanish before the bar closes. If the alert fires the moment the condition is first true, you'll get notifications for signals that never appear on the finished chart.
| Frequency | Fires | Use it for |
|---|---|---|
| Once per bar close | When the bar closes with the condition true | Signals defined on closed bars (most strategies and indicators) |
| Once per bar | The first time the condition is true within a bar | Intrabar events, such as price touching a level |
Every time / alert.freq_all | On every update where the condition is true | Rarely what you want: can fire many times per bar |
For alertcondition() you pick the frequency in the dialog; for alert() it's the freq argument. When in doubt, use once per bar close. The reasons signals change on the live bar are covered in Pine Script repainting explained.
Alerts are snapshots
When you create an alert, TradingView stores a copy of the script and its input values with it. Editing the code or changing the indicator's settings afterwards doesn't update existing alerts. After any change, delete the old alert and create a new one.
Checklist
- Signals calculated on every bar, outside
ifblocks. - Alerts set to once per bar close unless you deliberately want intrabar alerts.
- Messages that identify the symbol, timeframe and event.
- Alerts recreated after every code or settings change.
- Webhook receivers that validate and log every message.
Ready-made scripts with alert conditions: RSI, MACD, Supertrend and the other indicators.
Sources and further reading
- Pine Script User Manual: Alerts — script alerts, order fill alerts and alert frequency.
- Pine Script v6 reference: alertcondition() and alert() — the parameters of both functions.
- Pine Script User Manual: Repainting — why an alert on an unconfirmed bar can fire for a signal that later disappears.
Try it with Edgoro
Describe the alert you want — "alert once per bar close when RSI(14) crosses back above 30 and the close is above the 200 EMA, with a JSON message containing the symbol, price and RSI" — and Edgoro writes the Pine Script v6 code with the right alert calls. Build your alerts with Edgoro.
Alerts can be delayed or missed, and signals describe the past. Trading involves substantial risk of loss; test any automation on a demo account first.