If one purchase becomes two Google Ads conversions, trace the order through each destination action before changing the count setting. A thank-you-page reload, two separate purchase actions and an additional server data source are different configurations. The same transaction ID does not merge everything in the account.

A mismatch alone does not prove duplication. Compare the same account, dates, time zones, attribution windows, outcome and value definition. Google Ads may attribute only part of your store’s orders, while a report can include several different actions. Start by segmenting the report by conversion action.

Find the boundary before removing a tag

PatternFirst checkWhat will not settle it
Confirmation page sends againSame business order, destination action and exact transaction IDCounting browser requests as accepted conversions
Native purchase plus GA4-imported purchaseSeparate action IDs, their settings and the campaign’s selected goalAssuming the same order ID merges separate actions
Tag plus additional backend sourceSupported integration, same destination action, exact ID and value unitsAssuming all browser/server combinations share one rule
Several real purchases after one ad clickDifferent confirmed orders versus repeated sends of one orderChanging every purchase action to One

Use the business transaction, not the page load

For Google Ads, a repeated transaction ID is deduplicated within the same conversion action. Generate an opaque ID per actual order in the backend or commerce system, retain it on retries and reloads, and use a different ID for a different order. Do not use email, a customer ID, a fixed thank-you label or a newly generated page-load ID. Google documents a 64-character limit for these transaction IDs.

In GTM, inspect the confirmed-purchase data-layer event, create a Data Layer Variable for the actual transaction-ID key, and map it to the Google Ads tag’s Transaction ID field. Check the resolved value in Preview and Tag Assistant. A literal template expression or undefined is a broken mapping, even if the tag fires. Avoid adding another purchase trigger while the original sender remains unexplained.

GA4 has its own purchase deduplication rules. Its documented transaction-ID deduplication applies to web streams, not app streams, and involves purchases from the same user. An empty transaction ID can suppress purchases; a shared ID across different orders can undercount. Do not treat a raw event row or an identifier alone as a universal cross-stream, cross-user merge guarantee.

Google Ads transaction-ID instructions; GA4 purchase deduplication scope. Checked 3 November 2026.

Separate counting from bidding eligibility

One limits counting per ad click within an action; Every allows multiple valuable conversions. Neither setting joins two separate purchase actions. For purchases, preserve distinct legitimate orders rather than hiding duplication by reducing the count.

Inspect Goals → Conversions → Summary, then the campaign’s actual goal settings. For a standard goal, a primary action is used for bidding when the campaign uses that goal. Secondary actions normally remain in All conversions for observation. A secondary action included in a selected custom goal is still used for bidding. Review account defaults, campaign overrides and custom-goal membership before deciding that changing Primary to Secondary solved the overlap.

Choose an authoritative purchase outcome and compare the coverage of the overlapping sources before changing them. Keep a record of the action, campaign scope, owner and change date. A lower future conversion total after removing an overlapping bidding action is not, by itself, evidence that real sales fell. The setting change also does not prove historical data has been repaired.

Google Ads counting options; primary, secondary and custom goals; campaign-specific goals. Checked 3 November 2026.

Browser and server delivery can be supported together

Google’s multi-source conversions feature is currently documented as a beta. It supports adding eligible backend data to a manually coded website conversion action through Data Manager or its supported API path. It is not the same as making a second GA4-imported purchase action. Check feature eligibility in your account; Google lists imported Analytics and URL-based conversion actions as ineligible for that setup.

Within the configured action, the additional source uses the exact transaction ID to match the tag event. Google explicitly says this does not deduplicate across other actions. Matching uploads can update value and currency, so dollars versus cents, currency and trial behavior matter. Consent and attribution fields also remain part of the documented setup. Review the current requirements before adding a new sender; matching IDs alone do not implement this integration.

Google Ads multi-source conversions: eligibility, matching, value updates and trial behavior. Checked 3 November 2026.

Run an eight-row identity exercise locally

This fixed synthetic SQLite example separates three known business orders from eight delivery rows. It groups non-empty transaction IDs by target account and action, while preserving missing-ID rows as unresolved. The additional_source label describes the example’s intended route; it does not certify any real account integration.

Download the local conversion-identity SQL, save it in your working folder and run:

python3 - <<'PY'
import sqlite3
from pathlib import Path
connection = sqlite3.connect(':memory:')
setup, report = Path('conversion-identity-demo.sql').read_text().split('-- BEGIN REPORT\n', 1)
connection.executescript(setup)
for metric, value in connection.execute(report):
    print(f'{metric}: {value}')
PY
Inspect the complete synthetic SQL
-- Fixed synthetic delivery log, not a Google reporting/deduplication engine.
-- A send row does not prove destination acceptance or an attributed conversion.
-- Business order IDs are known local records; transaction IDs are sent values.
CREATE TEMP TABLE business_orders (order_id TEXT PRIMARY KEY);
INSERT INTO business_orders VALUES ('order_101'), ('order_102'), ('order_103');
CREATE TEMP TABLE delivery_log (
  delivery_id INTEGER PRIMARY KEY,
  order_id TEXT NOT NULL,
  target_account TEXT NOT NULL,
  action_id TEXT NOT NULL,
  transaction_id TEXT,
  source TEXT NOT NULL
);
INSERT INTO delivery_log VALUES
  (1, 'order_101', 'test_account', 'native_purchase', 'order_101', 'browser'),
  (2, 'order_101', 'test_account', 'native_purchase', 'order_101', 'reload'),
  (3, 'order_101', 'test_account', 'ga4_import', 'order_101', 'analytics'),
  (4, 'order_101', 'test_account', 'ga4_import', 'order_101', 'analytics_retry'),
  (5, 'order_102', 'test_account', 'native_purchase', 'order_102', 'browser'),
  (6, 'order_102', 'test_account', 'native_purchase', 'order_102', 'additional_source'),
  (7, 'order_103', 'test_account', 'native_purchase', NULL, 'browser'),
  (8, 'order_103', 'test_account', 'native_purchase', NULL, 'reload');

-- BEGIN REPORT
WITH identified_pairs AS (
  SELECT target_account, action_id, transaction_id, COUNT(*) AS rows_sent
  FROM delivery_log
  WHERE transaction_id IS NOT NULL AND LENGTH(TRIM(transaction_id)) > 0
  GROUP BY target_account, action_id, transaction_id
), order_actions AS (
  SELECT DISTINCT order_id, target_account, action_id FROM delivery_log
), multiple_actions AS (
  SELECT order_id FROM order_actions GROUP BY order_id HAVING COUNT(*) > 1
)
SELECT 'business_orders' AS metric, COUNT(*) AS value FROM business_orders
UNION ALL SELECT 'delivery_rows', COUNT(*) FROM delivery_log
UNION ALL SELECT 'identified_action_transaction_pairs', COUNT(*) FROM identified_pairs
UNION ALL SELECT 'missing_transaction_id_rows', COUNT(*) FROM delivery_log
  WHERE transaction_id IS NULL OR LENGTH(TRIM(transaction_id)) = 0
UNION ALL SELECT 'orders_sent_to_multiple_actions', COUNT(*) FROM multiple_actions
UNION ALL SELECT 'same_action_repeated_pairs', COUNT(*) FROM identified_pairs
  WHERE rows_sent > 1;
MetricResultInterpretation
business_orders3Known records in the synthetic order system
delivery_rows8Observed sends, including retries and missing IDs
identified_action_transaction_pairs3Non-empty keys grouped within target account and action
missing_transaction_id_rows2Rows requiring review; not merged by a missing key
orders_sent_to_multiple_actions1One known order was sent to two separate actions
same_action_repeated_pairs3Identified keys appearing in more than one send row

These are log checks, not Google conversion totals

The three identified pairs include one order in two actions. The two missing-ID rows cannot safely be collapsed into one conversion or counted as two accepted conversions. This exercise makes no network request, creates no database file and models neither attribution, consent processing, GA4 user identity nor Google’s internal deduplication. It does not change an account.

Audit the conversion actions you actually count

Use the sample or paste the read-only action export from the conversion-action export script. The audit runs in this browser. It reviews supplied settings for overlapping actions and goal risks; it cannot see tag firing, transaction IDs, live campaign selections or destination acceptance that are absent from the input.

Runs in this browser. Your action names and settings stay here.

Use the read-only export script below. Keep the header row. CSV and tab-separated exports with the same headers are accepted.

Check campaign goals to confirm bidding eligibility. Custom goals can include secondary actions. Match transaction or lead IDs to verify repeated events.

Keep the action report beside the event trail. A settings warning is a reason to inspect the implementation; it is not proof that a particular order was counted twice.

Validate one order, a reload and a different order

  1. In an appropriate test environment, confirm an order in the source system and record the exact intended action, transaction ID, value and currency. Document how test activity will be treated.
  2. Inspect the resolved event in GTM Preview/Tag Assistant and relevant delivery diagnostics. A fired tag or successful local job does not by itself prove the final report contains one attributed purchase.
  3. Reload or revisit that same confirmation. The business transaction ID should remain stable. Create a second distinct test order and confirm its ID differs; do not regenerate the first order’s ID to hide a retry.
  4. Trace every source and destination action. If an eligible additional data source is configured, verify its exact ID, destination, required fields, units and status. Treat absent IDs, mismatched prefixes and separate actions as distinct review cases.
  5. After processing, compare the intended action’s reporting with source orders, allowing for attribution, time zone, consent, reporting lag and scope. Review Conversions and All conversions separately and retain the change date and rollback.

Download the duplicate-conversion review worksheet.

Review worksheet fields
DUPLICATE CONVERSION REVIEW
Working checklist, not a Google upload format or account-changing script.

FREEZE THE COMPARISON
Account / campaign / actual selected standard or custom goal:
Date range / account and CRM time zones / review cutoff:
Conversions versus All conversions versus conversion-time reporting:
Attribution model / windows / business outcome / value definition:
Order source of truth and any test/refunded/cancelled order treatment:

MAP EACH PATH FOR THE SAME OUTCOME
Business order ID (opaque; no email or other customer identity):
Event trigger / original source / consent state:
Target account and conversion action identifier / owner:
Browser tag / GA4 import / platform plugin / server or Data Manager path:
Exact transaction_id sent on each path (missing stays missing):
Value / currency / units (dollars and cents are different):
Primary/secondary setting / campaign goal / custom-goal membership:
Count setting / actual destination diagnostics / evidence timestamp:

CONTROLLED VALIDATION
One confirmed order: correct ID, value, currency and action:
Reload/revisit same confirmation: original business ID stays stable:
Second distinct order: new business ID, even from the same ad click:
Different sources: same intended action and exact ID where supported:
Separate action or wrong ID: investigate, do not assume a shared merge:
Missing/empty/static/placeholder ID: preserve evidence and fix mapping:
GA4 purchase path: web versus app stream and collected user context:
Test activity treatment and validation environment documented:

CHANGE RECORD
Chosen authoritative purchase outcome and delivery owner:
Reason for retaining/removing an overlapping path from bidding:
Campaign-specific and custom goals reviewed before changing settings:
Tag/data-layer change / exact scope / owner / rollback:
If multi-source: feature eligibility, destination action, consent fields,
  exact ID match, value/currency/units and trial behavior verified:
Change date; before/after reports; reporting lag and business reconciliation:
Do not infer historical data is repaired merely because a setting changed.
Do not add an extra sender to compensate for an untraced missing event.

If there is no received lead to match, use the conversions-without-leads diagnostic. For storage retries, use the server acceptance and retry exercise. For attribution differences, use the conversion reconciliation guide.

AdProtektor adds observed-visit evidence and configurable protection. ConversionOS can participate in eligible configured event paths, but adding it does not automatically repair existing duplicate tags or merge separate actions. Review the integration’s actual delivery owner, supported destination and status. Website enforcement and fraud-aware event handling remain separate from transaction deduplication, Google billing and proof of a genuine customer.

If an incorrect duplicate already counted, review the exact original conversion with the Google Ads conversion adjustment guide.

Start a free AdProtektor trial to review the supported protection and event path for your site.