> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hiveku.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Conversion Uploads

> Send CRM outcomes back to Google, Microsoft and Meta so automated bidding trains on real revenue instead of raw form fills — the two gates, the validate-only proving step, and every reason a conversion is refused

Ad platforms optimise toward whatever you tell them a conversion is. If the only thing they hear about is a form fill, they will buy you more form fills — including the bad ones. Conversion uploads close the loop by sending the *outcome* back: this lead became a won deal, worth this much, from this click.

This is the capability that changes what a bidding algorithm is optimising for, and it is the one most commonly asked about in evaluations.

<Note>
  Tracked **phone calls** are uploaded on a separate path with its own switch, under Communications → Settings → Ad conversion uploads. This page covers CRM and commerce outcomes: won deals, form leads and store orders.
</Note>

## What can be uploaded

| Source          | What it sends                         | Value                 |
| --------------- | ------------------------------------- | --------------------- |
| `crm_deal_won`  | A deal reaching a won stage           | The deal's own value  |
| `form_lead`     | A form submission tied to an ad click | A fixed value you set |
| `shopify_order` | A store order                         | The order total       |

Set a **fixed value** on a form-lead designation. A form submission carries no amount of its own, so a designation left on "use the record's own value" will save and arm quite happily and then upload nothing — every candidate is refused for having no value, rather than sent as a zero. That refusal is deliberate: a zero-value conversion actively teaches the bidding algorithm the lead was worthless.

Uploads are supported for **Google Ads**, **Microsoft Advertising** and **Meta**. LinkedIn and TikTok can be connected for reporting but cannot receive uploads.

## The two gates

Nothing uploads until **both** are satisfied. This is deliberate: each one alone is a plausible-looking half-configuration that would otherwise fail silently.

<Steps>
  <Step title="The account is opted in">
    A per-account switch, off by default. No account has ever uploaded a conversion without someone turning this on.
  </Step>

  <Step title="At least one source is armed">
    A designation points a source at a specific conversion action on a specific ad account, and is then armed. A designation lands **unarmed** unless you explicitly ask otherwise.
  </Step>
</Steps>

Being opted in with nothing armed uploads nothing. A run in that state refuses with `source_not_designated` rather than reporting a quiet success.

## Hiveku never creates a conversion action

The destination must already exist on the ad account. Creating conversion actions on a client's account is not something a marketing tool should do on your behalf.

How you point at it differs by platform:

* **Google Ads** — Hiveku lists the account's own conversion actions to pick from, and ownership-checks the one you choose against that account both when the designation is saved and again at upload time. If the list comes back empty, create one in Google Ads first with an import or offline source.
* **Microsoft Advertising** — you type the offline conversion goal name exactly as it appears in Microsoft. There is no picker, and no ownership check: a typo becomes a silent non-match at upload.
* **Meta** — you type the Conversions API event name, such as `Lead` or `Purchase`.

<Tip>
  Prefer a conversion action that counts **one per click**. A many-per-click action counts a repeat customer more than once against the same click, which inflates that campaign's apparent performance. The designation screen warns when the action you pick counts many-per-click.
</Tip>

## Validate-only: proving the payload before it counts

Enabling conversion uploads **always** lands in validate-only. A request that tries to enable it and take it live in the same call is rejected outright rather than quietly downgraded — going live is a separate, deliberate second step.

In validate-only, Google receives the upload as a validation request: it checks the payload and **records nothing**. You get to see that a real upload would be accepted, without a single conversion reaching the bidding model.

<Warning>
  Only Google Ads offers a platform-side validation mode. Microsoft and Meta rows are parked **locally**: no conversion is sent and nothing is recorded on either platform. Hiveku still resolves the connection's credentials first, and for Meta looks up the pixel or dataset — read-only calls that record nothing. Those rows are counted separately and never described as proven, because nothing checked them.
</Warning>

### Going live is two actions, not one

Flipping to live does not release what was already parked. That is a separate button, on purpose: turning the switch should not push a backlog of accumulated conversions into a client's bidding model in the same click.

The sequence in full:

1. Designate a conversion action for a source
2. Arm it
3. **Preview** — a true dry run that touches no credential and writes nothing
4. **Enable** — lands in validate-only
5. **Prove** — run it; the payload is validated, nothing is recorded
6. **Go live** — new conversions record for real
7. **Release** — requeue the parked backlog, when you are ready for it

Every configuration step is reversible, and there is a switch-off available at any point, including while live. What cannot be reversed is an upload that already landed — a recorded conversion cannot be un-sent. That asymmetry is exactly why validate-only and the separate release step exist.

## Why a conversion is refused

Most refusals are correct and expected. The run report names a reason for every one rather than reporting a bare count, and these are the ones you will actually see:

<AccordionGroup>
  <Accordion title="no_click_id">
    The record carries no ad click ID, so there is nothing to match against. Usually the most common reason, and the first one worth checking. A lead that arrived organically, or with tagging stripped, simply cannot be uploaded — the platform has nothing to join it to.
  </Accordion>

  <Accordion title="conversion_precedes_click">
    The conversion is dated **before** the click that supposedly produced it, which is impossible. Usually a clock or ordering problem in the source record. Refused rather than uploaded with a nonsensical timestamp.
  </Accordion>

  <Accordion title="source_not_designated">
    No conversion action is designated for that source, or the designation exists but is not armed. This is the second gate doing its job.
  </Accordion>

  <Accordion title="Consent was explicitly denied">
    Where the visitor's advertising signal is an explicit denial, the record is suppressed and never uploaded. Only an explicit denial suppresses — a record carrying no signal is unaffected.
  </Accordion>

  <Accordion title="The conversion is too old for the platform">
    Each platform bounds how old a conversion can be. Meta's Conversions API rejects an **event** older than 7 days — measured from the conversion, not the click — so anything left sitting in validate-only that long is skipped rather than sent. Hiveku will not let you create a new Meta designation while the account is still in validate-only, precisely to stop a backlog quietly ageing out. Google and Microsoft bound the age of the **click** instead, and their windows are far longer.
  </Accordion>
</AccordionGroup>

<Note>
  A high `no_click_id` count is usually a **tracking** finding, not an upload finding. It means leads are arriving without recoverable ad click IDs, which is worth fixing upstream — see [How Attribution Works](/marketing/attribution).
</Note>

## Duplicates and repeat uploads

Every upload carries a stable identifier derived from the source record. **Google and Meta dedupe on it platform-side**, so re-running a batch cannot create a second conversion for the same deal. Microsoft's offline-conversion API accepts no such key, so there the protection is Hiveku's own record of what it already sent rather than anything Microsoft enforces.

On Google, a row the platform already has comes back marked as a duplicate and is recorded as a **success**, not a failure. Meta absorbs a repeat silently on the same identifier. Microsoft reports no duplicate class at all.

Removing a designation does not send anything behind your back either: rows already queued for that source are marked skipped rather than dispatched.

## What is deliberately not sent

* **No personal data to Meta.** The Meta path sends only the click parameter. Enhanced matching — a hashed email or phone used **instead of** a click ID, so the platform matches the person rather than the click — is refused for Meta on policy grounds. Google and Microsoft support it. A row is matched one way or the other, never both.
* **Nothing while validate-only is on.** Not partially, not for some platforms. Nothing.
* **Nothing from a source with no armed designation.**

## Watching it work

The outbox records every row's state: queued, validated, uploaded, failed or skipped, with an error code where there is one.

<Warning>
  Not every error code is a failure. A validate-only park and a duplicate the platform already had both carry a code while being entirely normal outcomes. Genuine failures are listed separately from these, so a healthy account does not present a wall of alarming-looking rows.
</Warning>

## What's next

<CardGroup cols={2}>
  <Card title="How Attribution Works" icon="route" href="/marketing/attribution">
    What gets captured, and why numbers differ from the platform's
  </Card>

  <Card title="Connecting Ad Accounts" icon="plug" href="/advertising/connecting-accounts">
    Connect Google, Microsoft and Meta
  </Card>

  <Card title="Phone Tracking" icon="phone" href="/communications/phone-tracking">
    Call conversions upload on their own separate switch
  </Card>

  <Card title="Advertising Reports" icon="chart-line" href="/advertising/reports">
    Campaign ROI once outcomes are flowing back
  </Card>
</CardGroup>
