Google Sheets offline conversions: how to send sales from a spreadsheet (and why weekly uploads lose rows)
A lot of businesses run their sales in a spreadsheet, and that's fine. The question is how to get the sales from the sheet back to the ad platform without the process quietly rotting. Let me walk through it.
First the format. Whether you upload a file or send rows automatically, each row needs the same handful of things: who the person is (email or phone, formatted properly), when the sale happened, what it was worth, and, if you have it, the click ID that started it. For Google, that's the GCLID. For Meta, the fbclid. Without a click ID, the platform has to match on the email or phone alone.
Then the rules that decide whether a row survives. Meta rejects events sent more than 7 days after they happened. Google ignores offline conversions uploaded more than 90 days after the click, and 63 days for enhanced conversions for leads. LinkedIn takes conversions up to 90 days old. So a sheet of last month's sales is already partly dead on Meta by the time you upload it.
That's the core problem with the spreadsheet route. The weekly or monthly upload is the cheapest process and the highest loss. The cheapest way to fix it is to change the shape: send each sale as a row is added, not in a batch.
There are two ways to do that. Automate it: a Zap or Make scenario that triggers when a new row appears and posts it to a webhook. Each row should carry an ID, so a resend of the same row isn't counted twice. Or keep the CSV, but use it for the right job, which is warming up an account with past customers, not for live sales.
A few things that go wrong with sheets specifically.
Formatting. A phone number stored as a number loses its leading plus sign or zeros. An email with a trailing space hashes into something that matches nobody.
Click IDs cut off. Spreadsheets love to truncate or reformat long strings. A GCLID is long and case-sensitive, so treat it as text.
Dates. A sale dated before its own click is thrown away. Time zones bite here.
Nobody owns it. A sheet that depends on someone remembering will decay.
A made-up cost of the batch habit. 30 sales a month, uploaded once a month to Meta: roughly three quarters are older than 7 days at upload. You keep about a quarter.
If you're building a sheet for this, here's a layout that works. One row per sale or stage. Columns: email, phone with country code, event name, the date and time of the sale, the value, the currency, an order ID that's unique to that row, and one column per click ID you have (gclid, fbclid, ttclid, li_fat_id), formatted as text.
Before you send anything, run four checks. Are emails trimmed and lowercase? Do all phone numbers have a country code? Is every date after the click, in one time zone? Is each order ID unique? Twenty minutes of cleaning here saves you hours of "why didn't it match".
And decide the process once: who adds rows, how often, and who checks the result. A sheet with no owner is a sheet that stops working the month someone leaves.
Do your sales live in a sheet? How do they get back to your ads today?
More on this: Google Sheets and CSV offline conversions, and the complete guide to offline conversion tracking.