Report booked jobs, qualified leads and closed deals to Google Ads by click id or hashed email and phone, from a workflow step.
GA4 events reach Google Ads through the property link, at the user level. An offline conversion upload goes the direct way: Karmaflow.ai tells your Google Ads account that a specific click (its gclid) became a booked job or a qualified lead, with a value. Smart Bidding then learns from revenue attributed to the click, and Enhanced Conversions for Leads covers the contacts who arrived without a click id.
Nothing is uploaded automatically. You decide which trigger becomes which conversion action in a workflow, with the Upload Google Ads Conversion step.
Availability. Two things must be true before anything is uploaded. Karmaflow.ai must have switched uploads on platform-wide; until then every attempt is recorded as Not sent, platform switch off. And your workspace must be approved by a Karmaflow.ai admin for Google Ads and Analytics data sharing, which you request at the top of Settings → Integrations → Google Analytics 4 (see Approval by Karmaflow.ai comes first); until then attempts are recorded as Not sent — awaiting Karmaflow approval. You can prepare everything meanwhile: the conversion actions and the workflows all work.
Settings (the gear icon) → Integrations → Google Ads · Local Services → 5 · Offline conversions to Google Ads
Before an account is linked the card explains how to link one and stops there. Once linked:
Validate a conversion (nothing is recorded). Enter a contact id or a gclid and press Validate. The request goes to Google with the validate-only flag: credentials, the action and the row shape are checked, no conversion is counted. The result names the match used (gclid, or N hashed identifier(s)) or shows Google's own rejection text. Disabled while the platform switch is off, because the request itself is a write.
The counters and the uploads table at the bottom list every attempt with its result, the trigger, the action, what it matched by, the value, and a Detail sentence in Google's words when Google rejected it.
| Result | Meaning |
|---|---|
| Uploaded | Google accepted the conversion. |
| Validated (test) | The validate-only test passed. |
| Already recorded (duplicate order id) | Google already holds a conversion with this order id for this action; a re-run of the same event, not a failure. |
| Rejected by Google | Google refused the row; Detail carries the reason (for example an unparseable click id, or a click older than the action's window). |
| Not sent, platform switch off | The platform-wide switch is off. |
| Not sent — awaiting Karmaflow approval | Your workspace is not approved for Google data sharing yet. |
| Not sent, uploads off for this account | The account switch is off. |
| Not sent, no conversion action | The step named an action that is not in the account's list; refresh the list. |
| Not sent, no click id or hashable contact data | No click id anywhere on the contact and nothing to hash. |
| Not sent, Do Not Contact | No click id, and the contact is opted out so hashed identifiers were withheld. |
Agents → Workflows → Orchestrations → your workflow → Add Step → Upload Google Ads Conversion
value and currency after a deal stage change).dealId when you want one conversion per deal instead.Under the fields, the same {{field}} chips as the GA4 step show what the workflow's trigger carries. The editor also states the current gate: Uploads are switched off platform-wide for now or Uploads are off for this account, so nobody builds a step that silently does nothing.
How a contact is matched, in order: a click id in the run itself (a chat or form event that carried attribution); the click id stored on the contact; the most recent chat session with a click id; a Google lead-form lead for the contact. With no click id, hashed email and phone are sent as enhanced conversions, unless the contact is Do Not Contact. Consent signals ride on every upload: DENIED for Do Not Contact, GRANTED otherwise.
The step puts googleAdsUploadStatus on the run for later branches.
flowchart TD
T["Trigger fires<br/>(e.g. Conversation analyzed, outcomeType = booked)"] --> S["Upload Google Ads Conversion step"]
S --> F{"Platform switch on?<br/>Account switch on?"}
F -- no --> L1["Logged: Not sent + reason"]
F -- yes --> A{"Conversion action known?"}
A -- no --> L2["Logged: Not sent, no conversion action"]
A -- yes --> M{"Click id on run / contact /<br/>chat session / lead form?"}
M -- yes --> U["Upload by gclid / gbraid / wbraid"]
M -- no --> E{"Enhanced conversions on and<br/>contact not Do Not Contact?"}
E -- yes --> H["Upload by hashed email / phone"]
E -- no --> L3["Logged: Not sent + reason"]
U --> R["Google answers per row:<br/>Uploaded · Already recorded · Rejected (with reason)"]
H --> R
Every row says "Not sent, platform switch off". Karmaflow.ai has not switched uploads on yet; nothing on your side is wrong. Prepare the card and the workflows; they start working when the switch is on.
Every row says "Not sent — awaiting Karmaflow approval". Request approval at the top of the Google Analytics 4 settings page, or check its status there.
"Rejected by Google" with an unparseable click id. The stored gclid was truncated or altered on the way to the contact, usually by a form that rewrote the hidden field. Check the form endpoint's submission; the contact's stored click id is what was received.
"Rejected by Google" saying the conversion is outside the window. The click is older than the conversion action's click-through lookback window in Google Ads, or the conversion time you mapped is before the click. Widen the window on the action or leave the time field empty.
The action list is empty after Refresh. The account has no conversion action of the accepting type. Create one in Google Ads under Goals → Conversions → New conversion action → Import → Other data sources or CRMs → Track conversions from clicks, then refresh.