Skip to content
ChartTailor
WorkServicesPricingField NotesAbout Start a build
← Pine Discoveries

Webhook alerts should be valid JSON before they are clever JSON

A TradingView webhook payload is an interface. If the JSON is loose, the whole automation becomes fragile.

A webhook alert is not just an alert with a longer message. It is a small interface between TradingView and something outside the chart. The outside process may be a trade copier, a bot, a logging service, a private dashboard, or a spreadsheet. Whatever it is, it cannot read intent. It can only parse the string the script sends.

That is why I treat alert JSON as part of the indicator design, not as a final formatting step. If the payload is inconsistent, the downstream tool becomes fragile even when the chart logic is correct. The chart may be saying the right thing, but the receiver is forced to guess what the thing means.

Why this catches people

Where people usually go wrong is starting with a human sentence and then trying to stuff data into it. A message like “Long breakout on BTC at 68420” is fine for a person reading a popup. It is a poor contract for a webhook. The symbol may contain punctuation. The timeframe may be written differently from what the receiver expects. The price may be rounded differently from the broker or exchange. The same signal may later need a cancellation or an update state.

JSON fixes that only if it is actually JSON. Missing quotes, trailing commas, unescaped strings, mixed numeric formats, and optional keys all make the receiving side harder to trust. If the webhook is connected to an execution process, those details are not cosmetic.

The Pine bit

The practical pattern is to keep the payload boring. Use stable keys. Quote strings. Format numbers deliberately. Include the chart context that the receiver cannot safely infer. Most importantly, include the signal state so the receiver knows whether it is looking at a forming idea, a confirmed signal, or a cancellation.

In Pine, the payload is still just a string, so it deserves the same care as any other hand-built string interface. I do not rely on the receiver to repair malformed JSON. The receiver should validate the message, but the script should send something clean in the first place.

//@version=6
indicator("Webhook payload example", overlay = true)

setup = close > ta.highest(high[1], 20)
priceText = str.tostring(close, format.mintick)

if setup and barstate.isconfirmed
    msg = '{"symbol":"' + syminfo.tickerid + '",' +
          '"timeframe":"' + timeframe.period + '",' +
          '"setup":"breakout",' +
          '"state":"confirmed",' +
          '"price":' + priceText + '}'
    alert(msg, alert.freq_once_per_bar_close)

How I handle it in builds

I avoid making the public text and the machine payload the same thing. A good human alert can be friendly. A good webhook payload should be repetitive, plain, and easy to reject when it is malformed. Those are different jobs. If both are needed, I would rather build two formats than compromise the one that controls automation.

When the payload is designed this way, the script can evolve without breaking the receiver. You can add a key, change a setup name, or include a version field. The important part is that the receiver knows what it is parsing and can treat unknown or missing values as an error instead of inventing a trade decision.

Where this shows up

The best payloads also include enough information to debug the event later. If a user forwards a webhook log two weeks after the fact, a payload that only says “buy” is almost useless. A payload with symbol, timeframe, event name, state, price, bar time, and script version can be traced back to the chart. That makes support dramatically easier.

I avoid making the receiving side depend on the visible alert title. Titles change because users rename alerts in the UI. Payload keys should be stable even if the public wording changes. That small separation is what turns a fragile webhook into an interface that can survive real use.

How I test it

I test this by checking the alert log, not only the chart. The chart tells me when a condition appeared. The log tells me what TradingView actually sent. If a webhook is involved, I compare the received payload with the intended state. That closes the gap between visual signal and operational event.

Checks before I trust it

  • Keep string values quoted and numeric values deliberately formatted.
  • Use the same required keys for every event of the same type.
  • Include symbol, timeframe, setup name, signal state, and price when those matter downstream.
  • Avoid trailing commas and optional keys that change the payload shape unexpectedly.
  • Version the payload if an external tool depends on it.

The discovery here is not exotic. It is just easy to ignore because the chart is visual and the webhook is invisible. A payload that looks dull on the page is often the thing that keeps the automation from becoming mysterious later.