Objective 1 from the client doc "4 Star Data Setup": get the Data Manager API set up for offline conversions in Google Ads + events in GA4, with per-row visibility into which rows did not import, orchestrated in n8n. (= Phase 1 / sold scope.)
Author: Diego Sanz (Vantage Node). Drafted 2026-06-18, informed by the platform audit
(platform-audit-2026-06-18.md) and client ground truth (4star-data-setup-notes.md).
Source of truth = Supabase (CRM SQL Server, hourly sync).
An offline Quote/Order only counts in Google Ads if it can be tied back to the original ad click. Three possible keys; we must confirm which exist in Supabase before any build:
Conversion Linker (_gcl prefix), so gclid is captured in the
cookie; unknown whether it's written to the form payload → CRM → Supabase.user_email + user_phone, so viable if they
land in Supabase. (Depends on the RFQs enhanced-conversions setup, currently flagged.)Risk: if none of these is stored per row, a website tracking change is required first (capture + persist gclid/PII at RFQ submit). That is the difference between "straightforward" and "blocked on a code change." This is the #1 discovery item — see
mezar-discovery-questions.md.
| CRM stage | Google Ads conversion action | Current state |
|---|---|---|
| RFQ | RFQs (web tag) + rfq_thankyoupage_ga (GA4 import, observation) |
Active; EC ⚠ setup issue |
| Quote | Quotes — "Website (Import from clicks)" |
Active — offline import target |
| Order | Orders — "Website (Import from clicks)" |
⚠ Needs attention — offline import target |
The offline-import actions for the two CRM stages already exist; we feed them, we don't
create them. Confirm each action's count setting, value handling, and conversion window, and
diagnose the Orders "needs attention" state before go-live.
C:\DataStudiosGithub\credentials\). Data Manager API needs no developer token.
Scopes: Google Ads + GA4 (Analytics).Quotes + Orders: confirm import-readiness, value, window, count;
diagnose Orders "needs attention."RFQs enhanced-conversions setup issue (matters if matching on PII).Schedule (daily) → Query Supabase (new/changed Quote+Order rows since watermark) →
Transform → Data Manager payload (match key + conversion action + conversion time + value) →
Upload to Google Ads (Data Manager) → Parse per-row response →
Write status back to Supabase (success/fail + error per row) → Alert on failures →
Advance watermark. (GA4 events as a parallel branch in Phase 3.)
Founder principles to bake in (from the client doc): - Daily cadence is fine — Supabase sync is hourly; do not promise sub-hour freshness. - Exclude unsettled days — set the upload cutoff to skip the still-moving recent window. - Conversion time = actual event time, not upload time (correct attribution dating). - Idempotency — use quote_id/order_id as the dedupe key so re-runs never double-count (relevant given the RFQ-side over-counting already observed).
import_status (pending/success/failed),
import_error, imported_at, conversion_action, run_id. (Or a dedicated
conversion_import_log table keyed by quote_id/order_id.)| # | Decision | Options | Owner |
|---|---|---|---|
| 1 | Match key | gclid / ECL (hashed PII) / both | Client + Diego (needs Supabase) |
| 2 | GA4 ingestion | Measurement Protocol / Data Manager | Diego |
| 3 | Cadence + unsettled-day cutoff | daily; cutoff = ? days | Diego + client |
| 4 | Where per-row status lives | Supabase column / log table / sheet | Diego |
| 5 | Value per stage | use Quote/Order $ value or fixed? | Client |
| Dependency | Status | Needed for |
|---|---|---|
| Google Ads / GA4 / GTM access | ✅ active | discovery, validation |
| dsanz@ OAuth token | ⏳ to mint (Phase 0) | all API writes |
| Supabase access + schema | ❌ blocked | Phases 1–2 (and match-key confirmation) |
| n8n instance | ❌ blocked | Phase 2 |
| Match key in Supabase | ❓ unknown | whether a website change is needed first |
Net: Phase 0 de-risks now; the pipeline is gated on Supabase + n8n. Chase the match-key confirmation hardest — see the discovery questions for Mezar.