Integration · Google Ads

Google Ads Conversions API — server-side, on behalf of merchants.

AdsPing forwards conversion events from our customers’ websites to their own Google Ads accounts via the Google Ads API (Conversions API). We do not manage campaigns, modify bids, or touch any account-side resource — we restore conversion signals that ad blockers and iOS Safari ITP block on the client.

Manager Account
838-601-4858
API operations used
3 read · 1 write
Campaigns modified
None — ever
Token storage
AES-256-GCM at rest

Use case

Built for D2C e-commerce merchants on Google Ads.

Our customers are direct-to-consumer e-commerce merchants on Shopify, WooCommerce, and custom storefronts, typically spending $5,000–$200,000 per month on Google Ads. On modern browsers, 30–50% of their client-side gtag conversions are lost to ad blockers and iOS Safari ITP cookie restrictions. The signals never reach Google Ads, and Smart Bidding starves on incomplete data.

AdsPing closes this gap. A merchant installs our tracking snippet (pb.js), authenticates their own Google Ads account via OAuth 2.0, and picks which conversion action should receive forwarded events. From that moment, every Purchase, Lead, or AddToCart on their site is delivered to their Google Ads account via customers:uploadClickConversions — on the server, bypassing the client-side losses.

Every API call AdsPing makes is on behalf of a paying merchant who has authenticated their own Google Ads account. AdsPing never advertises for itself through customer accounts. The merchant retains full control of their campaigns, budgets, bidding, and conversion actions — AdsPing only writes the conversion events the merchant explicitly wired.

Example merchant

Shopify store selling premium skincare, $40K/month on Google Ads

  • Before AdsPing: ~62% of purchases attributed in Google Ads (iOS Safari + ad-blocker losses)
  • After AdsPing: ~96% attributed via combined gtag + Conversions API forwarding
  • Effect on bidding: Smart Bidding learns from the recovered signals; CPA drops 18% over 6 weeks (target ROAS unchanged)
  • Time to setup: ~12 minutes total — install snippet, OAuth, pick conversion action, test

Architecture

How conversion events reach Google Ads.

┌──────────────────┐     HTTPS      ┌──────────────────────┐
│  Merchant site   │  ────────────► │  AdsPing backend     │
│  + pb.js snippet │                │  (NestJS, Fastify)   │
│  (visitor's      │                │                      │
│   browser)       │                │  - Postgres (Prisma) │
└──────────────────┘                │  - Redis + BullMQ    │
                                    │  - Sentry            │
                                    └──────────┬───────────┘
                                               │ OAuth Bearer
                                               │ + developer-token
                                               ▼
                                    ┌──────────────────────┐
                                    │  Google Ads API      │
                                    │  googleads.gapi.com  │
                                    └──────────────────────┘

Browser-side gtag fires in parallel (legacy send_to or new named-event format) for ad-blocker-free visitors. Google dedups the server-side and browser-side copies by gclid + timestamp, so no conversion is counted twice.

API operations

Exactly which Google Ads API operations we call.

Read — onboarding only

  • customers:listAccessibleCustomersOnce per OAuth flow

    Populates the merchant's Google Ads customer picker during onboarding. We enumerate the accounts they have access to, never beyond what their own OAuth grant exposes.

  • GoogleAdsService.search (customer)One-time per customer

    Resolves the human-readable account name for the customer picker dropdown. Query: SELECT customer.id, customer.descriptive_name FROM customer LIMIT 1.

  • GoogleAdsService.search (conversion_action)One-time per customer

    Lists ENABLED conversion actions so the merchant can pick which one should receive forwarded events. Query restricts to conversion_action.status = 'ENABLED'.

Write — per conversion event

  • customers:uploadClickConversionsPer merchant conversion event

    The core operation. Called once per Purchase / Lead / AddToCart / etc. on a merchant's site. Anchored on gclid (preferred), gbraid/wbraid (iOS App Campaigns), or Enhanced Conversions identifiers (SHA-256 hashed email + phone). Includes orderId for cross-channel dedup.

  • customers:uploadConversionAdjustmentsPlanned — Q3 2026

    For forwarding Shopify refunds as negative-value adjustments so Smart Bidding sees restated ROAS. Same OAuth scope, same authentication pattern, same per-merchant credentials.

Sample uploadClickConversions request

The complete payload for a single Purchase event, exactly as AdsPing constructs it. customerId and conversionActionId are merchant-supplied during onboarding; gclid + hashed identifiers come from the visitor’s session.

POST https://googleads.googleapis.com/v20/customers/1234567890:uploadClickConversions
Authorization: Bearer <merchant_access_token>
developer-token: <adsping_developer_token>
login-customer-id: 8386014858

{
  "conversions": [{
    "conversionAction": "customers/1234567890/conversionActions/987654321",
    "conversionDateTime": "2026-05-13 12:34:56+00:00",
    "gclid": "Cj0KCQjw...",
    "conversionValue": 199.90,
    "currencyCode": "USD",
    "orderId": "SHOPIFY-1043",
    "userIdentifiers": [
      { "hashedEmail": "<sha256>" },
      { "hashedPhoneNumber": "<sha256>" }
    ]
  }],
  "partialFailure": true
}

Operations we never call

  • customers:mutate — no campaign, ad group, keyword, or budget changes
  • googleAds:mutate — no resource-graph mutations of any kind
  • Recommendations API — we don't read or apply optimization recommendations
  • Audience uploads / Customer Match — out of scope
  • Asset library / creative uploads — never accessed
  • Change history, billing setup, account-level configuration — never accessed
  • Reporting beyond the read operations listed above — no campaign-level analytics fetched

Supported conversion types

Every standard merchant-side action maps to a Google Ads conversion.

One AdsPing pipeline = one Google Ads conversion action. A merchant can wire multiple pipelines per pixel to track every meaningful step in their funnel.

Typepb.js eventGoogle Ads conversionNotes
PurchasePurchaseWebsite → Purchasevalue + currency + orderId required for Smart Bidding accuracy
LeadLeadWebsite → Submit lead formAuto-detected on form submit by pb.js (no merchant code needed)
Add to cartAddToCartWebsite → Add to cartAuto-bridged from GA4 dataLayer push if present
Phone clickPhoneCallPhone calls → Clicks on phone numberAuto-detected when visitor clicks any tel: link
Begin checkoutInitiateCheckoutWebsite → Begin checkoutFires from /checkout route or merchant code
Sign-upSignUpWebsite → Sign-upFor SaaS / membership merchants
WhatsApp clickWhatsAppClickCustom (configured per merchant)Common for service businesses in Turkey + LATAM
Appointment requestAppointmentRequestCustom (configured per merchant)Healthcare, beauty, consulting verticals

OAuth & security

Merchant credentials, protected end-to-end.

Scopes requested

  • adwords — Google Ads API (this integration)
  • analytics.readonly — list GA4 properties (optional, separate)
  • tagmanager.readonly — list sGTM containers (optional, separate)

Token handling

  • Access & refresh tokens encrypted with AES-256-GCM at rest
  • Decrypted only at upload time, never logged in plaintext
  • Per-merchant isolation — no cross-account access
  • TLS 1.2+ for every outbound call to Google

PII handling

  • Email and phone hashed with SHA-256 before transit (Enhanced Conversions)
  • Raw PII never persisted at AdsPing
  • GDPR / CCPA compliant, Limited Data Use mode for opted-out visitors

Revocation

  • Merchants can revoke AdsPing’s access at myaccount.google.com/permissions at any time
  • On revoke, the next upload fails with invalid_grant and AdsPing automatically stops further calls
  • The merchant is notified by email to reconnect or delete

Click-to-conversion flow

From visitor click to Google Ads conversion.

[1] Visitor clicks a Google ad → Google appends gclid to landing URL
[2] Merchant's site loads pb.js → extracts gclid → first-party cookie (90-day TTL)
[3] Visitor browses, returns days later, completes Purchase
[4] pb.js sends event { gclid, value, currency, hashed_email } to AdsPing backend
[5] AdsPing backend:
      - Validates event, sanitizes payload
      - Looks up pipeline → decrypts merchant's Google Ads access token
      - Enqueues to BullMQ (per-merchant concurrency cap)
[6] Worker pops event:
      - POST customers:uploadClickConversions
      - On 401: refresh access token, retry once
      - On 4xx: mark failed (no retry storm)
      - On 5xx: exponential backoff up to 8 attempts, then dead-letter
[7] Google Ads matches gclid → original click → campaign + keyword
[8] Smart Bidding ingests the signal, adjusts future bids

The merchant’s campaigns, bidding strategies, budgets, and conversion-action definitions are never touched. AdsPing’s only mutation on the merchant’s account is the conversion upload itself.

Required Minimum Functionality

How AdsPing meets the Google Ads API Required Minimum Functionality.

The Google Ads API Required Minimum Functionality (RMF) policy sets the baseline behavior every third-party integration must satisfy. Each section below names the policy intent and how AdsPing implements it.

  • Account linking via OAuth 2.0

    Every merchant explicitly authorizes AdsPing via Google's standard OAuth 2.0 authorization-code flow with offline access. The consent screen lists the requested scopes (adwords, analytics.readonly, tagmanager.readonly) before the merchant approves. We never accept credentials directly.

  • Per-merchant credential isolation

    Every merchant's OAuth refresh token is scoped to their account row. Encrypted at rest with AES-256-GCM, decrypted only when uploading their conversions. Cross-tenant access is structurally impossible — there is no admin endpoint that crosses tenant boundaries.

  • Conversion uploads only — no campaign mutation

    Our use of the Google Ads API is restricted to uploadClickConversions (write) and the onboarding metadata reads listed above. We do not call any mutate endpoint. The merchant retains full control of campaigns, budgets, bidding, conversion-action definitions, and account access.

  • Required identifiers handled correctly

    Every conversion includes orderId for dedup against any merchant-side gtag conversion, conversionDateTime in correct ISO 8601 format, and exactly one of gclid / gbraid / wbraid / userIdentifiers (Enhanced Conversions). Partial-failure mode is enabled so per-event errors don't poison batches.

  • User identifiers hashed with SHA-256

    When a merchant opts into Enhanced Conversions, email and phone are normalized (lowercase, trimmed, country code added) and SHA-256 hashed in the merchant's browser before being sent to AdsPing. We never receive or persist plaintext PII.

  • Revocation honored immediately

    If a merchant revokes AdsPing at myaccount.google.com/permissions, the next upload returns invalid_grant. AdsPing detects this within seconds, disables further uploads to that account, and emails the merchant. We never retry against a revoked token.

  • Rate limit and quota handling

    On RESOURCE_EXHAUSTED, requests back off exponentially up to 8 retries before being dead-lettered. Per-merchant in-flight concurrency caps prevent any single merchant from saturating our developer token's quota. Global BullMQ concurrency is capped at 10 workers.

  • Logging and audit trail

    Every conversion upload (success or failure) is logged with timestamp, merchant ID, customer ID (last 4 digits), conversion action ID, and the orderId. OAuth events are audited separately. Plaintext tokens never appear in logs.

Reliability & operations

Built for the merchant data we’re trusted with.

Queue + retry

Every conversion event lands in a per-merchant BullMQ queue. Workers process with exponential backoff (up to 8 attempts on 5xx). Terminal failures route to a dead-letter queue that surfaces in the merchant’s dashboard — never silently dropped.

Idempotency

Every event has a deterministic event_id and orderId. If a worker retries after a transient failure, Google dedups the conversion. We never double-count.

Per-merchant rate caps

Per-merchant in-flight concurrency is capped (default 5, agency tier up to 20). No single merchant can saturate AdsPing’s shared developer-token quota. On RESOURCE_EXHAUSTED, jobs back off rather than thrashing.

Observability

Sentry receives every worker error. The merchant dashboard surfaces per-pipeline last error + timestamp. Auth-class failures auto-disable the pipeline to prevent retry storms and notify the merchant by email.

Merchant experience

What it looks like from the merchant’s side.

  1. 01

    Create AdsPing account

    Email + password, 2FA optional. 14-day trial, no credit card required.

  2. 02

    Create a pixel for the site

    Name it (e.g. "Shopify store — apparel.com"). AdsPing generates a pixel ID and the script tag.

  3. 03

    Paste the script into the site <head>

    One line. On Shopify, this goes in theme.liquid or via Custom Pixel. WooCommerce, Webflow, custom sites — same one-liner.

  4. 04

    Connect Google Ads via OAuth

    On the pixel's Destinations tab, click "Connect Google Ads". Google's consent screen lists the requested scopes. Approve. AdsPing fetches the merchant's accessible customers + their conversion actions.

  5. 05

    Pick a conversion action and an event

    From dropdowns: customer (e.g. 1234567890), conversion action (e.g. "Purchase"), event name filter (e.g. Purchase). Save. The pipeline is now live.

  6. 06

    Verify in the dashboard

    Trigger a test conversion on the site. Within 5–10 seconds it appears in AdsPing's Recent Events with a Success badge. Google Ads UI lags 3–24 hours but reflects the conversion under the conversion action's Recent Conversions tab.

Frequently asked questions

Google Ads-specific FAQ.

Why do you need write access to merchant accounts at all?
The Conversions API is fundamentally write-only — uploadClickConversions is how conversions enter Google Ads from any external source (including Google's own tools). We have no read access beyond the onboarding metadata listed above. We never call any mutate endpoint that changes campaigns, bids, budgets, or any other account-side resource.
What's the difference between AdsPing and the Google tag (gtag) that Google provides for free?
The Google tag fires client-side and is intercepted by ad blockers (~10–20% of users), weakened by iOS Safari ITP (~30% of mobile sessions), and lost when JavaScript fails. AdsPing fires the Conversions API server-side, which is immune to all three failure modes. We run both in parallel — Google dedups by gclid + timestamp, so merchants never double-count.
Can a merchant grant AdsPing access to accounts they don't own?
No. The OAuth flow uses standard authorization-code grant. The set of accessible Google Ads customers returned by listAccessibleCustomers is exactly the set the merchant has access to in their own Google Ads UI. We cannot list, read from, or write to any other customer.
What happens if the merchant's OAuth refresh token expires or is revoked?
On the next upload, Google returns invalid_grant. AdsPing's health monitor detects this within seconds, marks the pipeline as auth_failed, and emails the merchant with a one-click reconnect link. We never retry against a revoked token. While auth_failed, browser-side gtag fallback keeps firing — server-side resumes when the merchant reconnects.
How does AdsPing prevent abuse of its developer token?
Three layers: (1) every merchant pays a subscription before they can configure a pipeline — there's no free-API-call tier that allows anonymous abuse; (2) per-merchant in-flight concurrency caps prevent any single account from saturating quota; (3) suspicious patterns (high failure rates, unusual conversion volumes) auto-pause the merchant pending review.
Do you store any merchant or end-user PII?
No raw PII. Email and phone for Enhanced Conversions are normalized + SHA-256 hashed in the visitor's browser before being sent to AdsPing — we never receive plaintext. Hashed identifiers are forwarded to Google and not persisted past the upload. The merchant's own account email is stored for product login / billing only.
Where are merchant OAuth tokens stored, and how are they protected?
In a managed Postgres database on Railway (EU + Turkey regions available). Tokens are encrypted at rest with AES-256-GCM using a key held only in the application's runtime environment (Railway secret manager). The database never sees plaintext tokens. Decryption happens only at upload time inside the worker process.
What's the timeline for AdsPing to call the API after a merchant action?
Typical event reaches our backend in ~80ms. The worker dequeues and posts to googleads.googleapis.com within 100–500ms (depending on queue depth). End-to-end p95: under 800ms. Google Ads UI then has its own 3–24 hour processing window before the conversion appears in reports.
How are pipelines validated before going live?
When a merchant wires a new pipeline, AdsPing performs a structural validation (customer ID resolvable, conversion action ENABLED, OAuth scope present) before accepting it. The merchant can fire a test event from their site and watch it appear in the Recent Events dashboard within seconds, confirming the end-to-end path is working before relying on it for paid traffic.
How do we contact AdsPing if Google has follow-up questions?
[email protected] — monitored by our engineering team during European business hours and async over weekends. For compliance-specific questions, our developer contact email on the Google Ads API Center is kept up-to-date.

About AdsPing

Who we are.

AdsPing is an independent software company building server-side conversion infrastructure for paid acquisition teams. We support Meta Conversions API, TikTok Events API, GA4 Measurement Protocol, GTM Server-side, and Google Ads Conversions API as parallel destinations on a single tracking snippet.

Company
AdsPing
Istanbul, Türkiye — serving merchants globally
Contact
[email protected]
Engineering & merchant relations
Manager account (MCC)
838-601-4858
Infrastructure
NestJS + Postgres + Redis on Railway
AES-256-GCM at rest, TLS 1.2+ in transit

Full legal documentation: Privacy Policy · Terms of Service · Data Processing Agreement · Security.

Stop losing Google Ads conversion signals.

14-day free trial. No credit card. 10,000 events / month free forever after that.