Ghost ID Docs
Product documentation
Back to Dashboard

Revenue Attribution

Every sale you make can be traced back to the exact marketing source that brought the visitor in the first place. Ghost ID tracks visitors from their first click, watches them through your funnel, and credits revenue to the channel that earned it โ€” whether the sale happened minutes or months later.

๐Ÿง  How It Works

Ghost ID needs one thing to attribute a sale: a signal that the sale happened. That signal carries the amount, a transaction ID, and the visitor's identity. We then look up that visitor's first-touch and last-touch marketing data and record the sale in your revenue dashboard.

There are two ways to send that signal. You pick what fits your stack.

MethodWorks WithCustomer Setup
Universal JS CallAny payment provider (Stripe, PayPal, Square, GoHighLevel, Shopify, WooCommerce, invoicing, crypto, anything)Paste one line on your success/thank-you page
Automatic WebhookStripe, Shopify, WooCommerce (including Stripe-based platforms like GHL, Webflow, Framer)Connect once in Ghost ID, add a webhook in the provider dashboard

โšก Option 1: Universal JS Call (recommended)

Works everywhere. One line on your thank-you / success / order-confirmation page. Our tracking script reads the visitor's ghost_vid from their first-party cookie and attaches it automatically.

JavaScript
GHOST.revenue(49.99, 'USD', 'txn_abc123', { plan: 'pro' });

Parameters:

  • amount (required): number, the total paid
  • currency (default `USD`): 3-letter ISO currency code
  • transactionId (optional but recommended): a unique ID for the sale โ€” used to dedupe accidental double-fires
  • metadata (optional): any extra context you want in your reports

Platform Recipes

Every platform exposes order data slightly differently. Pick the recipe for yours.

Stripe Checkout โ€” your custom success page

Configure your Stripe Checkout Session to redirect to a page on your domain with `?session_id={CHECKOUT_SESSION_ID}`. On that page, read the session ID from the URL and fire:

HTML
<script>
  const params = new URLSearchParams(window.location.search);
  const sessionId = params.get('session_id');
  // Your backend or Stripe.js can fetch session details and call:
  GHOST.revenue(orderTotal, 'USD', sessionId);
</script>

GoHighLevel โ€” funnel thank-you page

In the GHL funnel editor, add a Custom Code block to your thank-you/confirmation step. GHL substitutes order values via merge tags at render time.

HTML
<script>
  GHOST.revenue({{order.total}}, 'USD', '{{order.id}}');
</script>

Merge-tag names vary by GHL funnel version. If the tags don't render with real values, connect Stripe automatically (Option 2 below) โ€” our email fallback catches the sale without any merge tags.

Shopify โ€” order status page

In your Shopify theme, add to the `order-status` section (or use the Checkout & Accounts โ†’ Additional Scripts setting):

Liquid
<script>
  GHOST.revenue({{ checkout.total_price | money_without_currency | remove: ',' }}, '{{ shop.currency }}', '{{ checkout.order_id }}');
</script>

WooCommerce โ€” thankyou action hook

Add to your theme's `functions.php` (or a custom snippet plugin):

PHP
add_action('woocommerce_thankyou', function($order_id) {
  $order = wc_get_order($order_id);
  if (!$order) return;
  ?>
  <script>
    GHOST.revenue(<?= $order->get_total() ?>, '<?= $order->get_currency() ?>', '<?= $order->get_order_number() ?>');
  </script>
  <?php
}, 20);

Google Tag Manager

If you already push purchase events into `dataLayer` for GA4 / Meta Pixel, create a GTM tag that fires on a URL trigger matching your success page and reads from the existing event:

JavaScript
// Custom HTML tag, trigger: Page View on URL matching /thank-you/ or /order-confirmation/
<script>
  var ecommerce = {{DLV - ecommerce}};  // built-in GTM variable
  if (ecommerce && ecommerce.value) {
    GHOST.revenue(ecommerce.value, ecommerce.currency || 'USD', ecommerce.transaction_id);
  }
</script>

Anything else

Get the amount and order ID into your success page however your stack exposes them, then call `GHOST.revenue(...)`. That's all.

๐Ÿ”Œ Option 2: Automatic Webhook Connection

If you'd rather not touch your success page, connect your provider directly and Ghost ID catches every sale automatically via outbound webhooks.

๐Ÿ’ก

When to use: You use Stripe / Shopify / WooCommerce and want set-and-forget revenue tracking. This also catches subscription renewals that happen server-side (where no user session exists to fire a JS call).

Stripe Setup

Works with direct Stripe, and every Stripe-based platform: GoHighLevel, Webflow, Framer, Bubble, most SaaS checkouts. Open Ghost ID and Stripe in two tabs.

In Ghost ID

  1. Go to Settings โ†’ Revenue Connections
  2. Click Connect Stripe
  3. Leave the modal open, switch to Stripe in another tab

In your Stripe dashboard

  1. Confirm the top-right toggle says Live mode
  2. Developers โ†’ API keys
  3. Next to "Secret key" click Reveal live key token
  4. Copy the `sk_live_...` value

Back in Ghost ID

  1. Paste `sk_live_...` into the Secret Key field
  2. Leave Webhook Signing Secret empty for now
  3. Click Connect
  4. The modal now shows a webhook URL: `https://analytics.ghostid.ai/ghost-revenue` โ€” copy it

Back in Stripe

  1. Developers โ†’ Webhooks โ†’ + Add endpoint
  2. Paste the webhook URL
  3. Under Events to send, select these four:
    • checkout.session.completed
    • payment_intent.succeeded
    • invoice.paid
    • charge.succeeded
  4. Click Add endpoint
  5. On the endpoint page, click Reveal next to Signing secret
  6. Copy the `whsec_...` value

Final step in Ghost ID

  1. Click Reconnect on the Stripe card
  2. Paste `sk_live_...` again
  3. Paste `whsec_...` into Webhook Signing Secret this time
  4. Click Connect
๐Ÿ’ก

Why four events? `checkout.session.completed` covers one-time Stripe Checkout sales. `invoice.paid` covers subscription renewals. `payment_intent.succeeded` covers direct PaymentIntent flows used by Stripe Elements and some platforms. `charge.succeeded` catches legacy direct-charge flows (older GoHighLevel integrations, custom Charges API usage) that don't fire any of the other three. Ghost ID dedupes across all four so you never double-count a sale.

Shopify Setup

Use this when Shopify is your checkout source and you want Ghost ID to capture paid orders and refunds automatically without adding JS to the theme checkout flow.

In Ghost ID

  1. Go to Settings โ†’ Revenue Connections
  2. Click Connect Shopify
  3. Keep the modal open and copy the webhook URL shown there: `https://analytics.ghostid.ai/api/connect/shopify/webhook`

In Shopify admin

  1. Settings โ†’ Apps โ†’ Develop apps โ†’ Create app
  2. Enable read_orders scope and install the app
  3. Copy the Admin API access token (`shpat_...`)
  4. Settings โ†’ Notifications โ†’ Webhooks โ†’ Create webhook
  5. Create webhook #1 with topic Order payment (`orders/paid`) and delivery URL set to the Ghost ID URL
  6. Create webhook #2 with topic Order refunded (`orders/refunded`) and the same delivery URL
  7. Shopify requires separate webhook entries per topic; there is no multi-event selector for one endpoint
  8. Copy the webhook signing secret from Shopify

Back in Ghost ID

  1. Paste store URL (`your-store.myshopify.com`)
  2. Paste Admin API access token (`shpat_...`)
  3. Paste webhook signing secret
  4. Click Connect
  5. Ghost ID auto-verifies that both Shopify webhook topics are present
๐Ÿ’ก

Why these two topics? `orders/paid` records a confirmed sale. `orders/refunded` records a revenue reversal so net revenue stays accurate in attribution reports.

WooCommerce Setup

Use this when WooCommerce powers checkout and you want Ghost ID to capture new orders and refunds directly from Woo outbound webhooks.

In Ghost ID

  1. Go to Settings โ†’ Revenue Connections
  2. Click Connect WooCommerce
  3. Keep the modal open and copy the webhook URL shown there: `https://analytics.ghostid.ai/api/connect/woocommerce/webhook`

In WooCommerce admin

  1. WooCommerce โ†’ Settings โ†’ Advanced โ†’ REST API โ†’ Add key
  2. Set permissions to Read/Write so Ghost ID can auto-verify webhook configuration
  3. Copy Consumer Key (`ck_...`) and Consumer Secret (`cs_...`)
  4. WooCommerce โ†’ Settings โ†’ Advanced โ†’ Webhooks โ†’ Add webhook
  5. Create webhook #1 with topic Order created or Order updated, and delivery URL set to Ghost ID URL
  6. Create webhook #2 with topic Order refunded, same delivery URL
  7. Copy the webhook Secret value

Back in Ghost ID

  1. Paste store URL (`https://yourstore.com`)
  2. Paste Consumer Key and Consumer Secret
  3. Paste webhook Secret
  4. Click Connect
  5. Ghost ID auto-verifies active webhook coverage for both required topics
๐Ÿ’ก

Why two webhooks? `order.created` or `order.updated` captures successful order lifecycle events. `order.refunded` captures reversals. Ghost ID combines both to keep attributed revenue net-accurate.

๐Ÿ“ก Ad Platform Connections (Meta CAPI + Google GA4)

Send server-side conversion events to Meta and Google directly from Ghost ID. Improves attribution match quality on your ad accounts (Meta typically reports 10-20% Event Match Quality lift, often translating to ~15% lower CPA), captures conversions that ad-blockers miss, and works without you wiring CAPI yourself.

Ghost ID already captures the visitor identifiers your ad platforms need โ€” _fbp, _fbc, _ga, _gcl_au, gclid, fbclid โ€” passively from cookies set by tools you already have on your site. When a visitor converts (form submit, revenue event, checkout completed), Ghost ID's CAPI sender fires a deduplicated server-side event with proper PII hashing and your captured match keys attached.

โ„น๏ธ

How it differs from your existing pixel: Your client-side pixel still fires in the browser. Ghost ID's CAPI sender adds a second, server-side fire with the SAME event_id for deduplication. Meta and Google merge them into one conversion with higher match confidence. You get the lift without losing your existing pixel data.

Meta Conversions API Setup

Open Ghost ID and Meta Business Manager in two tabs. No Meta App registration needed โ€” Ghost ID posts to your pixel using your own access token.

In Meta Business Manager

  1. Events Manager โ†’ Data Sources โ†’ select your pixel (or create a new one)
  2. Settings tab โ†’ scroll to Conversions API section
  3. Click Generate access token โ€” pick the Set up with Dataset Quality API option (recommended; gives you the Event Match Quality score back)
  4. Copy the access token
  5. Note the Pixel ID at the top of the Settings page (15-16 digits)
  6. Optional but recommended: Open the Test Events tab and copy the test code at the top (e.g. TEST12345). With a test code, the validation event lands in your Test Events stream instead of your live data.

In Ghost ID

  1. Site selector (top sidebar) โ†’ pick the site this pixel tracks
  2. Go to /connections
  3. Scroll to the Ad Platform Connections section
  4. Click Connect Meta CAPI
  5. Paste Pixel ID, Access Token, and (optional) Test Event Code
  6. Hit Connect โ€” Ghost ID fires one synthetic PageView to validate the credentials. You'll see "Meta CAPI connected" with events_received: 1 + an fbtrace_id on success.
๐Ÿ’ก

Verify in Meta: Events Manager โ†’ your pixel โ†’ Test Events tab (if you used a test code) or Activity / Overview tab (live stream โ€” note: brand-new pixels can take 10-30 minutes to surface activity in the Overview UI even though events are received immediately). Look for the synthetic PageView from "Ghost ID Connection Validator".

Google GA4 Measurement Protocol Setup

GA4 conversions flow into your linked Google Ads account automatically โ€” no Google Cloud project, no developer token, no OAuth review needed. You just need a measurement_id (which you already have if GA4 is on your site) and an api_secret you generate in GA4 admin.

In Google Analytics 4

  1. Admin โ†’ Data Streams โ†’ select your Web stream
  2. Note the Measurement ID at the top (starts with G-)
  3. Scroll down to Measurement Protocol API secrets โ†’ click Create
  4. Name it (e.g. "Ghost ID CAPI"), save, copy the API Secret value

In Ghost ID

  1. Same site selector + /connections โ†’ Connect GA4 MP
  2. Paste Measurement ID + API Secret
  3. Hit Connect โ€” Ghost ID validates the credentials via GA4's debug endpoint (no event recorded). On success: "Google GA4 connected" with no validation messages.
๐Ÿ’ก

Verify in GA4: Configure โ†’ DebugView shows real-time events as they arrive. After a real conversion fires (or after running a synthetic test), you should see a generate_lead or purchase event with the captured gclid and UTM parameters attached.

What Triggers a CAPI Send

Once connected, Ghost ID's sender worker polls every 30 seconds for these conversion events on your site and fires to all configured platforms in parallel:

Ghost ID eventMeta eventGA4 event
form_submitLeadgenerate_lead
revenue / checkout_completed / purchasePurchasepurchase
lead_stage_changeLeadgenerate_lead
โ„น๏ธ

Idempotency: Ghost ID generates a deterministic event ID per source event, so re-runs and worker restarts never re-fire the same conversion. Meta and Google receive the same event_id on the server-side fire as your client-side pixel uses, allowing them to dedupe across the two paths.

Disconnecting

  • Click Disconnect (trash icon) on the Meta CAPI or GA4 MP card on /connections โ€” Ghost ID stops firing immediately and clears your stored credentials
  • To rotate credentials: click Reconnect on the connected card and paste new values. The validation event re-fires to confirm the new credentials work before saving.

๐Ÿงช Verify It's Working

After a real sale:

  • Check your /revenue dashboard โ€” the sale should appear within ~30 seconds
  • The source column tells you which path caught the sale:
SourceMeaning
apiCaught via `GHOST.revenue()` on your success page
stripeCaught via Stripe webhook, ghost_vid stamped in metadata
stripe_subscriptionCaught via Stripe invoice.paid event (renewals)
stripe_email_fallbackCaught via Stripe webhook using email match (GHL / platform checkouts without metadata)
shopifyCaught via Shopify order webhook
woocommerceCaught via WooCommerce order webhook

๐Ÿ› ๏ธ Troubleshooting

Revenue isn't appearing after a test sale

  • Confirm the tracking script is on the page where the purchase originates (visit any page, open browser devtools โ†’ Network โ†’ look for analytics.ghostid.ai/api/script.js)
  • If using the JS call: open browser console on the thank-you page and check for errors โ€” typos in `GHOST.revenue()` are silent otherwise
  • If using a webhook: in your provider dashboard, open the webhook endpoint detail page and check delivery status. 200 = received, 4xx = signature mismatch or unknown site, 5xx = server issue

Webhook fires but nothing attributes

  • Your customer may not have given their email earlier in the funnel. Ghost ID needs either explicit metadata.ghost_vid OR a captured email to link the sale to a visitor. Add an email-capture step before checkout (contact form, opt-in, newsletter) and attribution will resume.
  • Alternatively, switch to the Universal JS Call path โ€” it uses the cookie directly, no email needed.

I'm seeing duplicate revenue rows

  • If using JS calls: pass a consistent `transactionId` โ€” Ghost ID dedupes on it. If you omit the ID, accidental double-fires create duplicate rows.
  • If using Stripe webhooks: as of April 2026, Ghost ID dedupes across all three Stripe events (checkout, payment_intent, invoice) using shared transaction IDs. Historic rows written before that date may contain duplicates โ€” contact support for a cleanup.

๐Ÿ“˜ API Reference

For server-side revenue tracking (instead of client-side `GHOST.revenue()`), see the Revenue API Reference.