Skip to main content
Skip to article

#n8n: Sync WhatsApp Messages to Google Sheets

Your WhatsApp messages contain customer gold. Buying patterns. Common questions. Feature requests. Complaints. Everything you need to improve your product.

It's trapped in a chat app. No search. No analysis. No team access. Flying blind.

The fix: n8n webhook automation that syncs every WhatsApp message to Google Sheets in real-time. Searchable archive. Message volume analytics. Trend identification. GDPR-compliant exports.

This guide shows you the complete pipeline. No backend server. Thirty-minute setup. MoltFlow webhooks forward messages to n8n, n8n appends to Google Sheets, you get instant analytics. Runs forever. Works with 500+ n8n integrations for CRM sync, Slack alerts, and AI analysis.

What You're Building

By the end of this guide, you'll have a system that:

  1. Captures every incoming and outgoing WhatsApp message in real-time
  2. Logs each message to Google Sheets with timestamp, sender, content, and session
  3. Filters by session or message type (text, image, audio)
  4. Visualizes message volume over time with Google Sheets charts
  5. Exports data for analysis in Excel, Python, or BI tools

The entire flow is automated. Messages appear in your spreadsheet within seconds of being sent or received.

Why Log Messages to Google Sheets?

WhatsApp is great for communication. Terrible for analytics.

Google Sheets gives you:

  • Search: Find messages by keyword, date range, or sender
  • Filtering: Show only specific sessions or message types
  • Charts: Visualize message volume, response times, common keywords
  • Sharing: Give your team read-only access to the archive
  • Export: Download as CSV for analysis in other tools
  • Formulas: Calculate metrics like average response time, messages per day

Plus, Google Sheets is free and accessible from anywhere. No database setup. No SQL queries. Just a familiar spreadsheet interface.

Use Cases

Here's what you can do with a WhatsApp message archive:

Customer Support Analytics

Log all support conversations. Calculate:

  • Average messages per ticket
  • Response time per agent
  • Most common support topics (keyword frequency)
  • Peak support hours

Lead Quality Analysis

Track which leads convert by correlating WhatsApp conversations with CRM data:

  • Do leads who ask about pricing convert more than those who ask about features?
  • How many messages does it take to close a deal?
  • Which sales reps have the highest close rate?

Content Research

Mine customer language for:

  • Questions they ask (FAQ candidates)
  • Words they use (copy for landing pages)
  • Problems they mention (product roadmap ideas)

Compliance and Archival

Some industries require logging all customer communications. WhatsApp doesn't provide built-in export. This workflow creates a timestamped, immutable record.

Prerequisites

Before you start, make sure you have:

  • MoltFlow account with active WhatsApp session (sign up)
  • n8n instance (self-hosted or n8n.cloud) — installation guide
  • Google account for Google Sheets
  • MoltFlow API key (Dashboard → Settings → API Keys)

New to n8n + MoltFlow? Start here: Connect MoltFlow to n8n: WhatsApp Automation Without Code

Step 1: Set Up Your Google Sheet

First, create the spreadsheet where messages will be logged.

Create New Sheet

Go to Google Sheets and create a new blank spreadsheet. Name it something like "WhatsApp Message Archive".

Set Up Columns

In the first row, create these column headers:

ABCDEFGH
TimestampDirectionFromToMessageTypeSessionMessage ID

What each column means:

  • Timestamp: When message was sent (ISO format for sorting)
  • Direction: "incoming" or "outgoing"
  • From: Sender phone number or name
  • To: Recipient phone number or chat ID
  • Message: The actual message text
  • Type: "text", "image", "audio", "video", "document"
  • Session: Which MoltFlow session handled this message
  • Message ID: Unique identifier from WhatsApp

Format the Sheet

Make it easier to read:

  • Freeze the header row (View → Freeze → 1 row)
  • Set Timestamp column to date/time format
  • Set column widths (Timestamp: 150px, Message: 400px, others: 120px)
  • Add filter buttons (Data → Create a filter)

Share with n8n

You need to give n8n write access to this sheet.

Option A: OAuth (Recommended)

In n8n, go to Credentials → Add Credential → Google Sheets OAuth2 API. Follow the authorization flow. This gives n8n permission to write to any sheet in your Google account.

Option B: Service Account

Create a service account in Google Cloud Console, download the JSON key, and share your sheet with the service account email. More secure but more setup.

For this guide, we'll use OAuth (simpler).

Step 2: Configure MoltFlow Webhook

You need MoltFlow to forward messages to your n8n workflow.

Create Webhook in MoltFlow

Go to MoltFlow Dashboard → Webhooks and click "Create Webhook".

URL: We'll fill this in after creating the n8n workflow

Events to subscribe:

  • message (incoming messages)
  • message.any (includes outgoing messages)

Subscribe to message.any if you want to log both sides of conversations. If you only care about incoming messages, just use message.

Sessions: Select the session(s) you want to log (or leave blank for all)

Save the webhook (we'll activate it after setting up n8n).

Step 3: Create n8n Workflow

Now build the workflow that receives messages and writes to Google Sheets.

Add Webhook Node

In n8n, create a new workflow. Add a Webhook node.

Settings:

  • HTTP Method: POST
  • Path: whatsapp-to-sheets
  • Response Mode: Last Node
  • Response Code: 200

Activate the workflow. Copy the webhook URL that n8n generates:

text
https://your-n8n.com/webhook/whatsapp-to-sheets

Go back to MoltFlow webhook config and paste this URL. Activate the webhook.

Test Webhook

Send a test message to your WhatsApp session. Check the n8n execution log. You should see a payload like this:

json
{
  "event": "message",
  "session": "my-session",
  "payload": {
    "id": "msg_abc123",
    "from": "[email protected]",
    "fromName": "John Doe",
    "to": "me",
    "body": "Hey, what's your pricing?",
    "timestamp": "2026-02-03T14:30:00Z",
    "type": "chat",
    "hasMedia": false
  }
}

Perfect. Now let's parse this data and write it to Google Sheets.

Step 4: Parse Message Data

After the Webhook node, add a Set node named "Format for Sheets".

This extracts the fields we care about and formats them for the spreadsheet.

Configure Fields

Field NameExpressionNotes
timestamp={{ $json.payload.timestamp }}ISO 8601 format
direction={{ $json.event === 'message.any' && $json.payload.fromMe ? 'outgoing' : 'incoming' }}Detect direction
from={{ $json.payload.fromName || $json.payload.from }}Use name if available
to={{ $json.payload.to || 'N/A' }}Recipient
message={{ $json.payload.body || '[Media message]' }}Text or placeholder
type={{ $json.payload.type || 'unknown' }}Message type
session={{ $json.session }}Session name
messageId={{ $json.payload.id }}Unique ID

The direction expression checks if the message came from you (fromMe: true) to determine if it's outgoing.

Step 5: Add Google Sheets Node

After the Set node, add a Google Sheets node.

Operation: Append Row

Document: Select "By URL" and paste your Google Sheets URL

Alternatively, use "By ID" and extract the sheet ID from the URL:

text
https://docs.google.com/spreadsheets/d/{SHEET_ID}/edit

Sheet Name: Sheet1 (or whatever you named your sheet)

Columns:

Map each field to the corresponding column:

ColumnValue
A (Timestamp)={{ $json.timestamp }}
B (Direction)={{ $json.direction }}
C (From)={{ $json.from }}
D (To)={{ $json.to }}
E (Message)={{ $json.message }}
F (Type)={{ $json.type }}
G (Session)={{ $json.session }}
H (Message ID)={{ $json.messageId }}

Credentials: Select your Google Sheets OAuth2 credential (the one you set up in Step 1)

Save the workflow.

Step 6: Test the Complete Flow

Send another test message to your WhatsApp session.

Within seconds, it should appear in your Google Sheet.

Check:

  • Row appears in spreadsheet
  • Timestamp is formatted correctly
  • Direction shows "incoming" or "outgoing"
  • Message text is captured accurately
  • Session name is correct

If something's wrong, check n8n's execution log for errors. Common issues:

  • Google Sheets credentials not authorized
  • Sheet ID incorrect
  • Column mapping mismatched

Step 7: Add Optional Filtering

You might not want to log EVERY message. Maybe you only care about specific sessions, or only text messages (no images/videos).

Filter by Session

Add an If node after the Set node, before Google Sheets.

Condition:

javascript
{{ ['session-1', 'session-2'].includes($json.session) }}

Replace session-1 and session-2 with the sessions you actually want to log.

Only the true path connects to Google Sheets. The false path can connect to a different sheet or just end.

Filter by Message Type

Want to log only text messages? Add this condition:

javascript
{{ $json.type === 'chat' }}

Or exclude images and videos:

javascript
{{ !['image', 'video'].includes($json.type) }}

You can combine multiple conditions with AND/OR logic.

Complete n8n Workflow JSON

Here's the full workflow you can import into n8n:

json
{
  "name": "WhatsApp to Google Sheets - MoltFlow",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "whatsapp-to-sheets",
        "responseMode": "lastNode"
      },
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [250, 300]
    },
    {
      "parameters": {
        "values": {
          "string": [
            {
              "name": "timestamp",
              "value": "={{ $json.payload.timestamp }}"
            },
            {
              "name": "direction",
              "value": "={{ $json.event === 'message.any' && $json.payload.fromMe ? 'outgoing' : 'incoming' }}"
            },
            {
              "name": "from",
              "value": "={{ $json.payload.fromName || $json.payload.from }}"
            },
            {
              "name": "to",
              "value": "={{ $json.payload.to || 'N/A' }}"
            },
            {
              "name": "message",
              "value": "={{ $json.payload.body || '[Media message]' }}"
            },
            {
              "name": "type",
              "value": "={{ $json.payload.type || 'unknown' }}"
            },
            {
              "name": "session",
              "value": "={{ $json.session }}"
            },
            {
              "name": "messageId",
              "value": "={{ $json.payload.id }}"
            }
          ]
        }
      },
      "name": "Format for Sheets",
      "type": "n8n-nodes-base.set",
      "position": [450, 300]
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "YOUR_SHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Sheet1",
          "mode": "list"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "A": "={{ $json.timestamp }}",
            "B": "={{ $json.direction }}",
            "C": "={{ $json.from }}",
            "D": "={{ $json.to }}",
            "E": "={{ $json.message }}",
            "F": "={{ $json.type }}",
            "G": "={{ $json.session }}",
            "H": "={{ $json.messageId }}"
          }
        },
        "options": {}
      },
      "name": "Append to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [650, 300],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "Google Sheets account"
        }
      }
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Format for Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format for Sheets": {
      "main": [
        [
          {
            "node": "Append to Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Before importing:

  • Replace YOUR_SHEET_ID with your actual Google Sheets ID
  • Configure Google Sheets OAuth2 credentials in n8n

Building a Dashboard

Now that messages are flowing into Google Sheets, let's build some analytics.

Message Volume Over Time

Create a new sheet tab called "Dashboard".

In cell A1, add a formula to count messages per day:

text
=QUERY('Sheet1'!A:H, "SELECT A, COUNT(A) WHERE A IS NOT NULL GROUP BY A ORDER BY A", 1)

This creates a table of dates and message counts.

Create a chart:

  • Select the query results
  • Insert → Chart
  • Chart type: Line chart
  • X-axis: Date
  • Y-axis: Message count

You now have a visual timeline of message volume.

Messages by Direction

Count incoming vs outgoing:

text
=QUERY('Sheet1'!A:H, "SELECT B, COUNT(B) WHERE B IS NOT NULL GROUP BY B", 1)

Create a pie chart:

  • Chart type: Pie chart
  • Shows percentage breakdown of incoming vs outgoing

Top Senders

Find who messages you most:

text
=QUERY('Sheet1'!A:H, "SELECT C, COUNT(C) WHERE C IS NOT NULL GROUP BY C ORDER BY COUNT(C) DESC LIMIT 10", 1)

Create a bar chart:

  • X-axis: Sender name
  • Y-axis: Message count

Average Response Time

Calculate how long it takes you to respond to incoming messages.

In a new column (column I), add this formula:

text
=IF(B2="outgoing", MINUS(A2, VLOOKUP(H2, {H:H, A:A}, 2, FALSE)), "")

This finds the previous incoming message with the same thread and calculates time difference.

Then average this column:

text
=AVERAGE(I:I)

Message Type Breakdown

How many text vs image vs audio messages?

text
=QUERY('Sheet1'!A:H, "SELECT F, COUNT(F) WHERE F IS NOT NULL GROUP BY F ORDER BY COUNT(F) DESC", 1)

Create a bar chart showing distribution.

Advanced: Add Full-Text Search

Google Sheets has built-in search, but it's slow on large datasets. Here's how to build a custom search interface.

Create Search Sheet

Add a new tab called "Search".

Cell A1 (label): "Search for:"

Cell B1 (input): Leave blank (user types search term here)

Cell A3 (formula):

text
=QUERY('Sheet1'!A:H, "SELECT * WHERE E CONTAINS '" & B1 & "' ORDER BY A DESC", 1)

This searches the Message column (E) for whatever text is in B1 and displays all matching rows sorted by date descending.

Usage: Type a keyword in B1, hit Enter, see all messages containing that keyword.

Search by Date Range

Cell A1: "Start Date:" Cell B1: (enter start date)

Cell A2: "End Date:" Cell B2: (enter end date)

Cell A4 (formula):

text
=QUERY('Sheet1'!A:H, "SELECT * WHERE A >= date '" & TEXT(B1, "yyyy-MM-dd") & "' AND A <= date '" & TEXT(B2, "yyyy-MM-dd") & "' ORDER BY A DESC", 1)

Now you can view all messages within a specific date range.

Handling Large Datasets

Google Sheets can handle up to 10 million cells. At ~100 characters per message, that's roughly 100,000 messages before you hit limits.

If you're logging high-volume conversations (thousands per day), you'll need archival strategy.

Monthly Archive Sheets

Instead of appending to one sheet forever, create a new sheet each month.

In n8n, add a Code node before Google Sheets:

javascript
const timestamp = $input.first().json.timestamp;
const date = new Date(timestamp);
const sheetName = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;

return {
  ...input.first().json,
  sheetName: sheetName
};

In Google Sheets node:

  • Sheet Name: ={{ $json.sheetName }}

This creates sheets named like "2026-02", "2026-03", etc.

You'll need to manually create each new sheet at the start of the month (or use Google Apps Script to auto-create).

Export Old Data

Once a month, export old sheets to CSV and delete the Google Sheet tab:

  • File → Download → CSV
  • Store in cloud storage (Google Drive, S3, Dropbox)
  • Delete the sheet tab to free up space

Upgrade to Database

If you're logging 10,000+ messages per day, Google Sheets isn't the right tool. Upgrade to:

  • Airtable (better for large datasets, still has UI)
  • PostgreSQL (full database, requires n8n Postgres node)
  • BigQuery (Google's data warehouse, great for analytics)

The n8n workflow structure stays the same — just swap the Google Sheets node for a Postgres/Airtable node.

Troubleshooting

Messages Not Appearing in Sheet

Check:

  • Webhook is active in MoltFlow Dashboard
  • n8n workflow is activated (not just saved)
  • Google Sheets credential is authorized
  • Sheet ID is correct
  • Column mappings match (A-H)

Debug: Check n8n execution log. Look for errors on the Google Sheets node.

Duplicate Messages

Problem: Same message appears twice in sheet.

Cause: MoltFlow retries failed webhooks. If n8n responds slowly, MoltFlow might retry before getting response.

Solution: Add deduplication. Before appending to sheet, check if Message ID already exists:

javascript
// In Code node before Google Sheets
const messageId = $input.first().json.messageId;
const sheet = $('Append to Google Sheets').all(); // Get existing data

const exists = sheet.some(row => row.json.H === messageId); // Check column H

if (exists) {
  return { skip: true };
}

return { skip: false };

Then add an If node that only appends if {{ !$json.skip }}.

Timestamp Format Wrong

Problem: Timestamps appear as text instead of dates in Google Sheets.

Solution: Make sure Timestamp column is formatted as "Date time" in Google Sheets:

  • Select column A
  • Format → Number → Date time

If values still appear as text, n8n might be sending strings. Convert to date in the Set node:

javascript
={{ new Date($json.payload.timestamp).toISOString() }}

Rate Limit Errors

Problem: Google Sheets API returns 429 (too many requests).

Cause: n8n is trying to append too many rows too fast.

Solution: Add a Delay node (500ms) before Google Sheets node. Or use batch mode:

Instead of appending one row per message, batch messages and append in groups of 10-20.

What's Next

You've got a complete WhatsApp message archive and analytics dashboard running on Google Sheets.

Connect MoltFlow to n8n in 15 minutes, configure webhooks for message forwarding, and start building analytics on top of your message data. The workflow template in this guide handles the basic sync—extend it with REST API calls for advanced filtering.

Ready to implement this? Follow our step-by-step guide: Connect MoltFlow to n8n for the foundational webhook setup, then use this guide's workflow template for Google Sheets sync.

Related workflows:

Advanced enhancements:

  • Add sentiment analysis to detect angry/happy customers
  • Extract contact info (email, phone) with regex and store in separate columns
  • Build a "Support Ticket" view that groups messages by conversation thread
  • Export to data visualization tools (Tableau, Looker, Metabase)

MoltFlow features to explore:

  • Webhook Events — Other events you can log (status changes, media uploads, etc.)
  • API Reference — Full API for building custom integrations

Ready to build your message archive? Start your free MoltFlow trial and import this workflow in 5 minutes.

Conclusion

Data trapped in chat apps is useless data.

With this n8n workflow, every WhatsApp conversation becomes searchable, analyzable, and shareable. You can spot trends, track response times, and mine customer language for insights — all in a familiar spreadsheet interface.

Start simple. Log messages for a week. Build a basic dashboard. Once you see the value, expand the workflow — add filtering, create advanced charts, export for machine learning.

Your WhatsApp data has answers. Now you can find them.

Questions? Join the MoltFlow Discord or check out the full documentation.

Now go unlock your message data.

> Try MoltFlow Free — 100 messages/month

$ curl https://molt.waiflow.app/pricing

bash-5.2$ echo "End of post."_