Date: November 25, 2025 Priority: High Estimated Recovery Time: 2-4 weeks
Conversion tracking broke in September 2025, causing ~3 months of "Maximize Conversions" bidding to run without conversion data. The algorithm has been optimizing blind, likely wasting budget on lower-quality traffic.
Root Cause: WhatConverts stopped pushing conversions to Google Ads (disconnected integration).
Status: Fixed as of Nov 26, 2025
GoogleAdsConversionUploadService| Month | Conversions | Spend | CPA | Status |
|---|---|---|---|---|
| Nov 2024 | 158 | $4,414 | $27.93 | Healthy |
| Dec 2024 | 115 | $3,837 | $33.37 | Healthy |
| Jan 2025 | 167 | $4,542 | $27.20 | Healthy |
| Feb 2025 | 145 | $3,797 | $26.19 | Healthy |
| Mar 2025 | 151 | $4,255 | $28.18 | Healthy |
| Apr 2025 | 134 | $3,681 | $27.47 | Healthy |
| May 2025 | 119 | $2,683 | $22.54 | Healthy |
| Jun 2025 | 135 | $2,478 | $18.35 | Healthy |
| Jul 2025 | 87 | $2,452 | $28.18 | Declining |
| Aug 2025 | 56 | $2,242 | $40.03 | 50% drop |
| Sep 2025 | 1 | $2,084 | $2,084 | BROKE |
| Oct 2025 | 6 | $1,941 | $323 | Broken |
| Nov 2025 | 1 | $1,550 | $1,550 | Broken |
Duration: 2-4 weeks
Steps:
Switch Bidding Strategy (Today)
Monitor Conversion Accumulation (Week 1-2)
Evaluate Performance (Week 2)
Fine-tune (Week 3-4)
Duration: 2-4 weeks
Steps:
Switch to Target CPA (Today)
Adjust Based on Performance (Weekly)
Consider Switching Back (Week 4+)
For Multiple Campaigns:
If you have separate campaigns (e.g., Dumpsters, Mobile Offices, Storage):
/admin/conversions)google_ads_status column)Phone Call Test
Chat Test
Location: Google Ads > Goals > Conversions
Verified conversion action:
UPLOAD_CLICKS conversion type for offline trackingPhone Calls ──► WhatConverts ──► Webhook (/webhooks/whatconverts) ─┐
│
▼
Conversion Model
(PostgreSQL)
│
Crisp Chat ──────────────────► Webhook (/webhooks/crisp) ──────────┘
│
▼
PushConversionToGoogleAdsJob
│
▼
GoogleAdsConversionUploadService
│
▼
Google Ads API (Conversion Upload)
Action: "Leads (91576)" ID: 811560869
| Component | Purpose |
|---|---|
Conversion model |
Stores all leads with gclid, UTM data, contact info |
PushConversionToGoogleAdsJob |
Background job triggered on new conversion |
GoogleAdsConversionUploadService |
Direct API upload to Google Ads |
/webhooks/whatconverts |
Receives phone calls & forms from WhatConverts |
/webhooks/crisp |
Receives chat leads from Crisp |
GOOGLE_ADS_CUSTOMER_ID=776-391-2839
GOOGLE_ADS_LOGIN_CUSTOMER_ID=623-323-9884
GOOGLE_ADS_CONVERSION_ACTION_ID=811560869
GOOGLE_ADS_DEVELOPER_TOKEN=(set in secrets)
# Check conversion counts
kamal app exec --reuse "bin/rails runner 'puts Conversion.count'"
# Check push status
kamal app exec --reuse "bin/rails runner 'puts Conversion.group(:google_ads_status).count'"
# View recent conversions
kamal app exec --reuse "bin/rails runner 'Conversion.last(5).each { |c| puts \"#{c.id}: #{c.lead_type} - #{c.google_ads_status}\" }'"
| Week | Expected Conversions | Expected CPA | Action |
|---|---|---|---|
| 1 | 15-25 | $40-60 | Monitor, don't panic |
| 2 | 25-40 | $30-45 | Evaluate progress |
| 3 | 35-50 | $25-35 | Consider strategy switch |
| 4 | 40-50+ | $22-30 | Should be stabilizing |
If you see any of these, take action:
| Issue | Threshold | Action |
|---|---|---|
| No conversions | 0 for 3+ days | Check WhatConverts integration |
| CPA spike | >$75 | Lower bids or switch to Manual CPC |
| Spend spike | >150% of normal | Check for runaway keywords |
| Click volume drop | <50% of normal | Check ad status, budgets |