🎓 Tutorials

TradingView Webhook to Google Sheets: Build a Free Trading Journal Without Zapier (2026)

⚠️ Disclosure: Some links on this page are affiliate links. If you sign up through them, I may earn a commission — at no extra cost to you. I only review tools I actually use.
Every serious trader keeps a journal. The problem? Manually logging entries is tedious, and most automation tools (Zapier, Make, IFTTT) charge monthly fees for something that should be free.

Here's what we're building: TradingView fires an alert → a free Google Apps Script webhook catches it → your trade lands in a Google Sheets journal automatically. Zero cost. Zero third-party dependencies. Takes about 15 minutes to set up.

I run a USDJPY momentum strategy with TradingView alerts. Before this setup, I was copy-pasting alert messages into a spreadsheet like a caveman. Never again.

What You Need

Important: Webhooks on TradingView require at least the Essential plan. If you're on the free plan, you get one alert total — no webhook URL field. If you're deciding which plan to get, I compared them all in my TradingView plan comparison guide.

Step 1: Create Your Trading Journal Spreadsheet

Open Google Sheets and create a new spreadsheet. Name it something like "Trading Journal 2026."

Set up these column headers in Row 1:

ABCDEFGH
TimestampTickerActionPriceTimeframeStrategyAlert MessageNotes
This structure captures everything you need for post-trade analysis. You can add more columns later (P&L, screenshots, etc.), but start lean.

Step 2: Deploy the Google Apps Script Webhook

This is where the magic happens. Google Apps Script gives you a free webhook endpoint that writes directly to your spreadsheet.

1. In your spreadsheet, go to Extensions → Apps Script

2. Delete any existing code in Code.gs 3. Paste this:

function doPost(e) {
  try {
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
    var data = JSON.parse(e.postData.contents);

    sheet.appendRow([
      new Date(),                          // Timestamp
      data.ticker || '',                   // Ticker symbol
      data.action || '',                   // BUY / SELL / CLOSE
      data.price || '',                    // Current price
      data.timeframe || '',                // Chart timeframe
      data.strategy || '',                 // Strategy name
      data.message || '',                  // Full alert message
      ''                                   // Notes (manual)
    ]);

    return ContentService
      .createTextOutput(JSON.stringify({ status: 'ok' }))
      .setMimeType(ContentService.MimeType.JSON);

  } catch (error) {
    return ContentService
      .createTextOutput(JSON.stringify({ status: 'error', message: error.toString() }))
      .setMimeType(ContentService.MimeType.JSON);
  }
}

// Required for webhook verification
function doGet(e) {
  return ContentService
    .createTextOutput('Webhook is active')
    .setMimeType(ContentService.MimeType.TEXT);
}

4. Click Deploy → New deployment

5. Select type: Web app 6. Set "Execute as" to Me 7. Set "Who has access" to Anyone 8. Click Deploy and authorize when prompted 9. Copy the Web app URL — this is your webhook endpoint

The URL looks like: https://script.google.com/macros/s/AKfycb.../exec

Save this URL. You'll paste it into TradingView in the next step.

Security Note

Setting access to "Anyone" means anyone with the URL can POST data to your sheet. The URL itself is a long random string, so it's effectively a secret key. Don't share it publicly. If you ever need to revoke access, just delete the deployment.

Step 3: Configure TradingView Alerts with Webhook

Now connect TradingView to your webhook.

1. Open any chart on TradingView

2. Click the Alert button (clock icon) or press Alt+A 3. Set your alert condition (price cross, indicator signal, etc.) 4. In the Notifications tab, check Webhook URL 5. Paste your Google Apps Script URL 6. In the Message field, paste this JSON template:

{
  "ticker": "{{ticker}}",
  "action": "{{strategy.order.action}}",
  "price": "{{close}}",
  "timeframe": "{{interval}}",
  "strategy": "Momentum Crossover",
  "message": "{{ticker}} {{strategy.order.action}} at {{close}} on {{interval}} chart"
}

7. Click Create

Understanding the Placeholders

TradingView replaces these placeholders with real values when the alert fires:

PlaceholderWhat It ReturnsExample
{{ticker}}Symbol nameUSDJPY, BTCUSDT
{{close}}Current price149.850
{{interval}}Chart timeframe60 (minutes), D (daily)
{{strategy.order.action}}Trade directionbuy, sell
{{time}}Alert trigger time2026-03-19T05:00:00Z
{{volume}}Current volume1523400
{{exchange}}Exchange nameBINANCE, OANDA
Pro tip: If you're using a Pine Script strategy (not just a simple price alert), {{strategy.order.action}} gives you the actual buy/sell signal. For plain indicators, use a static value like "action": "SIGNAL" and fill in the direction manually.

Step 4: Test the Pipeline

Before trusting this with real alerts, test it manually.

Option A: Test from TradingView

Set a price alert just above/below the current price so it triggers within seconds. Watch your Google Sheet — a new row should appear within 5-10 seconds.

Option B: Test with curl

curl -L -X POST "YOUR_WEBHOOK_URL" \
  -H "Content-Type: application/json" \
  -d '{"ticker":"BTCUSDT","action":"BUY","price":"84250.00","timeframe":"60","strategy":"Test Signal","message":"Test alert from curl"}'

If you see {"status":"ok"} and a new row appears in your sheet — you're live.

Common Issues

"Webhook URL is not valid" in TradingView: Make sure you copied the full Apps Script URL including the /exec at the end. Also verify your TradingView plan supports webhooks (Essential+). No data appearing in sheet: Check the Apps Script execution log. Go to Apps Script → Executions (left sidebar). Look for errors. The most common: JSON parsing failure because the alert message isn't valid JSON. Data in wrong columns: The appendRow array order must match your column headers. Adjust the order in the script if needed.

Step 5: Advanced — Add P&L Tracking

Once the basic pipeline works, enhance your journal with calculated fields.

In column I, add a header "Entry Price." In column J, add "Exit Price." In column K, add "P&L."

For the P&L formula in K2:

=IF(AND(I2<>"",J2<>""), IF(G2="BUY", J2-I2, I2-J2), "")

Auto-Link Entries and Exits

Here's a more advanced Apps Script that automatically pairs BUY/SELL signals for the same ticker:

💡 TradingView

Like what you're reading? Try it yourself — this link supports ChartedTrader at no cost to you.

Try TradingView Free →

function doPost(e) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var data = JSON.parse(e.postData.contents);
  var lastRow = sheet.getLastRow();

  if (data.action === 'sell' || data.action === 'SELL' || data.action === 'CLOSE') {
    for (var i = lastRow; i >= 2; i--) {
      var rowTicker = sheet.getRange(i, 2).getValue();
      var rowAction = sheet.getRange(i, 3).getValue();
      var exitPrice = sheet.getRange(i, 10).getValue();

      if (rowTicker === data.ticker &&
          (rowAction === 'BUY' || rowAction === 'buy') &&
          exitPrice === '') {
        sheet.getRange(i, 10).setValue(parseFloat(data.price));
        break;
      }
    }
  }

  sheet.appendRow([
    new Date(),
    data.ticker || '',
    data.action || '',
    data.price || '',
    data.timeframe || '',
    data.strategy || '',
    data.message || '',
    ''
  ]);

  return ContentService
    .createTextOutput(JSON.stringify({ status: 'ok' }))
    .setMimeType(ContentService.MimeType.JSON);
}

This automatically fills the exit price on your original entry row when a SELL signal fires for the same ticker. Combined with the P&L formula, you get automatic trade tracking.

Step 6: Pine Script Integration — Log Strategy Signals

If you're running a Pine Script strategy, you can send richer data with alert() calls:

//@version=6
strategy("My Momentum Strategy", overlay=true)

fast = ta.sma(close, 10)
slow = ta.sma(close, 50)

if ta.crossover(fast, slow)
    strategy.entry("Long", strategy.long)

if ta.crossunder(fast, slow)
    strategy.close("Long")

When you create the alert, select "Order fills only" or "Alert() function calls only" depending on whether you want to log every signal or just actual fills.

For the alert message with a strategy:

{
  "ticker": "{{ticker}}",
  "action": "{{strategy.order.action}}",
  "price": "{{strategy.order.price}}",
  "timeframe": "{{interval}}",
  "strategy": "{{strategy.order.id}}",
  "message": "{{strategy.order.comment}}"
}

{{strategy.order.price}} gives you the actual fill price (accounting for slippage in backtests), not just the closing price. Much more accurate for journal tracking.

Why Not Use Zapier or Make?

I tried Zapier first. It works — but here's why I switched:

FeatureGoogle Apps ScriptZapierMake
CostFree forever$19.99/mo (Starter)$9/mo (Core)
Webhook limitUnlimited750 tasks/mo on Starter1,000 ops/mo on Core
Latency2-5 seconds5-15 seconds5-10 seconds
CustomizationFull JavaScriptVisual builderVisual builder
MaintenanceSet and forgetAuth tokens expireAuth tokens expire
For a trading journal that just needs to catch webhooks and append rows, paying $20/month for Zapier is overkill. The Apps Script approach is faster, free, and you own the code.

The only scenario where Zapier wins: if you need complex multi-step workflows (alert → log + send Telegram + update Notion + email). For that, sure, pay for Zapier. For a simple journal? Apps Script all day.

Scaling: Multiple Strategies, One Sheet

If you run multiple strategies (like I do — USDJPY momentum on the daily chart, plus crypto swing trades on 4H), use the "strategy" field to differentiate:

{
  "ticker": "{{ticker}}",
  "action": "{{strategy.order.action}}",
  "price": "{{close}}",
  "timeframe": "{{interval}}",
  "strategy": "USDJPY Momentum",
  "message": "{{ticker}} {{strategy.order.action}} at {{close}}"
}

Then in Google Sheets, use Filter Views or a pivot table to analyze each strategy separately. You can also modify the Apps Script to write to different sheet tabs based on the strategy name:

var sheetName = data.strategy || 'Default';
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
if (!sheet) {
  sheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet(sheetName);
  sheet.appendRow(['Timestamp', 'Ticker', 'Action', 'Price', 'Timeframe', 'Strategy', 'Message', 'Notes']);
}

Each strategy gets its own tab automatically. Clean.

What This Setup Looks Like in Practice

After running this for my USDJPY momentum strategy, here's what a typical week looks like in the sheet:

TimestampTickerActionPriceTimeframeStrategy
2026-03-17 08:00USDJPYbuy149.230DMomentum
2026-03-17 14:30BTCUSDTbuy83450.00240Swing
2026-03-18 02:15BTCUSDTsell84120.00240Swing
No manual entry. No copy-pasting. Every alert is logged with exact timestamps and prices. When I review my trades on Sunday, everything is already there.

FAQ

Can I use this with TradingView's free plan?

No. Webhooks require the Essential plan ($12.95/month) or higher. You can set one alert on the free plan, but without the webhook URL option. If you're serious about automated journaling, the Essential plan is the minimum.

Will this work with OKX or other exchange alerts?

This setup catches any TradingView alert with a webhook — it doesn't matter what exchange your chart data comes from. If you're trading on OKX and want to go further (actually execute trades from alerts, not just log them), check out my OKX Signal Bot setup guide.

How many alerts can I log per day?

Google Apps Script has a daily quota of about 20,000 URL fetches for webhook receives via doPost. Unless you're running hundreds of 1-minute alerts, you'll never hit it.

Can I add charts or screenshots to the journal?

Not automatically from TradingView webhooks — they only send text data. But you can add a Google Sheets column for screenshot URLs and paste TradingView chart links manually.

What if Google Apps Script goes down?

It's Google infrastructure — uptime is essentially 99.9%+. I've been running this for months without a single missed alert. If you want redundancy, set up a second webhook endpoint in the same TradingView alert.

Next Steps

Once your journal is running:

1. Review weekly — Look for patterns. Which strategy wins? Which timeframe? Which session (Asian/London/NY)?

2. Add conditional formatting — Color-code winning trades green, losing trades red 3. Build a dashboard — Use Google Sheets charts to visualize your equity curve, win rate, and average R:R 4. Connect to your broker — If you're using TradingView connected to OKX, you can log both the signal AND the execution in the same journal

The best trading journal is the one you actually use. Automating the boring part (data entry) means you spend your time on the useful part (analysis).

Try TradingView — webhooks require the Essential plan or higher.
TradingView

Ready to get started? Use the link below — it helps support ChartedTrader at no cost to you.

Try TradingView Free →
📈

About the author

I'm a systematic trader running live strategies on IB (USDJPY momentum) and Hyperliquid (crypto perps). Every tool reviewed here is something I've used with real capital. Questions? Reach out.

📚 Related Articles

🎓 Tutorials

TradingView Free Plan Indicator Limit: How to Combine RSI, EMA, and MACD Into One Pine Script (2026)

Hit TradingView's 2-indicator limit on the free plan? Learn how to combine RSI, EMA, and MACD into a single all-in-one Pine Script v6 indicator — with full copy-paste code, visual customization tips, and a clear upgrade path when you outgrow the workaround.

March 23, 2026 ⏱ 10 min read
🎓 Tutorials

TradingView Webhook to Telegram Bot: Get Real-Time Alerts on Your Phone (2026 Setup Guide)

Learn how to send TradingView alerts directly to Telegram using webhooks. Step-by-step guide covering BotFather setup, free relay options, JSON payload formatting, and real trading alert examples — no coding experience required.

March 22, 2026 ⏱ 14 min read
🎓 Tutorials

TradingView Pine Script SuperTrend Strategy: Build a Custom Indicator Step by Step (2026)

Learn how to build a custom SuperTrend strategy indicator in Pine Script v6 with complete code. Includes RSI filter, multi-timeframe confirmation, stop loss/take profit, and backtesting setup for TradingView.

March 21, 2026 ⏱ 17 min read

📬 Get weekly trading insights

Real trades, honest reviews, no fluff. One email per week.