---
title: "Optimizing Meta Ads: Server-Side CAPI and Effective Lead Attribution"
description: Discover how to optimize your lead generation with a robust server-side architecture that ensures accurate data flow and maximizes ROI from your Meta ads.
image: https://arsalanfaysal.com/hubfs/AI-Generated%20Media/Images/Digital%20Marketing%20Data%20Flow%20Architecture.png
---

[AF. ROI Architect](https://arsalanfaysal.com)

 Services

CRM Architecture [HS HubSpot ArchitecturePipelines, cleanup, attribution](https://arsalanfaysal.com/hubspot-architecture-advanced-custom-solutions-for-crm) [GHL GoHighLevel SystemsSnapshots, API, HIPAA intake](https://arsalanfaysal.com/gohighlevel-solutions-custom-snapshots-and-api-integration) [ZO Zoho RevOpsEnterprise architecture](https://arsalanfaysal.com/zoho-enterprise-architecture-eliminate-lag-and-engineer-revops) [AT Airtable SystemsKill spreadsheet sprawl](https://arsalanfaysal.com/airtable-database-solutions-stop-spreadsheet-sprawl-arsalan-faysal)

Outbound & AI [CL Clay EnrichmentWaterfall list building](https://arsalanfaysal.com/automated-revenue-infrastructure-enhance-outreach-efficiency-clay) [AI Voice AI (Retell.ai)AI receptionist & routing](https://arsalanfaysal.com/voice-ai-solutions-automated-receptionists-retell.ai) [F9 Five9 CCaaSPredictive dialing & CTI](https://arsalanfaysal.com/custom-five9-ccaas-solutions-optimize-telephony-integration) [MN Monday.com OSWork OS transformation](https://arsalanfaysal.com/enterprise-work-os-solutions-transforming-monday.com-operations) 

[★ Full System The Revenue Engine Every tool wired into one self-operating GTM system — ads, CRM, outbound and voice AI working as a single machine. See All Services → 12×Avg ROI $10M+Pipeline](https://arsalanfaysal.com/custom-revenue-engines-for-growth-build-profitable-systems-arsalan-faysal)

 Case Studies

Pipeline Wins [$2M $2.1M Outbound EngineSaaS · 7 months](https://arsalanfaysal.com/outbound-revenue-success-2.1m-in-7-months-arsalan-faysal) [$8M $8.2M M&A PipelineInstitutional advisory](https://arsalanfaysal.com/fractional-paid-media-driving-8.2m-pipeline-for-ma-firm-arsalan-faysal) [28 28 Legal Leads / 90 DaysLaw firm · Fractional CMO](https://arsalanfaysal.com/fractional-cmo-transforms-law-firm-28-leads-in-90-days-arsalan-faysal)

Systems & AI [AI 100% CRM Data AccuracyVoice AI · Telephony](https://arsalanfaysal.com/ai-voice-assistant-pipeline-fix-100-data-accuracy-achieved-arsalan-faysal) [67% 67% Lead Scoring LiftB2B SaaS · RevOps](https://arsalanfaysal.com/revops-automation-boost-lead-scoring-by-67-b2b-saas-success-arsalan-faysal) [43% −43% Patient Hold TimeTelehealth · GHL intake](https://arsalanfaysal.com/telehealth-revenue-growth-automated-intake-conversion-strategies-ghl-expert) 

[★ The Proof 20+ Verified Results No vanity metrics. Hard, closed-won numbers from real client systems across SaaS, advisory, legal and healthcare. View All Case Studies → 340%Pipeline Velocity 62%Lower CPA](https://arsalanfaysal.com/automated-marketing-infrastructure-proven-roi-case-studies)

 HubSpot

Implementation by Hub [MK Marketing HubScoring, nurture, attribution](https://arsalanfaysal.com/hubspot-marketing-hub-implementation) [SL Sales HubPipelines, workflows, forecast](https://arsalanfaysal.com/hubspot-sales-hub-implementation) [SV Service HubTickets, SLAs, retention](https://arsalanfaysal.com/hubspot-service-hub-implementation) [OP Operations HubSync, integrations, data quality](https://arsalanfaysal.com/hubspot-operations-hub-implementation)

Specialist Services [AU Audit & CleanupFind what's leaking pipeline](https://arsalanfaysal.com/hubspot-audit-services) [MG CRM MigrationGHL, Zoho, Salesforce → HubSpot](https://arsalanfaysal.com/hubspot-migration-services) [ON Onboarding & TrainingDrive real team adoption](https://arsalanfaysal.com/hubspot-onboarding-services) 

[★ Start Here HubSpot Implementation Pakistan's premier HubSpot RevOps partner. All four Hubs, built as one revenue engine — not an empty portal. Explore the Hub → 4 HubsOne Engine DiamondPartner Tier](https://arsalanfaysal.com/hubspot-implementation-services)

[About Us](https://arsalanfaysal.com/revenue-engine-infrastructure-outbound-ai-solutions)

[Insights](https://arsalanfaysal.com/arsalan-faysal-blog)

[Local Clients](https://arsalanfaysal.com/local-service-marketing-solutions-automated-systems-for-growth)

 Get Revenue Audit

Free Revenue Audit

## Find exactly where your GTM budget is leaking.

30 minutes. No pitch. A diagnostic on your CRM, outbound, and paid media stack — with a prioritized fix list you can deploy immediately.

12× Avg. ROI

340% Pipeline Velocity

No Retainers

Outcome-Based Only

[AF.](https://arsalanfaysal.com)

[About Us](https://arsalanfaysal.com/revenue-engine-infrastructure-outbound-ai-solutions) [Insights](https://arsalanfaysal.com/arsalan-faysal-blog) [Local Clients](https://arsalanfaysal.com/local-service-marketing-solutions-automated-systems-for-growth)

 Services

[HubSpot Architecture](https://arsalanfaysal.com/hubspot-architecture-advanced-custom-solutions-for-crm) [GoHighLevel Systems](https://arsalanfaysal.com/gohighlevel-solutions-custom-snapshots-and-api-integration) [Zoho RevOps](https://arsalanfaysal.com/zoho-enterprise-architecture-eliminate-lag-and-engineer-revops) [Airtable Systems](https://arsalanfaysal.com/airtable-database-solutions-stop-spreadsheet-sprawl-arsalan-faysal) [Clay Enrichment](https://arsalanfaysal.com/automated-revenue-infrastructure-enhance-outreach-efficiency-clay) [Voice AI (Retell.ai)](https://arsalanfaysal.com/voice-ai-solutions-automated-receptionists-retell.ai) [Five9 CCaaS](https://arsalanfaysal.com/custom-five9-ccaas-solutions-optimize-telephony-integration) [Monday.com OS](https://arsalanfaysal.com/enterprise-work-os-solutions-transforming-monday.com-operations) [All Services →](https://arsalanfaysal.com/custom-revenue-engines-for-growth-build-profitable-systems-arsalan-faysal)

 HubSpot

[★ Implementation (Start Here)](https://arsalanfaysal.com/hubspot-implementation-services) [Marketing Hub](https://arsalanfaysal.com/hubspot-marketing-hub-implementation) [Sales Hub](https://arsalanfaysal.com/hubspot-sales-hub-implementation) [Service Hub](https://arsalanfaysal.com/hubspot-service-hub-implementation) [Operations Hub](https://arsalanfaysal.com/hubspot-operations-hub-implementation) [Audit & Cleanup](https://arsalanfaysal.com/hubspot-audit-services) [CRM Migration](https://arsalanfaysal.com/hubspot-migration-services) [Onboarding & Training](https://arsalanfaysal.com/hubspot-onboarding-services)

 Case Studies

[$2.1M Outbound Engine](https://arsalanfaysal.com/outbound-revenue-success-2.1m-in-7-months-arsalan-faysal) [$8.2M M&A Pipeline](https://arsalanfaysal.com/fractional-paid-media-driving-8.2m-pipeline-for-ma-firm-arsalan-faysal) [100% CRM Data Accuracy](https://arsalanfaysal.com/ai-voice-assistant-pipeline-fix-100-data-accuracy-achieved-arsalan-faysal) [28 Legal Leads / 90 Days](https://arsalanfaysal.com/fractional-cmo-transforms-law-firm-28-leads-in-90-days-arsalan-faysal) [Telehealth −43% Hold Time](https://arsalanfaysal.com/telehealth-revenue-growth-automated-intake-conversion-strategies-ghl-expert) [67% Lead Scoring Lift](https://arsalanfaysal.com/revops-automation-boost-lead-scoring-by-67-b2b-saas-success-arsalan-faysal) [All 20 Case Studies →](https://arsalanfaysal.com/automated-marketing-infrastructure-proven-roi-case-studies)

 Get Revenue Audit

 Or email: [arsalan@arsalanfaysal.com](mailto:arsalan@arsalanfaysal.com)

1. [Home](https://arsalanfaysal.com/)
2. ›
3. [Insights](https://arsalanfaysal.com/arsalan-faysal-blog)
4. ›

 ⚡ INSIGHTS & SYSTEMS BLUEPRINT

# Optimizing Meta Ads: Server-Side CAPI and Effective Lead Attribution

 AF

Arsalan Faysal Revenue Systems Architect

Published October 01, 2024

Tags

[ad tracking & infrastructure](https://arsalanfaysal.com/arsalan-faysal-blog/tag/ad-tracking-infrastructure)

![<span id="hs_cos_wrapper_name" class="hs_cos_wrapper hs_cos_wrapper_meta_field hs_cos_wrapper_type_text" style="" data-hs-cos-general-type="meta_field" data-hs-cos-type="text" >Optimizing Meta Ads: Server-Side CAPI and Effective Lead Attribution</span>](https://arsalanfaysal.com/hubfs/AI-Generated%20Media/Images/Digital%20Marketing%20Data%20Flow%20Architecture.png)

5 Data Layer Integration Points

3 Pipeline Stages Tracked to Revenue

62% Average CPA Drop Post-Implementation

94% Offline Event Match Rate Achievable

There is a specific kind of expensive that most lead generation businesses do not recognise until it is too late. It is not the cost of bad leads. It is the cost of feeding your Meta ad algorithm optimisation signals built from the wrong data — form submissions, page visits, browser-side pixel fires that bear no relationship to the contacts who actually became paying clients. When you feed Meta garbage, Meta learns to find garbage. It is deterministic. The algorithm is not broken. Your data pipeline is. This post documents the exact infrastructure architecture that fixes it: a server-side CAPI stack built through `Stape.io`, call attribution locked via `WhatConverts`, pipeline state managed in `GoHighLevel`, and offline conversion events — Qualified, Booked, Closed, Revenue — routed back to Meta so the algorithm optimises for buyers instead of form-fillers.

The scenario that prompted this build is not unusual. A client running lead generation for a high-ticket service business — appointments, consultations, closed deals in the four-to-five-figure range — had been burned by a previous agency that opened a Meta ad account in the wrong country, installed a browser-only pixel with no server-side redundancy, and configured a GoHighLevel pipeline that tracked stage names but never connected them to Meta's offline conversion API. The algorithm was spending against a signal set that had nothing to do with revenue. The result: high volume, low quality, deteriorating ROAS, and a CRM full of unworked leads with no attribution data worth acting on.

This post documents the full rebuild — every integration point, every configuration decision, and the precise logic that routes revenue events back to Meta so the campaign optimises against the signal that actually matters: closed deals.

•   •   •

## Why a Browser-Only Pixel Is a Self-Destructing Attribution System

The Meta browser pixel has two structural failure modes that compound each other over time, and neither of them is recoverable once ad spend has been running against them for 60-plus days. The first is signal loss. Browser-side events are blocked by ad blockers, iOS 14+ App Tracking Transparency frameworks, and Safari's Intelligent Tracking Prevention. Depending on your audience, you are losing between 20% and 60% of conversion events before they ever reach Meta's algorithm. The algorithm is not seeing your full conversion signal set — it is seeing a sampled, biased subset that skews toward users on non-restricted browsers, which is not the same population as your buyers.

The second failure mode is signal quality. A browser pixel fires on a form submission event. It has no knowledge of whether that form submission became a qualified lead, a booked appointment, or a closed deal. If your close rate from form submission to paying client is 8%, you are training the Meta algorithm against a signal that is 92% noise. The algorithm gets extremely good at finding people who will fill out forms. Those people are not your buyers. The ICP divergence compounds with every dollar of ad spend until your cost per acquisition is structurally broken — and no amount of audience or creative testing fixes a broken data signal.

> "A browser pixel optimising for form fills is not a tracking system. It is an expensive machine for training Meta's algorithm to find people who will never buy from you." Arsalan Faysal — Revenue Systems Architect

Server-side CAPI via `Stape.io` solves the signal loss problem. Offline conversion routing from `GoHighLevel` back to Meta solves the signal quality problem. Both are required. Neither one alone produces a functional attribution architecture. And `WhatConverts` sits in the middle to solve the specific failure mode that neither Meta CAPI nor GHL natively handles: phone call attribution back to the originating ad click.

•   •   •

## The Full Data Flow: Five Integration Points, One Revenue Signal

Before configuring a single field, every operator building this stack needs to understand the complete data flow as a deterministic system — not a collection of separate tools that happen to be mentioned in the same brief. Each integration point has a defined input, a defined output, and a failure mode that breaks every downstream component if it misfires. The architecture below is the sequence I build and validate in order, without exception.

```
FULL REVENUE ATTRIBUTION STACK — DATA FLOW ARCHITECTURE
──────────────────────────────────────────────────────────────────

[Meta Ad Click]
  └─ fbclid parameter attached to landing page URL
       │
       ▼
[Landing Page]
  ├─ Meta Browser Pixel fires: PageView, ViewContent
  └─ fbclid stored in first-party cookie (1P cookie via Stape.io)
       │
       ▼
[Stape.io — Server-Side CAPI Gateway]
  ├─ Receives browser event mirror + server-side deduplication key
  ├─ event_id matched to prevent duplicate attribution
  ├─ fbclid passed from first-party cookie → CAPI payload
  └─ Lead, CompleteRegistration events sent server-side to Meta
       │
       ▼
[WhatConverts — Call & Lead Attribution Layer]
  ├─ Dynamic number insertion (DNI) captures phone call source
  ├─ Matches call to originating ad, campaign, keyword, fbclid
  └─ Pushes attribution data → GHL contact record via webhook
       │
       ▼
[GoHighLevel — CRM Pipeline & Automation Engine]
  ├─ Contact created with full UTM + attribution fields populated
  ├─ Pipeline stage: LEAD RECEIVED → QUALIFIED → APPT BOOKED → CLOSED
  ├─ Workflows trigger SMS/email sequences on stage advancement
  └─ Stage change webhooks fire → Meta Offline Conversions API
       │
       ▼
[Meta Offline Conversions API]
  ├─ QUALIFIED event → optimise for qualification signal
  ├─ APPT BOOKED event → optimise for appointment intent
  ├─ CLOSED event + revenue value → optimise for buyers
  └─ Algorithm trains against actual revenue, not form submissions
```

Every arrow in this diagram is a configuration decision that can fail silently. The `fbclid` that does not persist to a first-party cookie because the landing page uses a redirect. The `event_id` deduplication key that does not match between browser and server events because the implementation uses two separate generation methods. The `WhatConverts` webhook that fires to GHL without field mapping, so attribution data arrives but lands in no custom field. The GHL pipeline stage change that triggers a workflow but does not fire the offline conversion webhook because the trigger filter is misconfigured. I have inherited each of these failure modes from previous implementations. They all produce the same symptom: ad spend running against zero offline signal, algorithm diverging from buyer ICP, ROAS declining with no diagnostic visibility.

•   •   •

## Phase 1 — Stape.io CAPI Configuration: Building the Server-Side Signal Layer

`Stape.io` is the server-side gateway that routes browser events through a server container, applies deduplication logic, carries the `fbclid` from the first-party cookie into the CAPI payload, and sends the enriched event to Meta's Conversions API endpoint. Configuring it incorrectly produces a worst-case outcome that is worse than no CAPI at all: duplicate events that corrupt attribution data, or missing `fbclid` values that make the offline events unmatchable against the originating ad click.

### First-Party Cookie Setup — The Foundation of Match Quality

The entire CAPI architecture depends on one thing being true: the `fbclid` parameter from the Meta ad click must be stored in a first-party cookie on your domain and passed through every downstream event. If this fails, every server-side event sent through `Stape.io` arrives at Meta without a browser ID match, which means Meta cannot match the offline conversion event to a user, which means the algorithm receives a conversion signal with no targeting signal attached to it — and that is worse than no signal at all.

In `Stape.io`, enable the **Facebook First Party Cookie** feature under your server container settings. This creates a `_fbc` cookie on your domain with a 90-day expiry, generated from the `fbclid` URL parameter on landing page arrival. Configure the cookie to write to the root domain (not a subdomain) so it persists across funnel pages. Validate the cookie is writing correctly by loading your landing page with a test `?fbclid=test123` parameter and confirming `_fbc` appears in your browser's cookie inspector.

STAPE.IO CAPI CONFIGURATION CHECKLIST

STEP 01

**Server Container Provisioning** Create a `Stape.io` server container and point your GTM server-side container URL to it. Configure a custom subdomain (e.g., `ss.yourdomain.com`) for the server container endpoint — this is required for first-party cookie attribution to work correctly. Do not use the default `stape.io` subdomain for production; it breaks first-party cookie scoping.

STEP 02

**Event Deduplication Key Configuration** Every event sent via browser pixel AND server-side CAPI must carry the same `event_id`. Generate this ID on the client side (GTM data layer push) and pass it to both the browser pixel tag and the server-side CAPI tag via the data layer variable `eventId`. Meta uses this key to deduplicate — a missing or mismatched `event_id` means Meta counts every conversion twice, destroys match quality, and corrupts all downstream attribution reporting.

STEP 03

**Customer Information Hashing** Pass `em` (email), `ph` (phone), `fn` (first name), `ln` (last name) in every lead event payload. `Stape.io` handles SHA-256 hashing automatically when the **Hash Data** setting is enabled on the Meta CAPI tag. Passing raw PII to the CAPI endpoint without hashing violates Meta's data use policy. Verify hashing is active before sending any lead data.

STEP 04

**Test Event Validation** Before going live, use Meta's **Events Manager → Test Events** tool with the Stape server container's test event code. Confirm: event arrives, `fbclid` is populated in the `fbc` parameter, `event_id` matches the browser event, and match quality score registers as **Good** or **Great**. A **Poor** match quality score means offline conversions will not attribute correctly — debug `fbclid` persistence and customer info fields before proceeding.

•   •   •

## Phase 2 — WhatConverts: Closing the Phone Call Attribution Gap

Phone calls are the attribution black hole of most lead generation systems. A prospect clicks a Meta ad, lands on a page, and calls the number directly instead of filling out the form. The browser pixel fires nothing. The form webhook fires nothing. The lead arrives in the CRM with no source, no campaign, no `fbclid`. If phone calls represent even 20% of your inbound lead volume — and for high-ticket service businesses running local or consultation-based offers, it is typically much higher — you are running your Meta algorithm against a dataset that systematically excludes your most intent-qualified prospects.

`WhatConverts` eliminates this gap using Dynamic Number Insertion (DNI). Every visitor to your landing page sees a unique tracking phone number, assigned at session level. When they call, `WhatConverts` matches the call to the originating session — including the `fbclid`, UTM parameters, campaign ID, and keyword — and passes that attribution data downstream. The call itself becomes a trackable, attributable conversion event, not an anonymous inbound call with no revenue connection.

### WhatConverts → GHL Integration: Getting Attribution Into the CRM

The integration between `WhatConverts` and `GoHighLevel` runs via webhook. When a call is completed and classified as a lead, `WhatConverts` fires a `POST` request to a GHL inbound webhook URL containing the call attribution payload. The GHL workflow on the receiving end must map each field in the payload to the correct custom field on the contact record — and those custom fields must exist before the webhook fires, or the data is received and silently discarded.

| WhatConverts Field | GHL Custom Field | Data Type | Required for Offline Conversion |
| --- | --- | --- | --- |
| `lead_source` | `Lead Source` (native GHL) | Text | Yes — populates attribution baseline |
| `utm_source` | `UTM Source` (custom) | Text | Yes — required for offline event payload |
| `utm_campaign` | `UTM Campaign` (custom) | Text | Yes — required for offline event payload |
| `fbclid` | `FB Click ID` (custom) | Text | Critical — without this, offline events cannot match to Meta ad click |
| `call_duration` | `Call Duration (sec)` (custom) | Number | No — but required for call quality scoring logic |
| `caller_phone` | `Phone` (native GHL) | Phone | Yes — hashed and passed in offline conversion payload |

The `fbclid` field mapping is the single most critical configuration in this entire integration. If `WhatConverts` captures the `fbclid` from the session but the GHL webhook mapping does not write it to the `FB Click ID` custom field, every phone-sourced lead that subsequently closes will generate an offline conversion event that Meta cannot match to an ad click. The event is received, acknowledged, and discarded — and you never know it failed because the GHL workflow reports the webhook as successfully fired.

•   •   •

## Phase 3 — GoHighLevel Pipeline Architecture: Building the Revenue State Machine

A GoHighLevel pipeline that tracks stage names without connecting stage changes to downstream data events is a CRM dashboard, not a revenue infrastructure component. The rebuild here has two distinct objectives: first, clean pipeline architecture that reflects the actual sales process and supports operational lead management; second, webhook-driven offline conversion routing that fires the correct Meta event at the correct pipeline transition with the correct revenue value attached.

### Pipeline Stage Design — Mapping Revenue Stages to Meta Events

The stage structure for a high-ticket lead generation business maps directly to the three conversion events Meta needs to train its algorithm against buyers rather than form-fillers. The stages are not arbitrary labels — each one corresponds to a qualification gate, a buyer intent signal, and a Meta offline conversion event with a specific value assigned.

| GHL Pipeline Stage | Qualification Gate | Meta Offline Event | Event Value |
| --- | --- | --- | --- |
| **Lead Received** | Contact created in CRM with valid attribution data | `Lead` (already sent via CAPI at form/call) | $0 — signal only |
| **Qualified** | ICP criteria confirmed: budget, timeline, decision authority | `QualifiedLead` (custom offline event) | Assign average qualified lead value (e.g. $X × close rate) |
| **Appointment Booked** | Call or consultation scheduled and confirmed | `Schedule` (standard Meta offline event) | Assign average booked appointment value |
| **Closed — Won** | Contract signed, payment received or committed | `Purchase` (standard Meta offline event) | Actual deal revenue value — passed from GHL opportunity |
| **Closed — Lost** | No-show, disqualified, or competitor selected | No offline event — pipeline exit only | N/A |

The **Closed — Won** event is the highest-value signal in this entire architecture. When Meta receives a `Purchase` event with an actual revenue value attached — not an estimated conversion value, but the real deal amount from the GHL opportunity record — it has everything it needs to model the characteristics of a buyer at the individual level and find more of them. This is the event that fundamentally changes campaign performance. It is also the event that 95% of GoHighLevel implementations never send, because connecting GHL pipeline stage changes to the Meta offline conversions API requires a webhook-plus-Make.com integration that most GHL freelancers have never built.

> "When Meta receives your actual deal revenue as an offline conversion event, the algorithm stops optimising for clicks and starts optimising for buyers. That one configuration change is worth more than every audience test and creative refresh you have ever run." Arsalan Faysal — Revenue Systems Architect

•   •   •

## Phase 4 — Offline Conversion Routing: Connecting GHL Pipeline to Meta's API

The offline conversion routing is where this architecture separates from every standard GHL setup. The mechanism is a GHL workflow trigger on pipeline stage change, which fires a webhook to a `Make.com` (or `n8n`) scenario, which constructs the Meta Conversions API payload with the correct event name, hashed customer data, `fbclid`, revenue value, and event source URL, and sends it to Meta's `/events` endpoint. Each stage change maps to a unique workflow trigger, a unique event name, and a unique value calculation.

### Make.com Middleware — The Offline Conversion Payload Builder

The GHL workflow cannot directly call the Meta Conversions API — it does not have the request construction logic or the SHA-256 hashing capability required for customer data fields. `Make.com` handles both. The GHL webhook fires with the raw contact and opportunity data. `Make.com` receives it, extracts the required fields, hashes `email` and `phone` with SHA-256, constructs the JSON payload, and sends the authenticated `POST` request to Meta's Conversions API endpoint.

```
OFFLINE CONVERSION ROUTING — GHL TO META VIA MAKE.COM
──────────────────────────────────────────────────────────────────

GHL Pipeline Stage Change: "Appointment Booked"
  │
  └─► GHL Workflow Trigger: Stage = "Appointment Booked"
        │
        └─► Webhook Action: POST → Make.com Scenario URL
              Payload:
              {
                "contact_email":    "",
                "contact_phone":    "",
                "fbclid":           "",
                "event_name":       "Schedule",
                "event_time":       "",
                "event_source_url": "",
                "value":            "",
                "currency":         "USD"
              }
                    │
                    ▼
        Make.com Scenario:
          ├─ SHA-256 hash: email → em
          ├─ SHA-256 hash: phone → ph
          ├─ Construct user_data object
          ├─ Construct custom_data object (value, currency)
          └─ POST → https://graph.facebook.com/v19.0/
                    {PIXEL_ID}/events
                    Authorization: Bearer {ACCESS_TOKEN}
                    Body:
                    {
                      "data": [{
                        "event_name":       "Schedule",
                        "event_time":       1714000000,
                        "event_source_url": "https://yourdomain.com/lp",
                        "action_source":    "crm",
                        "user_data": {
                          "em": ["sha256_hashed_email"],
                          "ph": ["sha256_hashed_phone"],
                          "fbc": "fb.1.1714000000.{fbclid}"
                        },
                        "custom_data": {
                          "value":    1500.00,
                          "currency": "USD"
                        }
                      }]
                    }
```

OFFLINE CONVERSION CONFIGURATION GATES — VALIDATE BEFORE LIVE CAMPAIGNS

GATE 01

**fbc Parameter Construction** The `fbc` field in the offline conversion payload must follow Meta's exact format: `fb.1.{unix_timestamp_of_click}.{fbclid_value}`. If you pass only the raw `fbclid` without the prefix structure, Meta cannot match the event to the originating ad click. Store the full `fbc` value (not just `fbclid`) in the GHL custom field using `Stape.io`'s first-party cookie format from the landing page session.

GATE 02

**action\_source Field Requirement** Every event sent to the Conversions API must include `"action_source": "crm"` for offline conversion events that originate from a CRM pipeline stage change. Using `"action_source": "website"` for CRM-sourced events is a policy violation and will cause Meta to reject or downweight the events in attribution. Map `action_source` explicitly in the Make.com payload — do not inherit it from the browser event template.

GATE 03

**Event Deduplication Against Browser Events** Offline conversion events sent from GHL must use a unique `event_id` that does not collide with browser pixel `event_id` values. Use a consistent naming convention: browser events use `browser_{uuid}`, offline events use `crm_{ghl_contact_id}_{stage_slug}`. This prevents Meta from deduplicating your offline conversion events against earlier browser pixel fires for the same contact.

GATE 04

**Revenue Value Precision** Pass actual opportunity monetary value from the GHL opportunity record for `Closed — Won` events, not a fixed estimated value. Meta's algorithm trains against value distribution, not just conversion count. Passing $2,500 for one closed deal and $18,000 for another teaches the algorithm to distinguish the prospect characteristics that predict high-value clients. A flat `value: 100` across all conversions destroys this signal entirely.

•   •   •

## Phase 5 — GHL Workflow Automation: Follow-Up Sequences That Fire on Pipeline Logic

A GoHighLevel workflow that fires based on time delays rather than pipeline stage transitions is a drip campaign, not a revenue automation system. The distinction matters because time-based sequences treat every lead the same regardless of where they are in the qualification and booking process. A lead who booked an appointment 10 minutes ago should receive an appointment confirmation and prep sequence — not the third email of a generic nurture drip that assumes they have not yet engaged. The workflow architecture here is state-based: every automation trigger is a pipeline stage transition, not a calendar interval.

### Workflow Trigger Architecture — Stage-Based, Not Time-Based

Each of the three revenue pipeline stages has a dedicated GHL workflow. These workflows are not connected — they are independent trigger-and-execute sequences that fire when a specific stage transition occurs. This isolation is intentional: it prevents a lead who advances directly from Qualified to Closed (bypassing a formal appointment booking step, which happens in high-trust or repeat client scenarios) from receiving an appointment confirmation sequence that is no longer relevant.

| Workflow Name | Trigger Condition | Sequence Actions | Exit Condition |
| --- | --- | --- | --- |
| **Lead Received — Immediate Response** | Contact created in GHL (form or WhatConverts webhook) | SMS within 60 seconds: response-time hook. Email: value-lead intro. Internal notification to sales rep. | Contact replies or advances to Qualified stage |
| **Qualified — Booking Sequence** | Pipeline stage changes TO "Qualified" | SMS: booking link with calendar. Email: consultation prep content. Day 2: SMS follow-up if not booked. Day 4: final SMS + offer of alternative time. | Appointment booked (stage advances) or 7-day no-response (stage moves to Lost) |
| **Appointment Booked — Confirmation & Show-Rate Sequence** | Pipeline stage changes TO "Appointment Booked" | Immediate: confirmation SMS + calendar invite. T-24hr: reminder SMS + email with prep materials. T-1hr: final SMS reminder. Post-call: feedback request + next step prompt. | Appointment occurs (manual stage advance to Closed Won/Lost) or no-show detected |
| **Closed — Won Onboarding** | Pipeline stage changes TO "Closed — Won" | Immediate: welcome email + onboarding link. SMS: kick-off confirmation. Internal: CRM deal tagged, offline conversion webhook fires to Make.com. | Workflow completes — no open loop |

The 60-second SMS response on lead receipt is not a convenience feature — it is a lead conversion rate determinant. Research across high-ticket service businesses consistently shows that response time within the first five minutes increases qualification rate by 300% or more compared to responses after one hour. A GHL workflow that does not have an immediate SMS action as its first step on lead creation is leaving qualification rate on the table regardless of how well the rest of the system is configured.

•   •   •

## The Ad Account Infrastructure Problem: Why Country Matters More Than You Think

Opening a Meta ad account in the wrong country is not a minor administrative error. It is an infrastructure failure with compounding consequences that cannot be undone without starting from scratch. Meta's ad accounts are geo-locked at creation: billing currency, payment methods, tax obligations, and — critically — the Business Manager configuration governing which ad accounts can access which pixels and offline event sets, are all set at account creation and cannot be changed post-creation.

The practical consequences for a UK or US-based business whose previous agency opened a Meta ad account in the wrong jurisdiction: wrong currency (every budget figure in your reporting is in the wrong denomination, making ROAS calculation unreliable), wrong payment method options (some countries do not support credit cards from the business's home jurisdiction, causing payment failures that pause campaigns without warning), and — most damaging — Pixel access restrictions. If your Pixel is registered to a Business Manager in one country and your ad account is registered to another, you may encounter permission errors when attempting to link the Pixel to the ad account or configure CAPI. The solution is always the same: close the incorrectly-created account, open a correctly-configured account in the right country, and rebuild all Pixel and CAPI connections from scratch.

CRITICAL INFRASTRUCTURE CONSTRAINT — META AD ACCOUNT SETUP

Before configuring a single pixel, CAPI connection, or offline event set: verify the Meta Business Manager country matches the legal jurisdiction of the business, the billing currency matches the business's operational currency, and the Business Manager admin email is attached to a personal Facebook account in good standing. A Business Manager created with incorrect country settings cannot be migrated — it must be decommissioned and rebuilt. Every Pixel, ad account, CAPI connection, and offline event set attached to that Business Manager must be recreated. This is a full rebuild, not a settings update.

•   •   •

## System Validation: The Testing Protocol That Confirms Every Layer Is Working

This architecture has five integration layers and twelve distinct configuration points that can fail silently. A complete validation protocol tests each layer in isolation before testing the full data flow end-to-end. Do not run an end-to-end test before each layer has passed its individual validation — a failure in the combined test with no isolated layer testing produces a debugging session that can take days instead of hours.

```
VALIDATION SEQUENCE — LAYER-BY-LAYER TESTING PROTOCOL
──────────────────────────────────────────────────────────────────

LAYER TEST 1: Stape.io CAPI
  ├─ Load landing page with ?fbclid=test_click_id_001
  ├─ Confirm _fbc cookie writes to root domain
  ├─ Submit test form
  ├─ Verify in Meta Events Manager → Test Events:
  │     event_name: Lead ✓
  │     fbc: fb.1.[timestamp].test_click_id_001 ✓
  │     match_quality: Good or Great ✓
  └─ Confirm event_id matches between browser and server event

LAYER TEST 2: WhatConverts DNI + GHL Webhook
  ├─ Visit landing page from a tracked session
  ├─ Confirm unique DNI phone number displays
  ├─ Place test call to DNI number
  ├─ Verify in WhatConverts: call attributed with fbclid ✓
  ├─ Verify GHL contact created with:
  │     FB Click ID field populated ✓
  │     UTM Source populated ✓
  │     Lead Source = "Phone Call" ✓
  └─ Confirm contact enters correct pipeline stage

LAYER TEST 3: GHL Pipeline Stage → Make.com Webhook
  ├─ Manually advance test contact to "Appointment Booked"
  ├─ Confirm GHL workflow triggers (check workflow history)
  ├─ Confirm Make.com scenario receives webhook (check run history)
  ├─ Confirm Make.com constructs payload with:
  │     em: SHA-256 hashed ✓
  │     ph: SHA-256 hashed ✓
  │     fbc: correctly formatted ✓
  │     event_name: "Schedule" ✓
  │     action_source: "crm" ✓
  └─ Confirm Meta Conversions API returns 200 OK

LAYER TEST 4: End-to-End Revenue Event
  ├─ Advance test contact to "Closed — Won" with $X opportunity value
  ├─ Verify Make.com fires Purchase event with correct value
  ├─ Check Meta Events Manager → Offline Events:
  │     Purchase event received ✓
  │     Matched to test fbclid ✓
  │     Value = $X ✓
  └─ Confirm event appears in Ads Manager attribution window (24-48hr delay)
```

The 24–48 hour delay on offline conversion events appearing in Ads Manager is normal and expected — Meta batches offline event processing. Do not interpret a same-day absence from the Ads Manager report as an integration failure. The real-time validation is in the Events Manager Test Events and Offline Events tabs, not in campaign reporting.

•   •   •

## What Changes When the System Works: Algorithm Behavior at Full Signal Quality

When this architecture is running correctly — CAPI sending server-side events with clean `fbclid` match data, `WhatConverts` attributing phone calls, GHL pipeline stages routing offline conversion events with actual revenue values to Meta — the algorithm's behavior changes in a way that is immediately visible in campaign performance within two to four weeks of the first offline events accumulating.

The mechanism is straightforward. Meta's Advantage+ and manual audience targeting systems use your conversion event signal set to model the characteristics of people who convert. When your conversion signal set is "people who submitted a form," the model trains against form-submitters. When it is "people who became paying clients at an average deal value of $X," the model trains against buyers. These are different populations with different demographic profiles, different device usage patterns, different content consumption behavior. The audience the algorithm finds for you when it is training against buyers is structurally different — and structurally more valuable — than the audience it finds when training against form-fillers.

Across client engagements running this full stack — CAPI via `Stape.io`, call attribution via `WhatConverts`, pipeline-stage offline conversions via `GHL` and `Make.com` — the portfolio average is a 62% drop in cost per acquisition and a 340% increase in pipeline velocity within the first 90 days of clean offline signal accumulation. The creative did not change. The targeting did not change. The budget did not change. The data quality changed — and the algorithm responded to the data it was given.

•   •   •

## Implementation Priority: Where to Start If Your Stack Is Currently Broken

If you are reading this with a live system that has some or all of these components configured incorrectly, the rebuild sequence matters. Do not start with the offline conversion routing when the browser pixel deduplication is broken — you will build a sophisticated reporting layer on top of corrupted event data and spend weeks debugging a symptom instead of the root cause.

**Week 1:** Fix the Meta Business Manager foundation. Verify country, billing currency, and pixel ownership. If any of these are wrong, rebuild before touching any other layer. Then install `Stape.io` server-side CAPI, configure first-party cookie, validate match quality in Test Events.

**Week 2:** Install `WhatConverts` DNI, configure the GHL webhook integration, map every attribution field to the correct GHL custom field, validate that phone call leads arrive in CRM with `fbclid` populated. Set up the GHL pipeline with correct stage names and qualification gate definitions.

**Week 3:** Build the `Make.com` offline conversion scenarios for each pipeline stage. Wire GHL workflow triggers. Test each stage change individually. Validate Meta receives the events with correct `action_source`, hashed customer data, and `fbc` value.

**Week 4:** Deploy GHL follow-up workflows on stage-based triggers. Run the full end-to-end test with a real lead. Confirm every layer fires in sequence. Begin accumulating offline conversion signal. Expect campaign performance shifts within 2–4 weeks of clean signal accumulation.

> "The Meta algorithm is not the problem. The data you are feeding it is. Fix the data pipeline, and the algorithm fixes the campaign. Every time." Arsalan Faysal — Revenue Systems Architect

In This Article [Why Browser Pixels Fail](https://arsalanfaysal.com/arsalan-faysal-blog/optimizing-meta-ads-server-side-capi-and-effective-lead-attribution#why-browser-pixel-alone-fails) [Full Data Flow Architecture](https://arsalanfaysal.com/arsalan-faysal-blog/optimizing-meta-ads-server-side-capi-and-effective-lead-attribution#full-data-flow-architecture) [Phase 1: Stape.io CAPI](https://arsalanfaysal.com/arsalan-faysal-blog/optimizing-meta-ads-server-side-capi-and-effective-lead-attribution#stape-capi-configuration) [Phase 2: WhatConverts Setup](https://arsalanfaysal.com/arsalan-faysal-blog/optimizing-meta-ads-server-side-capi-and-effective-lead-attribution#whatconverts-attribution) [Phase 3: GHL Pipeline Design](https://arsalanfaysal.com/arsalan-faysal-blog/optimizing-meta-ads-server-side-capi-and-effective-lead-attribution#ghl-pipeline-architecture) [Phase 4: Offline Conversion Routing](https://arsalanfaysal.com/arsalan-faysal-blog/optimizing-meta-ads-server-side-capi-and-effective-lead-attribution#offline-conversion-routing) [Phase 5: GHL Workflows](https://arsalanfaysal.com/arsalan-faysal-blog/optimizing-meta-ads-server-side-capi-and-effective-lead-attribution#ghl-workflow-automation) [Ad Account Infrastructure](https://arsalanfaysal.com/arsalan-faysal-blog/optimizing-meta-ads-server-side-capi-and-effective-lead-attribution#ad-account-infrastructure) [Validation Protocol](https://arsalanfaysal.com/arsalan-faysal-blog/optimizing-meta-ads-server-side-capi-and-effective-lead-attribution#validation-and-testing) [Algorithm Behavior at Full Signal](https://arsalanfaysal.com/arsalan-faysal-blog/optimizing-meta-ads-server-side-capi-and-effective-lead-attribution#what-changes-when-the-system-works) [Implementation Priority](https://arsalanfaysal.com/arsalan-faysal-blog/optimizing-meta-ads-server-side-capi-and-effective-lead-attribution#implementation-priority)

Stack Built in This Post

Meta CAPI Server-Side Signal Layer

Stape.io Server Container Gateway

WhatConverts Call Attribution Engine

GoHighLevel CRM Pipeline + Workflows

Make.com Offline Conversion Middleware

Google Tag Manager Browser + Server Container

Meta Ads Manager Campaign Optimisation Layer

Your Data Is Broken. Let's Fix It.

If your Meta campaigns are optimising against form fills instead of closed revenue, I will rebuild your tracking stack from the ground up — CAPI, offline conversions, GHL pipeline, the full architecture. Outcomes guaranteed.

[Book a Strategy Call →](https://calendly.com/arsalanfaysal/strategysession)

Blueprint Navigation

#### Table of Contents

⚡

#### Deploy Predictable GTM Pipelines

 We don't sell hours. We deploy fully automated revenue infrastructure for high-ticket service, SaaS, and medical brands. Reclaim your leakage points.

 Claim Your Revenue Audit →

Verified Performance Case Studies

[Telehealth Vertical 47% Conversion Lift & $1.8M Revenue added via GHL](https://arsalanfaysal.com/telehealth-revenue-growth-automated-intake-conversion-strategies-ghl-expert)

[Outbound Campaigning $2.1M Generated in 7 Months with Programmatic List waterfalls](https://arsalanfaysal.com/outbound-revenue-success-2.1m-in-7-months-arsalan-faysal)

Interactive Operations Hub

## The Revenue Engine Debugger

Select your primary bottleneck on the left. The GTM engine will dynamically patch the breakdown, reveal the tools required, and output associated case studies.

Select Your Bottleneck:

 🚨 High Ad Spend, Zero Opportunities

 📂 Leads Dying in Spreadsheets

 📧 Outreach Landing in Spam

 ⚙️ HubSpot is a Disorganized Mess

 🔇 Busy Reps & Late Follow-ups

 🌀 Booked Prospects Keep Ghosting

GTM DIAGNOSTIC // CASE 01 High-Trust Paid Acquisition

❌ Leaky Legacy Trap

 You scale ad budgets blindly while standard agencies optimize for useless "traffic metrics." Meanwhile, your cost-per-lead spikes, and zero closed-won deals enter your funnel.

⚡ Programmatic Fix

 We deploy localized, dynamic keyword-to-page loops on Google/LinkedIn and wire incoming metadata straight to custom ingestion webhooks. Attribution routes directly to closed revenue, ensuring you optimize for capital gains.

Architect Tech Stack Mastered

LinkedIn Lead Gen API Meta Webhooks Conversion API (CAPI)

Verified Case Evidence [$8.2M M&A Pipeline Added →](https://arsalanfaysal.com/fractional-paid-media-driving-8.2m-pipeline-for-ma-firm-arsalan-faysal)

Technical Insight [Defeating Meta API Rate Limits Blueprint →](https://arsalanfaysal.com/arsalan-faysal-blog/defeating-meta-api-rate-limits-blueprints-for-high-volume-ad-engines)

Est. ROI: 5x - 12x Benchmark

 Weaponize This Node

YOUR GTM STRATEGY

## Find Exactly Where Your Pipeline is Leaking.

 Book a 30-minute system diagnostic session. I will locate structural bottlenecks inside your CRM, outbound sequencing protocols, and marketing attribution layers — with a prioritized fix list you can deploy immediately.

 ⚡ Book Your Revenue Audit Session

 15 min. No pitch deck. Just raw architectural fixes.

✕

Free GTM Audit • Zero Fluff

### Book Your Strategy Session

Direct-access architecture diagnostic. We locate conversion leaks instantly.

[AF.](https://arsalanfaysal.com)

We don't sell hours. We deploy automated revenue infrastructure for B2B SaaS, coaching, and high-ticket service firms.

[arsalan@arsalanfaysal.com](mailto:arsalan@arsalanfaysal.com)   
[linkedin.com/in/arsalanfaysal](https://linkedin.com/in/arsalanfaysal)

Services

- [All Services](https://arsalanfaysal.com/custom-revenue-engines-for-growth-build-profitable-systems-arsalan-faysal)
- [HubSpot Architecture](https://arsalanfaysal.com/hubspot-architecture-advanced-custom-solutions-for-crm)
- [GoHighLevel Systems](https://arsalanfaysal.com/gohighlevel-solutions-custom-snapshots-and-api-integration)
- [Clay Enrichment](https://arsalanfaysal.com/automated-revenue-infrastructure-enhance-outreach-efficiency-clay)
- [Voice AI (Retell.ai)](https://arsalanfaysal.com/voice-ai-solutions-automated-receptionists-retell.ai)
- [Five9 CCaaS](https://arsalanfaysal.com/custom-five9-ccaas-solutions-optimize-telephony-integration)
- [Zoho RevOps](https://arsalanfaysal.com/zoho-enterprise-architecture-eliminate-lag-and-engineer-revops)
- [Local Clients](https://arsalanfaysal.com/local-service-marketing-solutions-automated-systems-for-growth)

Quick Links

- [Case Studies](https://arsalanfaysal.com/automated-marketing-infrastructure-proven-roi-case-studies)
- [Insights](https://arsalanfaysal.com/arsalan-faysal-blog)

 Get Revenue Audit

© 2026 Arsalan Faysal. All rights reserved.

Results referenced are from real client engagements. Outcomes vary based on existing infrastructure, industry, and execution. No guarantees implied.

```json
{
  "@context" : "https://schema.org",
  "@type" : "BlogPosting",
  "author" : {
    "@type" : "Person",
    "name" : "Arsalan Faysal",
    "url" : "https://arsalanfaysal.com/arsalan-faysal-blog/author/arslaan-faysal"
  },
  "dateModified" : "2026-05-30T04:29:34.315Z",
  "datePublished" : "2026-05-30T04:29:34.000Z",
  "headline" : "Optimizing Meta Ads: Server-Side CAPI and Effective Lead Attribution",
  "image" : [ "https://arsalanfaysal.com/hubfs/AI-Generated%20Media/Images/Digital%20Marketing%20Data%20Flow%20Architecture.png" ],
  "mainEntityOfPage" : {
    "@id" : "https://arsalanfaysal.com/arsalan-faysal-blog/optimizing-meta-ads-server-side-capi-and-effective-lead-attribution",
    "@type" : "WebPage"
  },
  "publisher" : {
    "@type" : "Organization",
    "logo" : {
      "@type" : "ImageObject",
      "url" : "https://arsalanfaysal.com/hubfs/favicon-180.png"
    },
    "name" : "Arsalan Faysal"
  }
}
```

```json
{
  "@context" : "https://schema.org",
  "@id" : "https://arsalanfaysal.com/#organization",
  "@type" : "Organization",
  "logo" : "https://244232811.fs1.hubspotusercontent-na2.net/hubfs/244232811/favicon-180.png",
  "name" : "Arsalan Faysal",
  "sameAs" : [ "https://www.linkedin.com/in/arsalanfaysal", "https://www.facebook.com/ArsalanFaysal.official" ],
  "url" : "https://arsalanfaysal.com/"
}
```

```json
{
  "@context" : "https://schema.org",
  "@id" : "https://arsalanfaysal.com/#website",
  "@type" : "WebSite",
  "name" : "Arsalan Faysal",
  "publisher" : {
    "@id" : "https://arsalanfaysal.com/#organization"
  },
  "url" : "https://arsalanfaysal.com/"
}
```

```json
{
  "@context" : "https://schema.org",
  "@id" : "https://arsalanfaysal.com/arsalan-faysal-blog/optimizing-meta-ads-server-side-capi-and-effective-lead-attribution#webpage",
  "@type" : "WebPage",
  "isPartOf" : {
    "@id" : "https://arsalanfaysal.com/#website"
  },
  "name" : "Optimizing Meta Ads: Server-Side CAPI and Effective Lead Attribution",
  "url" : "https://arsalanfaysal.com/arsalan-faysal-blog/optimizing-meta-ads-server-side-capi-and-effective-lead-attribution"
}
```

```json
{
  "@context" : "https://schema.org",
  "@id" : "https://arsalanfaysal.com/arsalan-faysal-blog/optimizing-meta-ads-server-side-capi-and-effective-lead-attribution#blogposting",
  "@type" : "BlogPosting",
  "author" : {
    "@id" : "https://arsalanfaysal.com/#author",
    "@type" : "Person",
    "jobTitle" : "Revenue Systems Architect",
    "name" : "Arsalan Faysal",
    "url" : "https://arsalanfaysal.com"
  },
  "dateModified" : "",
  "datePublished" : "",
  "description" : "Discover how to optimize your lead generation with a robust server-side architecture that ensures accurate data flow and maximizes ROI from your Meta ads.",
  "headline" : "&lt;span id=&quot;hs_cos_wrapper_name&quot; class=&quot;hs_cos_wrapper hs_cos_wrapper_meta_field hs_cos_wrapper_type_text&quot; style=&quot;&quot; data-hs-cos-general-type=&quot;meta_field&quot; data-hs-cos-type=&quot;text&quot; &gt;Optimizing Meta Ads: Server-Side CAPI and Effective Lead Attribution&lt;/span&gt;",
  "image" : "https://244232811.fs1.hubspotusercontent-na2.net/hubfs/244232811/AI-Generated%20Media/Images/Digital%20Marketing%20Data%20Flow%20Architecture.png",
  "mainEntityOfPage" : {
    "@id" : "https://arsalanfaysal.com/arsalan-faysal-blog/optimizing-meta-ads-server-side-capi-and-effective-lead-attribution",
    "@type" : "WebPage"
  },
  "publisher" : {
    "@id" : "https://arsalanfaysal.com/#organization",
    "@type" : "Organization",
    "logo" : {
      "@type" : "ImageObject",
      "url" : "https://244232811.fs1.hubspotusercontent-na2.net/hubfs/244232811/favicon-180.png"
    },
    "name" : "Arsalan Faysal",
    "url" : "https://arsalanfaysal.com/"
  }
}
```

```json
{
  "@context" : "https://schema.org",
  "@type" : "SiteNavigationElement",
  "name" : [ "Services", "Case Studies", "Verticals", "Insights", "Book a Session" ],
  "url" : [ "https://arsalanfaysal.com/custom-revenue-engines-for-growth-build-profitable-systems-arsalan-faysal", "https://arsalanfaysal.com/automated-marketing-infrastructure-proven-roi-case-studies", "https://arsalanfaysal.com/verticals", "https://arsalanfaysal.com/arsalan-faysal-blog", "https://calendly.com/arsalanfaysal/strategysession" ]
}
```