alert() vs alertcondition(): which one fires your webhook

The four combinations of alert(), alertcondition(), strategy and indicator in Pine Script, what each can put in a webhook body, and which frequency to choose.

Updated 30 Aug 2026

Pine has two functions with "alert" in the name and two kinds of script that can call them. Which pair you pick decides what your webhook receives: a fixed sentence, a runtime string, or a message that only exists when the broker emulator fills an order. This page lays out the four combinations and what a bridge on the other end can and cannot get from each.

The two functions

alertcondition() is the older one. It works in indicators only, sits in the global scope, and registers a named condition that appears as an item in the Create Alert dialog. Its message argument must be a constant string. The only way to get live values into it is TradingView's own placeholders, such as {{close}} or {{ticker}}, which are substituted after the fact (TradingView help: How to use a variable value in alert).

alert() is the newer one and, in the docs' words, more or less supersedes it. It works in indicators and strategies, can be called from inside an if so it only runs when your condition holds, takes a series string message built at runtime, and lets the script choose its own frequency (Pine Script docs: Alerts).

alert(message, freq)

The freq argument is one of:

FrequencyFires
alert.freq_once_per_bar (default)First call that executes on each live bar, possibly mid bar
alert.freq_once_per_bar_closeOnly on the closing update of the live bar
alert.freq_allEvery call, on every price update

Neither function creates a running alert on its own. Both create alert events, and a person still has to open the Create Alert dialog, pick the script, and turn the events into an alert. That alert is a snapshot of the script and its inputs; edit the script and the alert keeps running the old copy until you recreate it.

The two kinds of script

An indicator runs on every price update of the live bar. A strategy, unless calc_on_every_tick = true, runs once per bar on the closing tick. That difference reshapes how the alert functions behave:

  • In an indicator, alert() with the default frequency fires on the first tick that satisfies the condition, before the bar is confirmed.
  • In a strategy without calc_on_every_tick, every alert() call effectively uses alert.freq_once_per_bar_close regardless of the argument, because the script only runs at bar close (Pine Script docs: Alerts, In strategies).
  • Only a strategy has order fill events. When the broker emulator fills a simulated order, TradingView can fire the alert and substitute {{strategy.order.alert_message}} with whatever the order call passed as alert_message.

The four combinations

IndicatorStrategy
alertcondition()Works. Constant message plus TradingView placeholders. One dialog entry per condition.Not available. Compile error.
alert()Works. Runtime message. Fires on first matching tick unless freq_once_per_bar_close.Works. Runtime message. Always at bar close unless calc_on_every_tick.
Order fill with alert_messageNot available. Indicators place no orders.Works. Message set per order call, delivered when the emulator fills.
Order fill without alert_messageNot available.Fires, but the body is the literal text {{strategy.order.alert_message}}.

Indicator with alertcondition()

Use it when the payload is fixed apart from price and time. The body below is valid JSON after substitution because TradingView's numeric placeholders expand without thousands separators.

//@version=6indicator("RSI cross", overlay = false)r = ta.rsi(close, 14)alertcondition(ta.crossover(r, 50) and barstate.isconfirmed, "RSI up",     '{"sym":"{{ticker}}","side":"BUY","type":"RSI","price":{{close}},"time":"{{timenow}}"}')

What it cannot do: include a stop computed in Pine, switch the side inside one condition, or choose the frequency. Frequency is set in the dialog, and the safe choice there is Once Per Bar Close.

Indicator with alert()

Use it when the payload needs runtime values. Build the string with str.format() and the {0,number,#.##} pattern so numbers arrive ungrouped, keep TradingView placeholders outside the format string, and gate on barstate.isconfirmed. The webhook alerts page explains the thousands-separator trap in full.

//@version=6indicator("ORB signal", overlay = true)orHigh = ta.highest(high, 3)[1]orLow  = ta.lowest(low, 3)[1]fired  = ta.crossover(close, orHigh) and barstate.isconfirmedbody   = '{"sym":"{{ticker}}","side":"BUY","type":"ORB","price":{{close}},' +         str.format('"sl":{0,number,#.##}', orLow) + ',"time":"{{timenow}}"}'if fired    alert(body, alert.freq_once_per_bar_close)

In the dialog, choose the condition "Any alert() function call". The frequency you passed in code wins; the dialog's own frequency setting does not apply to alert() events.

Strategy with alert_message on orders

Use it when you want the alert to mean "the emulator filled this order", with the message you attached to that order. Every order function accepts alert_message: strategy.entry(), strategy.order(), strategy.exit(), strategy.close() and strategy.close_all(). In the dialog, choose "Order fills only" or "Order fills and alert() function calls", and put {{strategy.order.alert_message}} in the message box, or the custom text never reaches the webhook.

if fired    strategy.entry("L", strategy.long, alert_message = body)strategy.exit("X", "L", stop = orLow, limit = target, alert_message = exitBody)

The catch is fills the script did not see. Stops and targets fill inside a bar in the emulator, and the exit's message is whatever alert_message held when the exit call last ran. If a strategy.close() or a strategy.exit() has no alert_message, the fill still fires and the body is the unexpanded placeholder.

Strategy with alert()

Use it alongside alert_message, not instead of it. alert() in a strategy fires when the script decides, at bar close, and does not wait for a fill. That makes it the right carrier for a signal a human is going to confirm, because the human is the fill. Passing the same string to both keeps the two paths in step:

if fired    strategy.entry("L", strategy.long, alert_message = body)    alert(body, alert.freq_once_per_bar_close)

In the dialog, "alert() function calls only" gives you one message per decision. Adding order fills gives you a second message per fill, which a bridge has to dedupe.

What a bridge can receive from each

SourceBodyTimingDynamic valuesRisk to watch
Indicator alertcondition()Constant plus placeholdersPer dialog frequencyOnly {{close}} style placeholdersWrong frequency in the dialog fires mid bar
Indicator alert()Runtime stringPer freq in codeAnything in PineDefault frequency is once per bar, not bar close
Strategy order fillalert_message of the filled orderWhen the emulator fillsAnything in Pine at order timeExits without alert_message send the raw placeholder
Strategy alert()Runtime stringBar closeAnything in PineDuplicate of the fill message if both are enabled

A bridge that treats every POST as a fresh order will double count a strategy alert configured for both fills and alert() calls. Include a stable key in the body, either an id or the combination of symbol, side, strategy name and bar time, so the receiver can collapse the pair. Also decide what an unexpanded {{strategy.order.alert_message}} means. It is not malformed, it is an exit the script did not annotate, and the safe behaviour is to log it and do nothing.

Choosing

  • Fixed message, indicator, no computed levels: alertcondition(), dialog set to Once Per Bar Close.
  • Computed levels, indicator: alert() with alert.freq_once_per_bar_close and barstate.isconfirmed.
  • Strategy, you want the backtest and the live alerts to be the same events: alert() at bar close, alert_message on every order call with the same string, calc_on_every_tick = false.
  • Strategy, you want fills rather than decisions: order fills with alert_message on every call, including exits, plus a dedupe key.

The webhook alerts page covers what happens to the body after it leaves TradingView, and the repainting page explains why the bar close gate matters.

Try it in Sarathi

Sarathi's parser accepts all four paths as long as the body carries a symbol and a side, dedupes on id or on symbol, side, strategy and time, and treats an unexpanded {{strategy.order.alert_message}} as ignorable rather than as an error. Live The Studio writes Pine v6 strategies that pass one payload string to both alert_message and alert() at bar close. Each post becomes an order card in Telegram and on the web dashboard, where you tap Confirm at ½, 1× or 2× size, or Skip; nothing is placed without that tap. The paper broker fills confirmed orders today; Dhan and Zerodha adapters are planned. Planned Open the Studio.

Questions

Sarathi writes and checks Pine v6 strategies; paper trade before you connect a broker.

Open the Studio
Sarathiसारथी

Sarathi means charioteer. The charioteer drives; the warrior decides when to shoot. Here the software drives, and you confirm every order.

Status

Pre-launch · pre-revenue
Bridge verified live 24 Aug 2026

Get started →

Sarathi is an execution bridge, not an investment adviser, and is not registered with SEBI as a Research Analyst. Nothing on this page is advice or a recommendation to trade. Sarathi never holds your funds or securities; every order is placed by you, on your own broker account. Derivatives trading carries substantial risk of loss.

Chart illustrations use TradingView Lightweight Charts™. Every price on this page is made up.

TradingView and Telegram are trademarks of their respective owners. Sarathi is not affiliated with or endorsed by them.