Theory Road.
← PerspectivesSystems & Integration

Google Ads Offline Conversions From Your CRM: A Working Setup.

A contractor, clinic or brokerage that only reports leads to Google Ads is training its bidding on the wrong outcome. Here is how we get booked jobs and closed deals from the CRM back into Google Ads, with value, without the upload errors.

By Theory RoadSeptember 21, 202610 min read

Google Ads offline conversions are outcomes that happen after the click and off your website (a booked estimate, a signed contract, a closed listing) that you send back to Google Ads tied to the original click so bidding learns from revenue rather than form fills. The setup has three parts: capture the click identifiers (gclid, gbraid, wbraid) into hidden form fields and store them on the lead in your CRM, decide which stages actually predict revenue, and upload those stage changes with a value through a Google Sheets template, the API, Zapier or HubSpot's native sync. This piece walks a contractor, clinic or brokerage through all three, plus the 90-day click limit, the conversion window most people miss, enhanced conversions for leads as the fallback, and the time zone errors behind most rejected uploads.

An offline conversion is a conversion you import into Google Ads rather than one measured by a tag on your site. Google matches it to the click by the click identifier you send, or by a hashed email or phone number in the case of enhanced conversions for leads.

Why leads are the wrong thing to optimize.

Every ad account starts by counting form submissions and calls as conversions, which is the right first step and the wrong last one. A form fill costs the same whether it becomes a full roof replacement or a tire kicker asking for a free inspection. If bidding only sees form fills, it finds the keywords, audiences and hours that produce the cheapest form fills, which are rarely the ones that produce the best jobs.

The effect compounds because Smart Bidding is a learning system. Feed it booked estimates with values for a few months and it bids more on the searches that look like your sold jobs. We have built this for home builders, remodelers and brokerages, and the account starts spending differently before anyone touches a bid. See how this fits a builder's lead system and a brokerage's.

Capture the click ID on every lead.

When someone clicks a Google ad, Google appends a gclid parameter to the landing URL. Where the gclid is restricted, Google instead appends gbraid or wbraid, so capture all three. The parameter only exists on the landing page URL; if the visitor moves to a second page before filling in a form, it is gone unless you stored it.

The standard method: a small script on every page reads gclid, gbraid and wbraid from the URL and writes them to a first-party cookie with a 90-day life. Every form has three hidden fields with those names, and on page load the script copies the stored values into them, so they travel with the lead into whatever system receives it. Google Tag Manager can do this with a custom HTML tag; most form builders, including HubSpot and GoHighLevel forms, support hidden fields that prepopulate from a cookie.

For phone leads, the click ID comes from call tracking. CallRail's dynamic number insertion stores the gclid when the visitor lands, attaches it to the call, and its CRM integrations can pass it through. Without DNI, phone leads from ads have no click ID; enhanced conversions for leads, covered below, are the fallback.

The click ID is the only thread between the ad and the invoice. Drop it at the form and no report written later will tie them back together.

Store the click ID on the lead in the CRM.

The lead has to carry its click ID for weeks, through every stage, until it dies or becomes a job. That means custom fields on the lead or contact record, named clearly (gclid, gbraid, wbraid, plus a lead_created_at timestamp if the CRM does not expose one cleanly), mapped from the form.

  • JobNimbus: add custom fields on the Contact record under Settings, then Custom Fields, and map them from your web form through the API, Zapier or the native form integration. Keep them read-only for reps.
  • GoHighLevel: create custom fields under Settings, then Custom Fields, and map form fields to them in the form builder; its own forms also capture UTM and click parameters.
  • HubSpot: gclid is captured automatically on contacts created through HubSpot forms on pages with the tracking code. For other forms, create a custom contact property and map it.
  • kvCORE: create custom fields on the lead and map them from your landing page forms through the lead API or Zapier; leads from portals will not have click IDs, and that is expected.
  • Everything else (ServiceTitan, AccuLynx, Housecall Pro, Jobber, Clio): the same pattern, a custom field on the lead record, populated at creation and never edited.

Two rules keep this clean. The field is populated once at creation and never overwritten, because a returning visitor with a new gclid does not change which click produced the lead. And the creation timestamp is stored in a known time zone, because you need it to know whether the click is still inside the 90-day limit.

Choose the stages worth importing.

Google will accept a conversion for every stage in your pipeline, and that is a mistake. Import only stages that predict revenue. For most service businesses that is two actions: a booked estimate (a real person at a real address agreed to a visit) and a sold job (contract signed or deposit paid). For a clinic it is a scheduled consult and a completed first visit. For a brokerage, a signed buyer or listing agreement and a closed transaction.

Do not import raw leads; you already count those with the on-site conversion. Do not import contacted or qualified unless you truly bid on them. Set the sold action as primary with a value, and the booked action as secondary or primary with a smaller value depending on your cycle. A remodeler with a four-month cycle needs booked estimates as a primary signal because sold jobs are too rare and too late to teach bidding on their own.

Upload the conversions: four working methods.

Ways to send offline conversions to Google Ads
MethodHow it worksGood forLimits
Google Sheets templateFill Google's template with click ID, conversion name, time and value; Google Ads pulls it on a scheduleAny CRM that can export; weekly cadenceManual unless scripted; time zone errors are common
Google Ads APIYour system posts click conversions when a stage changesHigher volume; near real time; full control of valuesNeeds a developer and a developer token
Zapier or MakeA zap watches the CRM stage change and sends the offline conversionNo developer; JobNimbus, GoHighLevel, kvCOREPer-task pricing; timestamp format mapping
HubSpot native syncThe Ads tool sends lifecycle stage changes with the stored gclidHubSpot users with HubSpot formsOnly contacts HubSpot captured a click ID for
Create the conversion actions.
In Google Ads, open Goals, then Conversions, then Summary, click New conversion action, choose Import, then CRMs, files or other data sources, then Track conversions from clicks. Create one action per stage, for example Booked Estimate and Sold Job, with the categories Qualified lead and Converted lead.
Extend the click-through conversion window.
Open each action and set the click-through conversion window to the maximum that fits your cycle; the default is shorter than most sales cycles. Google accepts imports for clicks up to 90 days old, but only if the window covers the gap between click and conversion.
Choose the upload path.
Pick one method from the table. On JobNimbus or GoHighLevel with no developer, use Zapier: trigger on the stage change, filter for records where gclid is not empty, and send the conversion name, click ID, conversion time and value.
Format the conversion time correctly.
The conversion time must include the time zone offset in Google's format, for example 2026-09-21 14:30:00-05:00. Use the moment the stage changed, not the lead creation date. Most rejected rows fail here.
Send a test batch and check diagnostics.
Upload ten rows and open Goals, Conversions, Uploads to read the results. Google reports each row as imported, imported with warnings, or failed with a reason such as click not found, click too old, conversion time before click, or unparseable time. Fix the cause at the source.
Set primary and secondary and update bidding.
After two to four weeks of reliable data, make Sold Job primary with value, decide whether Booked Estimate is primary or secondary, and move campaigns to Maximize Conversion Value or Target ROAS once volume allows.

Enhanced conversions for leads when click IDs are lost.

Enhanced conversions for leads are Google's alternative when the click ID did not survive the trip to the CRM. Instead of a gclid, you send the lead's email or phone number, hashed with SHA-256, with the conversion name, time and value, and Google matches it against signed-in users who clicked your ad. The same identifier must have been collected at form submission through the Google tag or Tag Manager, with enhanced conversions enabled on the conversion action.

It is the more resilient path, because email and phone are already in every CRM while click IDs have to be carried deliberately. We set both up: click ID first because it is exact, enhanced conversions as the durable fallback. The upload row can include both; Google uses the click ID if it matches and falls back to the hashed data. Hash exactly as Google specifies (lowercase, trimmed email; phone in E.164; then SHA-256) or let the Sheets template or Zapier hash plain values for you.

Conversion windows, values and time zones.

A few settings cause most of the silent failures, where uploads succeed but conversions never appear in reports.

  • Conversion window: if the window on the action is 30 days and the job sold on day 45, the row imports without error and is never counted. Extend the window before your first upload.
  • Click age: Google accepts click conversions for clicks up to 90 days old. A remodeler whose jobs close in month five never gets the sold conversion imported; use booked estimate as the primary signal.
  • Time zone: the conversion time must carry an offset. A bare timestamp is rejected or shifted, and a time earlier than the click is rejected outright.
  • Value and currency: send a numeric value and a currency code on every row. A blank value teaches value-based bidding nothing; a currency symbol in the cell fails.
  • Duplicates: the same click ID with two slightly different times counts twice. Send each stage change once, from one system.

Our pre-launch tracking audit checks that the click ID is present on new leads, the CRM timestamp is in a known time zone and the conversion actions have the right windows; the checklist is in our conversion tracking audit.

What usually goes wrong.

  • Hidden fields added to the contact form but not to the quote calculator, booking widget or chat tool, so the highest-intent leads arrive with no click ID.
  • The gclid overwritten on the CRM record when a lead returns through a later ad click, breaking the tie to the click that produced them.
  • Uploading every pipeline stage, so bidding sees five conversions per customer and optimizes toward leads that move quickly rather than leads that pay.
  • Conversion time set to the lead creation date instead of the stage change, which misplaces conversions in the window or puts them before the click, which is rejected.
  • Local Services Ads leads pushed into the upload. LSA leads carry no gclid and are not eligible; their outcomes are reported in the LSA dashboard.
  • Upload succeeds, nobody checks diagnostics, and three months later the account has been bidding on a conversion action with zero data.

A weekly five-minute check of the Uploads diagnostics page is the whole maintenance load. The rest is upstream: whether reps move stages promptly and whether the form still carries the fields after the last site redeploy. This loop is what makes paid search accountable to revenue, the standard behind our paid media work.

How do I send offline conversions to Google Ads from my CRM?

Capture the gclid, gbraid and wbraid from the landing URL into hidden form fields, store them on the lead in a custom CRM field, then when a lead reaches a revenue-predicting stage such as booked estimate or sold, send the click ID, conversion name, conversion time with time zone and a value to Google Ads through the Sheets template, the API, Zapier or HubSpot's native sync.

How long after a click can I import an offline conversion?

Google accepts click conversions for clicks up to 90 days old. The conversion action's own click-through window must also cover the gap, and its default is shorter than that, so extend it in the action settings before uploading. Conversions for older clicks are rejected as click too old; use an earlier stage such as booked estimate as the primary signal if your cycle is longer.

What are enhanced conversions for leads?

A Google Ads method that matches an offline conversion using a hashed email address or phone number instead of a click ID. The same identifier must be collected on your site at form submission through the Google tag, with enhanced conversions enabled on the action. It is the fallback when click IDs are lost between the form and the CRM, and can be sent alongside the click ID.

Can I import Local Services Ads leads as offline conversions?

No. Local Services Ads leads are routed through Google's own phone number and message system, so they carry no gclid and cannot be matched to a click. Their outcomes are managed inside the Local Services Ads dashboard, where you rate leads, dispute unqualified ones and record which ones you booked. Keep them out of your offline conversion uploads.

Work with us

Let’s talk about what’s next.

A short note on where the business is and where it needs to go. A senior partner replies within one business day.

t@theoryroad.com

Your briefUnder a minute

Tell us what you need.

Read by a person. Never sold, never added to a list.