Tracking & Attribution

How Do You Send Dynamic Conversion Values to Google Ads Offline Imports?

Value-based bidding only works if each offline conversion carries its real amount. Which number to send, how to handle currency, what to do about refunds.

Quick answer

A dynamic conversion value is the real amount each conversion was worth, sent on its own row, instead of one flat number applied to every lead. Value-based bidding optimises toward the values you report, so a column of 1.00 teaches it that every conversion is identical. Send the amount you actually keep — net of discounts and refunds — in the currency the customer paid, on the same row as that conversion's click ID and conversion time.

Tell us what's broken. We'll fix your tracking — free.

Describe the tracking/attribution problem you're stuck on and we'll map it to a fix: server-side conversions to Meta, Google, TikTok and Pinterest, plus first-party tracking that survives Safari. No code required.

Send the real amount each conversion was worth, one value per row, instead of one flat number applied to every lead. Value-based bidding optimises toward the values you report, so a column of 1.00 teaches it nothing. The number to send is what you actually keep, in the currency the customer paid, beside that row’s click ID and conversion time.

The hard part is not the upload. It is deciding which number belongs in that column, and keeping it honest after a refund.

What is a dynamic conversion value, and why does a flat one hold you back?

A dynamic conversion value is a per-row amount that differs between conversions — 40 for one lead, 4,000 for another. A static value is the same figure on every row. Google’s offline import accepts both, and the difference only becomes expensive once you move a campaign onto a value-based bidding strategy.

Value-based strategies — Maximise Conversion Value, and Target ROAS on top of it — work by predicting how much value a given auction is likely to produce, then bidding accordingly. That prediction is built from the values you reported. If every conversion you ever uploaded was worth exactly 1.00, the model’s honest conclusion is that all conversions are interchangeable, and the strategy quietly degenerates into conversion-count maximisation under a different name.

The cost is invisible because nothing errors. Uploads succeed. The conversion column fills in. A ROAS figure appears, computed from numbers you invented. Meanwhile the campaign spends the same acquiring a tyre-kicker as it does acquiring an enterprise deal, because nobody ever told it the two differ.

Which number should you send: order total, net revenue, or gross profit?

Send the number you would defend in a finance meeting, and send the same definition every time. For ecommerce that is usually order total minus discounts and refunds, excluding shipping and tax. For lead gen it is the expected value of that lead, not the headline deal size.

Three common choices, and what each does to your bidding:

  • Order total (gross). Easiest to pull, and it over-values thin-margin products. A campaign optimising on gross revenue will happily buy your worst SKU all day.
  • Net revenue. Gross minus discounts, returns and refunds. The default recommendation for most advertisers: defensible, available in every order system, and it penalises the traffic that buys and sends things back.
  • Gross profit. Net revenue minus cost of goods. The most correct signal and the hardest to maintain, because COGS moves and somebody has to keep the mapping current.

Pick one and stop switching. From inside the bidding model, a definition change halfway through a learning period is indistinguishable from a market shift. If you must change, change it at a campaign boundary and write down the date.

Whatever you pick should reconcile with the same revenue you see when you attribute ecommerce revenue to the ad that started it. Two systems reporting two different figures for one order is a problem you will have to solve eventually. Solve it before you hand one of those figures to a bidding algorithm.

Diagram of a Google Ads offline conversion row being built in the PartialLeads dashboard style: an order card showing gross amount, discount and refund deducted to a net value with its currency code, joined to a captured Google click ID and conversion time

How do you value a lead that has not bought anything yet?

Use expected value: the average closed amount for that lead type multiplied by the rate at which that type closes. A demo request that closes a fifth of the time at an average of 5,000 is worth 1,000 on the row. It is an estimate, and an estimate that differentiates beats a constant that does not.

Work it from your own CRM, per lead type. Illustrative figures, to show the shape:

Lead type Avg closed value Close rate Value to send
Demo request 5,000 20% 1,000
Pricing enquiry 5,000 8% 400
Newsletter signup 5,000 1% 50

The point is the spread, not the digits. Three tiers already gives a bidding model something to work with, and three tiers is a pivot table.

Two refinements once the basics hold. First, segment on anything that reliably moves the close rate — company size, country, which form they filled. Second, if you grade leads before sales ever touches them, use the grade: a lead rated a strong match against your ideal customer is not worth what an unlikely one is, and if you already score leads against your ideal customer those tiers exist already.

The trap is sending full deal size for an unclosed lead. Upload 5,000 for every demo request and you have told Google that demo requests are five times more valuable than they are. It will bid on that belief until your real ROAS argues otherwise, several thousand dollars later.

What currency should the value be in?

Send the currency the customer actually paid in, with its ISO code on the row, and let Google do the conversion. Converting yourself before upload introduces a second exchange rate into a system that already has one, and the two will disagree on every reconciliation you ever run.

The rule matters more than it sounds. A row that carries an amount but no currency code is read in the account’s currency — so a €120 order uploaded into a USD account is counted as $120, silently, on every international row, in a direction that moves with the exchange rate. Confirm the exact behaviour in Google’s own import specification before your first multi-currency file; the field names change more often than the principle does.

Three things to check before that first upload:

  1. Every row carries a currency code, not only the rows that are not in your home currency.
  2. The code matches the amount. Pulling the value from one column and the currency from a billing country is how a Canadian customer’s USD payment ends up labelled CAD.
  3. Your own reporting converts on a stated date. Google’s converted figure and your internal one will differ slightly regardless, because they use different rates on different days. That is fine as long as you know which is which — the same discipline that applies when you report attribution across multiple currencies.

The principle is not Google-specific. On the Meta side, a purchase event carries its own value and currency pair rather than a pre-converted amount, which is why the guidance to send purchase value and currency to Meta reads almost identically.

What do you do when a conversion is refunded after you have uploaded it?

Restate it. Google Ads supports conversion adjustments — retracting a conversion you already uploaded, or restating it at a lower value — so a refund becomes a correction instead of a row you wish you could take back. Check the current adjustment format in Google’s documentation; the mechanics change more often than the concept.

Refunds are the most common reason an advertiser’s reported ROAS and their bank balance disagree. The uploaded value is a snapshot of the moment the order was placed. The refund arrives days or weeks later, into a system that never hears about it. Do nothing and the bidding model keeps optimising toward revenue that was returned — and toward the audiences that return it most, because in a gross-revenue column a high-refund segment is indistinguishable from a high-value one.

Two workable shapes:

  • Restate on a schedule. A second weekly pass looks back over the previous window, finds orders refunded or partly refunded since, and uploads the adjustment.
  • Delay the first upload. If your return window is short and your click window has room, hold the conversion until the return period closes and upload the settled figure once. Simpler, but it delays the signal, and delayed signal is worth less to a bidding model than prompt signal.

Most advertisers should restate rather than delay. Either way your own reporting should net refunds the same way, which is the practical reason to understand why refunds inflate your attributed revenue before you start reporting on gross.

How do you build the value column without an engineering team?

Export orders, join them to click IDs, write one row per conversion into the sheet your import reads, and schedule it. The join is the hard part: your order system knows the amount, your ad account knows the click, and almost nothing knows both.

The manual version, honestly described:

  1. Export orders for the period with order ID, amount, currency and customer email.
  2. Export leads with the click ID captured at the ad visit and the email typed into the form.
  3. Join on email, lowercased and trimmed.
  4. Map each joined row to click ID, conversion action name, conversion time, value, currency.
  5. Upload. Repeat next week. Forever.

It works, and it fails in predictable places. The email does not match, because the customer bought with a different address from the one they typed on the form. The click ID is missing, because it never survived the trip to the form. And step 3 silently drops every buyer who used two addresses — frequently the enterprise account you most wanted to value correctly.

That is the moment most teams notice the join is an identity problem rather than a spreadsheet problem. The upload pipe itself is the easier, separate question covered in how to import lead conversions into Google Ads.

How does PartialLeads put a real value on a Google Ads offline conversion?

By matching the purchase to the session that produced it, so the amount and the click ID land on one record before anything is exported. Orders arrive from Shopify, WooCommerce, Stripe, GoHighLevel or a universal webhook, get normalised, and are matched to a session by visitor ID first, then email, then phone, then IP.

Once matched, the order’s value and its native currency attach to the lead, the lead flips from Partial to Completed, and first-touch and last-touch attribution rows are written carrying the UTMs, click IDs and landing page from that person’s journey. Refunds arrive as their own row with their own status phase and net against the paid amount rather than overwriting it, so the ledger figure is settled revenue rather than order-day revenue.

Purchases ledger in the PartialLeads dashboard showing matched and unmatched orders with per-order values, currency chips, a netted refund row and a net revenue total

The Google Ads path dispatches from that matched purchase. Conversion rows are written to the client’s Google Sheet for Google’s scheduled import, carrying the click IDs captured at first touch — gclid, gbraid, wbraid — alongside hashed email and phone. Phones are normalised to E.164 with a country fallback from the session’s geo, and Gmail dot and plus variants are normalised before hashing, so the identifiers arrive in the shape the platform expects rather than the shape your CRM happened to store.

Because capture runs as the visitor types rather than on submit, those identifiers exist even for people who never pressed the button — and a submit-only pipeline has no row at all for that buyer, so there is nothing to put a value on.

The constraints, stated plainly:

  • Dispatch runs through a scheduled Google Sheets upload, not a live API write. There is an import cadence between an order settling and Google crediting it.
  • The value is only as settled as your refund data. A refund arriving after a row is already uploaded needs a restatement pass; matching does not retroactively edit a row Google is holding.
  • Google’s click window is Google’s. A long sales cycle can close a deal after the click is too old to credit, and no vendor extends that deadline.
  • We control what goes into the row. Google controls whether it matches. Every identifier can be present and correct and the click can still fail to resolve on Google’s side. Any vendor claiming otherwise is describing the half of the system they do not own.
What breaks The mechanism Where you see it in the dashboard
Every conversion uploaded at the same flat value Order value and native currency attached to the matched lead Revenue column on the Leads list, per-lead revenue block
Revenue and click ID sit in two systems that never join Purchase matched to a session by visitor ID, email, phone or IP Purchases ledger, matched vs unmatched wedge
Refunds left inside the reported figure Refund rows with their own status phase, netted against paid Purchases ledger, net revenue
Multi-currency orders flattened into one number Native currency kept per purchase; conversion stated with its rate date Revenue by currency cards, Attribution report currency selector
The value lands against the wrong campaign First-touch and last-touch attribution rows written per matched purchase Attribution report, first vs last touch tables
Contact identifiers rejected on format E.164 phone with geo fallback; Gmail dot and plus variants normalised before hashing Lead Detail contact fields
Buyers who never submitted the form have no row to value Email and phone captured on input, before submit Leads list, Partial badge

Tell us what's broken. We'll fix your tracking — free.

Describe the tracking/attribution problem you're stuck on and we'll map it to a fix: server-side conversions to Meta, Google, TikTok and Pinterest, plus first-party tracking that survives Safari. No code required.

Sources


Frequently asked questions

QWhat is a dynamic conversion value in Google Ads?
It is a conversion value that differs per conversion, sent on each row of an offline import rather than set once on the conversion action. One lead uploads at 40, the next at 4,000. It is what value-based bidding strategies read when they predict how much a given auction is worth, so without it those strategies have nothing to differentiate on.
QDo I have to use dynamic values, or can I leave every conversion at the same amount?
You can leave them flat, and conversion-count bidding will work fine. But Maximise Conversion Value and Target ROAS both learn from the values you report, so a constant value tells them every conversion is identical. If you are running either strategy against a flat column, you are running conversion-count bidding with extra steps.
QShould I send revenue or profit as the conversion value?
Net revenue — gross minus discounts and refunds — is the right default for most advertisers, because it is defensible and available in every order system. Gross profit is a better signal if you can keep cost-of-goods mapping current. Gross order total over-values thin-margin products. Whichever you choose, use the same definition every time; switching mid-flight makes the bidding model re-learn without telling you.
QHow do I put a value on a lead that has not bought anything?
Use expected value — average closed amount for that lead type times its close rate. A demo request closing a fifth of the time at an average of 5,000 goes in at 1,000. Do not upload the full deal size for an unclosed lead; that tells Google the lead is worth five times what it is, and the bidding will act on it.
QWhat currency should I send, and do I need to convert first?
Send the currency the customer paid in, with its ISO code on the same row, and let Google convert. Converting yourself adds a second exchange rate that will never quite agree with the platform's. A row carrying an amount with no currency code is read in the account's currency, which turns a €120 order into $120 without any error message.
QWhat happens if a customer refunds after I have already uploaded the conversion?
Google Ads supports conversion adjustments — retracting the conversion or restating it at a lower value. A weekly pass that looks back over the previous window, finds orders refunded since, and uploads the adjustment is usually enough. Skipping this is the main reason reported ROAS drifts away from the bank balance, and it teaches the bidding model to buy refund-prone audiences.
QCan I just wait until the refund window closes and upload the final number?
Yes, if your return period is short and Google's click window still has room when it ends. It is simpler than restating. The cost is timing: delayed signal is worth less to a bidding model than prompt signal, and a long sales cycle plus a long return window can push the upload past the click age Google will accept.
QMy values are correct but the conversions are not matching at all. Is that a value problem?
No. Matching and valuation are separate gates. A row matches on its click ID, the click's age and the conversion action name; the value column is only read once the row has matched. If nothing is crediting, check the click ID column and the conversion action name first — the value is irrelevant until the join succeeds.

Find the qualified leads your forms are currently throwing away.

Install PartialLeads on one landing page, send traffic, and compare what your CRM captured against what PartialLeads recovered and qualified.