Back to Google Analytics in Google Sheets
SheetXAI logo
Google Analytics logo
Google Analytics · Google Sheets Guide

Send Offline Events From Google Sheets to GA4 via Measurement Protocol

2026-05-13
4 min read
See the Excel version →

The Scenario

You are a backend developer. Three thousand offline purchase events are sitting in a Google Sheet — each row has a client ID, a timestamp, a product SKU, and a revenue value. These are purchases that happened in your company's physical retail locations last month and missed the GA4 client-side tag entirely.

Your GA4 property is the source of truth for revenue reporting. Without these events, last month's revenue in GA4 is off by roughly 40%. The board review is in six days.

You need to back-fill all 3,000 events into GA4 using Measurement Protocol. That means looping through every row, constructing the right JSON payload, sending an HTTP POST to the Measurement Protocol endpoint, and logging the response back to the sheet — so you know which rows succeeded and which failed.

The bad version of the next few hours:

  • Write a Google Apps Script (or Python script) to loop the sheet
  • Figure out the Measurement Protocol v2 payload structure — the docs are long
  • Handle authentication (Measurement Protocol uses an API secret, not OAuth)
  • Send the first few rows as a test, realize the timestamp_micros field needs to be in microseconds not milliseconds
  • Fix the timestamp conversion, re-run for the test rows
  • Run the full 3,000 rows, realize 47 of them failed because the client ID column had a trailing space
  • Go back, fix the client IDs, re-send the 47 failures
  • Two hours and two script iterations later, you have 3,000 rows sent but no confidence that the timestamp conversion was right for all of them.

The fast version is one prompt.

The Easy Way: One Prompt in SheetXAI

SheetXAI is an AI agent inside your Google Sheet that can loop every row, construct the Measurement Protocol payload, send the event to GA4, and write the response back — in one operation.

Open the SheetXAI sidebar and type:

For every row in my Google Sheet, send a purchase event to GA4 via Measurement Protocol. Use the client ID from column A, the timestamp from column B (convert to microseconds if it is in milliseconds), the product SKU as the item ID, and the revenue value from column D. After sending each row, write "Sent" or the error message into the Status column (column E). Log the total count of successes and failures in cell G1 when done.

SheetXAI loops the rows, constructs each payload, handles the timestamp conversion, sends the requests, writes the status back per row, and logs the summary. You come back to a sheet with a Status column and a count.

What You Get

A sheet with:

  • Column E (Status) — "Sent" for successful rows, or the GA4 error response for failures
  • Cell G1 — a summary: "2,953 sent successfully, 47 failed"
  • Failed rows identifiable — you can filter column E for anything that is not "Sent" to see exactly which rows need attention

The failures are logged, not silently dropped. The most common failure reasons — invalid client ID format, malformed timestamp, missing required field — appear in column E so you can fix and re-send just those rows.

What If the Data Is Not Quite Ready

Offline event sheets are never clean from the source system. SheetXAI handles the common issues inline.

When client IDs have trailing spaces or inconsistent formatting

Your retail system exports client IDs with occasional trailing spaces that break GA4's Measurement Protocol validation.

Before sending, clean the client IDs in column A — trim whitespace and normalize to lowercase. Then send a purchase event per row via Measurement Protocol, write the status to column E, and log success/failure counts in G1.

When timestamps are in local timezone instead of UTC

Your retail system logged timestamps in Pacific Time. GA4 Measurement Protocol expects UTC.

The timestamps in column B are in Pacific Time (UTC-8). Convert each one to UTC before constructing the Measurement Protocol payload. Send a purchase event per row, write status to column E, and log the summary in G1.

When you want to send only rows not yet sent

You ran a partial send last week. Some rows already have "Sent" in column E. You only want to send the remaining rows.

Skip any row where column E already contains "Sent." For all other rows, send a purchase event via Measurement Protocol using client ID from column A, timestamp from column B, SKU from column C, and revenue from column D. Write status to column E.

When you want the full back-fill plus a validation summary in one shot

You need the 3,000 events sent, the status logged per row, a count of successes and failures, and a one-sentence note about any systematic error pattern — all before you close your laptop for the day.

Clean client IDs in column A (trim whitespace). Convert timestamps in column B from milliseconds to microseconds. Send a purchase event per row to GA4 via Measurement Protocol using client ID, timestamp, SKU (column C), and revenue (column D). Write "Sent" or the error message to column E. Log the success and failure counts in G1. If more than 5 rows failed with the same error, write a note about that pattern in cell G2.

The pattern: instead of writing and debugging a script in two languages, you describe the send operation in one prompt. The 3,000 rows go out, the statuses land in column E, and you know exactly what to fix before the board review.

Try It

Get the 7-day free trial of SheetXAI and ask it to back-fill your offline events into GA4 from any sheet you have open. The Google Analytics integration is included in every SheetXAI plan. See also how to export GA4 key events with counts for a tagging audit or the Google Analytics in Google Sheets overview.

Stop memorizing formulas.
Tell your spreadsheet what to do.

Join 4,000+ professionals saving hours every week with SheetXAI.

Learn more