Stripe
Connect Stripe to AnyTrack with the AnyTrack app for Stripe. AnyTrack tracks trials, one-time payments, subscriptions and renewals server-side, attributes each one to the ad click, and sends it to your ad platforms.
Stripe Integration Overview
Section titled “Stripe Integration Overview”The AnyTrack app for Stripe connects your Stripe account to AnyTrack. Stripe sends each payment event to AnyTrack server-side. AnyTrack matches the payment to the visitor’s click ID, records the conversion, and attributes it to the campaign. On the Starter plan and above, AnyTrack sends the conversion to your ad platforms through the Conversion API.
The integration tracks these Stripe activities:
- Free trials that start
- One-time payments
- New subscriptions and their first payment
- Subscription renewals and their payments
- Payment methods that customers add
Server-side tracking does not use a thank-you page pixel. Ad blockers and browser privacy settings do not stop the payment from reaching AnyTrack.
On the Free plan, AnyTrack tracks and attributes Stripe payments, but does not send them to your ad platforms.
When to use the Stripe integration
Section titled “When to use the Stripe integration”The Stripe integration is for websites that send payments to Stripe directly: a custom website or funnel, a SaaS app, or any other site whose checkout does not run on a platform that AnyTrack integrates with.
When a platform that AnyTrack integrates with runs your checkout, AnyTrack gets the sale from that platform, not from Stripe. For example, if you sell on ClickFunnels with Stripe as the payment gateway, AnyTrack gets the sale from the ClickFunnels integration. The same applies to GoHighLevel, Shopify, and the other platforms in the Integration Catalog.
How the Stripe integration works
Section titled “How the Stripe integration works”What happens between the ad click and the conversion in your ad platforms
Visitor lands on your site
The AnyTrack Tracking Tag records the session, the UTMs, and the ad-platform click IDs. It gives the visitor an AnyTrack click ID.
Traffic source + click ID Visitor starts the Stripe checkout
The Tracking Tag adds the click ID to your Stripe Payment Links. A custom checkout sends the click ID to the Stripe metadata.
atclid Stripe sends the event to AnyTrack
When a trial starts, Stripe creates a subscription invoice, or a payment succeeds, Stripe sends the event to AnyTrack server-side.
AnyTrack attributes the conversion
AnyTrack reads the click ID, the customer data, and the order items. It records the conversion and attributes it to the campaign.
StartTrial / Purchase / SubscriptionPaid / RenewalPaid Conversion sent to your ad platforms
On the Starter plan and above, AnyTrack sends the conversion to your connected ad platforms through the Conversion API.
Technical details
Section titled “Technical details”| Supported features | Stripe |
|---|---|
| Tracking method Via Webhook | Server-side tracking |
| Setup method | OAuth |
| |
| Event attributes | |
| Conversion Mapping Rename or turn off events. | Yes |
| Combined Orders Groups upsells with the purchase. | No |
| Tracking Group Integration reference for AutoTag. | stripe |
| Tracking parameter Carries the click_id. | client_reference_id |
Tracked Events
Section titled “Tracked Events”| Stripe event | Default AnyTrack event | When it fires | Value |
|---|---|---|---|
| Trial started | StartTrial | A customer starts a subscription with a free trial | The subscription price |
| One-time payment made | Purchase | A payment that is not part of a subscription succeeds | The amount paid |
| Subscription started | Subscribe | Stripe creates the first invoice of a subscription, or the first invoice after a trial. The invoice is not paid yet. | The invoice total |
| First subscription payment made | SubscriptionPaid | The first payment of a subscription succeeds, including the first payment after a trial | The amount paid |
| Subscription renewed | Renew | Stripe creates the invoice for a new billing cycle. The invoice is not paid yet. | The invoice total |
| Renewal payment made | RenewalPaid | A recurring subscription payment succeeds | The amount paid |
| Payment method added | AddPaymentInfo | A payment method is added to a Stripe customer | 0 |
Payment, trial, and invoice events carry the currency, the order items, the Stripe transaction ID, and the customer data from Stripe: email, name, phone, and address.
AddPaymentInfo carries the customer data from the billing details of the payment method, and the payment method ID as the transaction ID. It has no value, currency, or order items.
A subscription payment outside the billing cycle, for example an immediate upgrade charge, is also a SubscriptionPaid event. AnyTrack skips a Purchase, SubscriptionPaid, or RenewalPaid with a value of 0.
You can change the AnyTrack event for each Stripe event on the integration page. Each ad platform receives only the events in its Event Mapping. Map StartTrial, SubscriptionPaid, and RenewalPaid there to send them to your ad platforms.
Setup Guide
Section titled “Setup Guide”Watch the complete Stripe setup from start to finish: connect Stripe, pass the click ID to Stripe, make a test purchase, send your conversions to Facebook with the Conversion API, and switch from Sandbox to Live.
Step 1: Connect Stripe in AnyTrack
Section titled “Step 1: Connect Stripe in AnyTrack”- Go to the Integration Catalog and search for Stripe.
- Click Install Integration.
- Select the property.
- Click Next.
- Select the mode:
- Live tracks real payments.
- Sandbox tracks payments in a Stripe sandbox. Use it to test your setup.
- Click Connect Stripe.
- In Stripe, select your Stripe account and approve the permissions of the AnyTrack app.
Stripe sends you back to AnyTrack, and the integration becomes active.
You can also start from the Stripe App Marketplace. Install the AnyTrack app there. Stripe then opens the AnyTrack dashboard, where you select the property to connect.
Step 2: Pass the click ID to Stripe
Section titled “Step 2: Pass the click ID to Stripe”AnyTrack attributes a Stripe payment through the AnyTrack click ID. Pick the path for your checkout:
- Stripe Payment Links: you do not change your code. See Stripe Payment Links.
- An AI coding tool builds your site, for example Claude Code, Codex, or Lovable: give the tool the AnyTrack prompt. See Use an AI coding tool.
- You write your checkout code: add the click ID to the Stripe metadata. See Add the code yourself.
Then check the click ID in Stripe.
Stripe Payment Links
Section titled “Stripe Payment Links”You do not need to change your Payment Links. The Tracking Tag finds each buy.stripe.com link on your page and adds the click ID to its client_reference_id parameter.
- Put your Payment Link on a page that carries the AnyTrack Tracking Tag.
- Do not set your own
client_reference_idon the link. If the link already has a value, the Tracking Tag keeps it and does not add the click ID.
Use an AI coding tool
Section titled “Use an AI coding tool”Does an AI coding tool build your site, for example Claude Code, Codex, or Lovable? Give it the AnyTrack Stripe prompt. The prompt tells the tool to find each Stripe checkout on your site, to read the AnyTrack click ID when the checkout starts, and to add the click ID to the Stripe metadata. The rest of your checkout does not change.
- Install the AnyTrack Tracking Tag on your site. Your AI coding tool can do it: copy the Tracking Tag of your property and tell the tool to add it to the
headsection of every page. The prompt stops when it does not find the Tracking Tag. - Copy the prompt below, or download the AnyTrack Stripe prompt.
- Open your project in your AI coding tool and paste the prompt.
- Review the changes before you publish your site. The tool lists the checkout flows that it found and the files that it changed. It ends with “✔️Finished successfully”.
- Make a test payment in a Stripe sandbox, then check the click ID in Stripe.
Show the AnyTrack Stripe prompt
# AnyTrack: Pass the AnyTrack Click ID to Stripe
We at AnyTrack provide this prompt to help you pass the **AnyTrack Click ID** (`atclid`) into Stripe. Inspect this website and implement the required changes using its existing framework, backend, Stripe integration, and purchase types. Cover every active checkout path you find, while retaining correct existing attribution code. Use the name “AnyTrack Click ID” throughout your implementation notes and customer-facing explanations.
**Strict scope: do not change the architecture or modify any existing flow. The final result must behave exactly as it does today, with the only functional addition being retrieval of the AnyTrack Click ID generated by our Tracking Tag and passing it to Stripe through the existing integration. Additional changes or fixes are out of scope.**
Make only the minimal attribution-specific changes needed in existing code paths and payloads. The only permitted timing change is awaiting the bounded async `atclid` lookup described below before the existing checkout creation request. Do not refactor, redesign, migrate integrations, upgrade dependencies, add checkout steps, or otherwise change UI, business logic, payment behavior, request sequencing, or payment retry behavior. Do not fix unrelated issues you discover. If attribution cannot be added within these constraints, report the specific limitation instead of changing the architecture or flow. Do not deploy or publish the changes to the live site: the customer reviews and tests them first. These constraints apply to every instruction below.
The customer may use a Stripe server SDK or make direct HTTP requests to the Stripe API. Both approaches are supported. Keep whichever approach the customer already uses; do not replace SDK calls with direct API requests or introduce an SDK where direct requests already work. The intended flow in either case is:
`Async AnyTrack('atclid') lookup in the browser → existing checkout/payment request's atclid field → backend → Stripe metadata.atclid (value unchanged)`
Implement when code access is available; otherwise provide concrete instructions for the detected integration. Ask only for information you cannot establish from the project and that is necessary to proceed.
## 1. Discover the integration before editing
First, verify that the customer's AnyTrack Tracking Tag is installed on the relevant website pages. **If the tag is missing, stop the task and tell the customer: “The AnyTrack Tracking Tag is not installed. Please install it on your website and confirm when it is installed so I can continue.” Do not continue implementation until the customer explicitly confirms installation.** After confirmation, re-check the installation before proceeding; if it is still missing, report that and remain stopped. Do not install the tag yourself, request a snippet as a substitute for confirmation, copy another site's tag, or invent a property ID.
This is an implementation prerequisite. Once the tag is installed, temporary runtime unavailability is handled by the bounded lookup below; an unavailable `window.AnyTrack` during page loading alone does not establish that the installation is missing.
Trace each checkout entry point to the code or platform that creates the Stripe object. Inspect the frontend, request schemas, backend routes or server actions, Stripe calls, installed SDK versions, configured API version, and any existing attribution mapping. Do not print secret values.
For projects built with Lovable, Base44, or similar platforms, identify the existing checkout implementation and platform-native backend functions or payment integration. Inspect the actual project; do not assume a particular backend or Stripe flow from the platform name. Pass the browser-retrieved AnyTrack Click ID through that existing mechanism and attach it where the Stripe object is created, using the matching metadata fields in section 4. Preserve platform SDK calls, function invocation, authentication, secrets management, and checkout behavior. If a managed integration does not expose the required per-checkout metadata fields, report the specific limitation; do not replace the integration or introduce a new backend.
Identify:
- Whether the backend uses a Stripe server SDK, direct HTTP API requests, or both, and where each Stripe object is created.- How checkout data reaches the backend: JSON, FormData/multipart, URL-encoded or native form submission, framework server actions, or another existing transport. Identify its parser and validation schema as well.- Hosted Checkout, embedded Checkout, custom Checkout using the Checkout Sessions API, direct PaymentIntents, or direct Billing Subscriptions.- One-time purchases, subscriptions, mixed carts, trials, and delayed or off-session charges actually supported by the site. Use Stripe's mode and recurring price configuration as evidence; product names such as “monthly supply” are insufficient.- Where the AnyTrack Tracking Tag loads, which property it belongs to, and whether existing code already collects and passes the AnyTrack Click ID.- When Stripe objects are created relative to the checkout action, including objects created on page load or after a queued backend job.
A Payment Element alone does not identify the backend flow. Trace whether its client secret comes from a Checkout Session, a direct PaymentIntent, or a Subscription's invoice payment.
Briefly list the detected flows and evidence, then implement the applicable branches. Keep the existing SDK/API version and UI mode values; this task does not require an integration migration.
## 2. Retrieve the AnyTrack Click ID in the browser
Use the customer's installed AnyTrack Tracking Tag after the prerequisite in section 1 is satisfied. Avoid duplicate AnyTrack Tracking Tag installations.
Don't create new utilities for getting the AnyTrack Click ID, but rely on the below helper `getAnyTrackClickId`. Don't generate it yourself by directly calling `AnyTrack('atclid')` or substitute a random UUID, email, Stripe customer ID, `gclid`, or `fbclid`. Use the helper `getAnyTrackClickId` to get the AnyTrack Click ID.The helper `getAnyTrackClickId` is an async function, it tries to get the AnyTrack Click ID and retries every 300ms during 5 seconds before giving up. In worst case the helper will return undefined, which is safe to send to the API later.
Call this helper only in the browser checkout handler, using `await getAnyTrackClickId()` where appropriate. When a new checkout/purchase flow attempt begins, the call of `getAnyTrackClickId` function will get the AnyTrack Click ID to include it into the request that eventually sends the value to Stripe (as instructed in the later section).
```jsasync function getAnyTrackClickId(browser = globalThis) { const deadline = performance.now() + 5000;
while (performance.now() < deadline) { try { const AnyTrack = browser?.AnyTrack; if (typeof AnyTrack === 'function') { const atclid = AnyTrack('atclid'); if (typeof atclid === 'string' && atclid.length > 0) return atclid; } } catch { // The tracker may become available on a later attempt. }
const remaining = deadline - performance.now(); if (remaining <= 0) break; await new Promise((resolve) => setTimeout(resolve, Math.min(300, remaining))); }
console.error('[AnyTrack] Could not retrieve the AnyTrack Click ID within 5 seconds.'); return undefined;}```
Retain the lookup promise and its result per checkout attempt using the existing browser submission handler or attempt context; do not require a particular frontend framework or state model. Keep the existing idempotency key and access token associated with the attempt, if used. Reuse the same promise/result for the same attempt, including a final `undefined`; a payment/API retry must not restart the 5-second lookup. Preserve the existing busy/submission guard so repeated clicks cannot create parallel checkouts. If an attempt is canceled or replaced while waiting, its result must not submit a stale checkout. Start a new lookup only for a genuinely new attempt. Do not add persistence or a new payment retry system. If the customer already carries checkout context across steps or queued jobs, pass the field through that existing context.
## 3. Carry attribution through the existing backend boundary
Preserve the customer's existing browser-to-backend transport, content type, endpoint or server action, parser, and submission behavior. Do not convert forms or server actions to JSON/fetch, introduce a new API endpoint, or replace the transport to add attribution. Always name the field or argument carrying the AnyTrack Click ID `atclid` throughout the existing checkout context, payloads, schemas, and backend mappings. If an existing attribution field uses another name, update that field and its mappings consistently to `atclid` within the existing transport. The final Stripe metadata key must also be exactly `atclid`.
After awaiting the lookup, pass the resolved string unchanged using the existing format. On timeout, `undefined` is returned. Do not serialize it as an empty string, `null`, or the string `"undefined"`:
| Existing browser-to-backend transport | On successful lookup | On timeout || --- | --- | --- || JSON | Include `atclid` in the existing payload. | Omit the property; `JSON.stringify` also omits object properties whose value is `undefined`. || FormData/multipart or URLSearchParams | Set the `atclid` field to the resolved string using the existing serializer. | Omit/delete the attribution field; do not pass `undefined` to `.set()` or `.append()`, which would stringify it. || Native HTML form | Populate a hidden input named `atclid` before the existing submission. | Remove or disable that attribution input so it is not submitted. || Framework server action or other transport | Pass `atclid` through the existing action's supported argument or form payload. | Use its supported optional-field representation, without inventing a placeholder value. |
For form submissions, integrate the bounded lookup into the existing submit handling while preserving validation, the submitter's name/value and action, CSRF fields, redirects, and duplicate-submission protection. Ensure serialization round-trips the exact AnyTrack Click ID; transport encoding is not sanitization. Read the field on the server through the existing parser or action argument rather than assuming a JSON body.
Hosted, embedded, and custom Checkout send the field through the customer's existing Checkout Session creation request; direct one-time checkout uses the existing PaymentIntent creation request; direct subscription checkout uses the existing Subscription creation request. Route names such as `/api/checkout-sessions`, `/api/payment-intents`, and `/api/subscriptions` are examples, not names to impose on the project. In all eight cases the browser sends the AnyTrack Click ID to the application's backend, and the backend sends it to Stripe.
Update every intervening schema, validator, action, service, and queued payload that could drop this field. For delayed creation, retain the browser-captured value with the specific order or checkout context until the backend creates the Stripe object.
On the server, pass the supplied AnyTrack Click ID through unchanged. Check only that it is a non-empty string before adding metadata. Do not sanitize, trim, truncate, remove control characters, hash, or otherwise rewrite it:
```jsfunction createAtclidMetadata(atclid) { return typeof atclid === 'string' && atclid.length > 0 ? { atclid } : {};}```
Adapt the same behavior to the backend's language. The value retrieved from AnyTrack must be identical to the value sent in Stripe metadata. Missing attribution must not prevent checkout or send an empty `metadata.atclid` value that could clear an existing value.
Pass the extracted `atclid` field or argument to `createAtclidMetadata` (or its equivalent in the backend's language), then merge the result into the relevant existing metadata maps without replacing other keys or nested payment/subscription settings. Extraction may use a parsed body field such as `body.atclid`, `formData.get('atclid')`, or an `atclid` server-action argument, depending on the existing integration. Attach this metadata during Stripe object creation without a separate attribution update request. If a customer's existing flow pre-creates an object, use an existing server-side update path for the correctly owned object only if it can carry the field without changing the flow. Otherwise report the limitation. Do not move object creation, add requests or checkout steps, or reorder confirmation to accommodate attribution.
Keep secret-key Stripe requests on the backend. Do not add arbitrary metadata to Stripe.js confirmation arguments, billing details, Payment Element options, or a hosted Checkout URL. Use metadata for the AnyTrack Click ID and preserve any existing business use of `client_reference_id`. Preserve server-owned prices, authentication, object ownership, idempotency, capture behavior, subscription settings, and redirect handling.
## 4. Apply the matching Stripe API branch
The table lists fields to supply through the existing Stripe server SDK call or direct HTTP API request. The metadata destinations are the same in both cases; adapt the parameter syntax and serialization to the customer's SDK/language or HTTP client. “Stripe request” in this prompt includes either approach. Implement only the rows the project uses, but cover all discovered entry points for those rows.
| Detected integration | Purchase type | Fields to populate with the unchanged AnyTrack Click ID || --- | --- | --- || Hosted Checkout Session | One-time | `metadata.atclid` and `payment_intent_data.metadata.atclid` || Hosted Checkout Session | Subscription | `metadata.atclid` and `subscription_data.metadata.atclid` || Embedded Checkout Session | One-time | `metadata.atclid` and `payment_intent_data.metadata.atclid` || Embedded Checkout Session | Subscription | `metadata.atclid` and `subscription_data.metadata.atclid` || Custom Checkout using Sessions | One-time | `metadata.atclid` and `payment_intent_data.metadata.atclid` || Custom Checkout using Sessions | Subscription | `metadata.atclid` and `subscription_data.metadata.atclid` || Direct PaymentIntent, including Elements | One-time | PaymentIntent `metadata.atclid` || Direct Billing Subscription, including Elements for its invoice payment | Subscription | Subscription `metadata.atclid` |
For Sessions, branch on the actual `mode`: use `payment_intent_data` for `payment` and `subscription_data` for `subscription`. A mixed cart handled in subscription mode follows the subscription branch. Keep Session metadata as well as the underlying object's metadata. See [Checkout Session creation](https://docs.stripe.com/api/checkout/sessions/create), [PaymentIntent creation](https://docs.stripe.com/api/payment_intents/create), and [Subscription creation](https://docs.stripe.com/api/subscriptions/create).
For subscriptions, attach the AnyTrack Click ID to the Subscription at creation. Renewals do not require a new browser lookup or attribution request. Do not add separate writes of `atclid` to invoice metadata or the subscription's invoice PaymentIntent, invoice updates, renewal hooks, or webhook handlers. If inspecting an existing downstream consumer, distinguish Stripe's own metadata propagation from writes performed by the application; see [Stripe's metadata propagation rules](https://docs.stripe.com/metadata#copy-metadata-to-another-object).
Do not use Customer metadata alone as the transaction attribution source or overwrite historical subscription attribution on every visit. For SetupIntents, setup-mode Sessions, invoice-only flows, subscription schedules, or legacy Charge integrations, trace the eventual payment-producing object and check its version-specific API. Saving a payment method is not a purchase; preserve the AnyTrack Click ID through the application's existing context and attach it when the actual payment or subscription is created.
Don't create a new webhook, or change if any webhooks exist. The current task is only about passing the AnyTrack Click ID to Stripe.
## 5. Verify each detected path and report the result
Use focused automated checks and Stripe test mode or sandbox where available. Never create live charges to verify tracking. Cover:
- The AnyTrack Tracking Tag installation prerequisite is satisfied. If installation is missing, stop and wait for the customer's explicit confirmation before continuing implementation.- A retrieved string is named `atclid` throughout the existing checkout context and backend boundary and passes unchanged to every required Stripe `metadata.atclid` field.- The existing browser-to-backend transport and parser are preserved. Verify successful field extraction and omission on timeout using the actual JSON, form, server-action, or other supported payload; no placeholder string is sent.- Each active UI/purchase combination, including any pre-created objects, deferred creation, trials, or retry paths the site actually supports.- Lookup attempts run immediately and then every 300 ms until success or the 5-second deadline. Missing or throwing AnyTrack, bootstrap queue return values, and empty results are retried. Replacing the bootstrap function with the loaded SDK during polling works.- Success resolves the exact AnyTrack Click ID and stops polling. Timeout logs one error without the raw AnyTrack Click ID, resolves `undefined`, and lets checkout proceed with the optional attribution field omitted and no added `atclid` metadata. No timer continues polling after completion.- A missing AnyTrack Click ID does not erase existing Stripe metadata. Payment/API retries reuse the original attempt's lookup promise/result, including `undefined`, and do not create another polling window. Separate checkout attempts keep their own state.- Existing submission guards prevent duplicate requests while awaiting the lookup, and canceled or replaced attempts cannot submit after their lookup resolves.- The architecture and existing flows remain unchanged apart from the explicitly requested bounded lookup before checkout creation. Review the diff to confirm every production-code change is strictly necessary to retrieve or pass `atclid`, with no unrelated changes or fixes.
When test/sandbox credentials and access permit, complete a sandbox checkout and inspect the resulting Stripe objects server-side or in the Dashboard. Distinguish source inspection, mocked requests, actual Stripe object verification, and confirmed AnyTrack ingestion; report only what you verified.
Finish with a compact table of detected flows, changed files or platform settings, destination fields, verification results, and any remaining customer action. If all relevant paths are already correct, verify and report that rather than rewriting them.
The scope is carrying the AnyTrack Click ID into Stripe. Preserve existing analytics events; do not add duplicate `InitiateCheckout`/`Purchase` events or a new webhook pipeline as a side effect.
After the setup is ready to generate atclid and pass it to Stripe as a metadata field, and the project's flows are covered, with this, tell at the end: ✔️Finished successfullyAdd the code yourself
Section titled “Add the code yourself”Use this path when you write your checkout code, with Stripe Checkout or Stripe Elements. When your server creates the Checkout Session, the PaymentIntent, or the Subscription, add the click ID to the Stripe metadata with the key atclid.
-
Read the click ID in your browser checkout handler with this helper. It retries every 300 ms for 5 seconds while the Tracking Tag loads. If it cannot read the click ID, it returns
undefined.async function getAnyTrackClickId(browser = globalThis) {const deadline = performance.now() + 5000;while (performance.now() < deadline) {try {const AnyTrack = browser?.AnyTrack;if (typeof AnyTrack === 'function') {const atclid = AnyTrack('atclid');if (typeof atclid === 'string' && atclid.length > 0) return atclid;}} catch {// The Tracking Tag may become available on a later attempt.}const remaining = deadline - performance.now();if (remaining <= 0) break;await new Promise((resolve) => setTimeout(resolve, Math.min(300, remaining)));}return undefined;}// In your checkout handler, before the checkout request:const atclid = await getAnyTrackClickId(); -
Send
atclidto your server with the checkout request. If the value isundefined, do not send the field. -
Add the value to the metadata when your server creates the Stripe object:
- Checkout Session, one-time payment:
metadata.atclidandpayment_intent_data.metadata.atclid - Checkout Session, subscription:
metadata.atclidandsubscription_data.metadata.atclid - PaymentIntent created by your server (Elements):
metadata.atclidon the PaymentIntent - Subscription created by your server:
metadata.atclidon the Subscription
// Checkout Session for a subscription (Node.js)const atclid = req.body.atclid;const metadata = typeof atclid === 'string' && atclid.length > 0 ? { atclid } : {};const session = await stripe.checkout.sessions.create({mode: 'subscription',line_items: [{ price: 'price_123', quantity: 1 }],metadata,subscription_data: { metadata },success_url: 'https://example.com/thank-you',}); - Checkout Session, one-time payment:
Pass the click ID to Stripe without changes. Do not send an empty atclid: in Stripe, an empty metadata value deletes the key.
Check the click ID in Stripe
Section titled “Check the click ID in Stripe”Stripe does not copy metadata from one object to another, so check each object that your checkout creates.
-
Make a test payment through your checkout. Use a Stripe sandbox with a Sandbox connection.
-
In the Stripe Dashboard, open each object below and find
atclidin its Metadata section:- Payment: a one-time payment shows
atclid. - Subscription: a subscription shows
atclid. Its payments do not show it. AnyTrack reads the click ID of each subscription payment from the customer or the subscription. - Customer: AnyTrack adds
atclidto the customer when it receives the first Stripe event with a click ID. Check the customer after the event appears in the Events Log of your Stripe integration. The customer value has 26 characters: the Property ID and the Client ID. It does not have the last 8 characters of the click ID. This is correct.
- Payment: a one-time payment shows
Payment Links send the click ID in client_reference_id, not in the metadata. To check a Payment Link, see Validate your integration.
Step 3: Turn off your old Stripe tracking
Section titled “Step 3: Turn off your old Stripe tracking”Did you track Stripe before with Zapier, Make, or a Custom Integration? Turn off that Zap, scenario, or webhook after you connect the Stripe app. Otherwise AnyTrack records each payment twice.
Repeat payments and renewals
Section titled “Repeat payments and renewals”When AnyTrack receives the first Stripe event with a click ID from your property, it saves the visitor on the Stripe customer, in the customer metadata key atclid. The event can be any tracked Stripe event, for example a trial or a payment. AnyTrack saves it only when the customer has no atclid yet.
The saved value is the first 26 characters of the click ID: the Property ID and the Client ID. The Client ID identifies the visitor. See AnyTrack Identifiers.
When a later payment from the same customer has no atclid in its own metadata, AnyTrack uses the customer value. AnyTrack attributes each renewal and each new purchase to the same visitor. This is the only data that AnyTrack writes to your Stripe account.
When a payment has no click ID at all, AnyTrack tries to match the customer email to a visitor it already identified, with Identity Resolution. If no visitor matches, the payment has no traffic source.
Permissions
Section titled “Permissions”The AnyTrack app asks for these Stripe permissions:
| Permission | Why AnyTrack needs it |
|---|---|
| Connected account, read | Read and validate the basic information of your Stripe account |
| Events, read | Receive the payment and subscription events of your account |
| Checkout Sessions, read | Read checkout purchases and the click ID of Payment Links |
| PaymentIntents, read | Read payments and the click ID in their metadata |
| Invoices, read | Track subscription invoices and the click ID in the subscription metadata |
| Subscriptions, read | Read subscriptions and the click ID in their metadata |
| Charges, read | Read charges and the click ID in their metadata |
| Payment methods, read | Receive the payment method events for AddPaymentInfo |
| Customers, read | Read the customer data that AnyTrack adds to the conversion |
| Customers, write | Save the click ID in the customer metadata |
Validate your integration
Section titled “Validate your integration”- Open a page with the Tracking Tag that links to your Stripe checkout.
- For a Payment Link, confirm that the link carries
client_reference_idwith a click ID. The AnyTrack Pixel Helper shows the Tracking Tag on the page. - Complete a test payment. Use a Stripe sandbox with a Sandbox connection, or a low-price product with a Live connection.
- For a checkout built with code or an AI coding tool, check the click ID in Stripe.
- Open the Events Log of your Stripe integration and confirm that the event appears, for example
Purchase,SubscriptionPaid, orStartTrial. - Open the Conversions Report and confirm that the event shows the traffic source of your test visit.
Switch from Sandbox to Live
Section titled “Switch from Sandbox to Live”AnyTrack records Sandbox payments the same way as live payments. When your tests are complete, replace the Sandbox integration with a Live integration.
A Sandbox integration shows a Sandbox label in your Integrations list and on its integration page.
A property has one Stripe integration. You cannot change the mode of an integration, so delete the Sandbox integration first. Until you delete it, the property shows Has Integration in the property list, and you cannot select the property.
- Open your Stripe integration.
- Open the Settings tab.
- In Danger Zone, click Delete Integration.
- In the Confirm Deletion dialog, click Confirm. AnyTrack stops receiving events from the Sandbox connection.
- Go to the Integration Catalog and search for Stripe.
- Click Install Integration.
- Select the same property.
- Click Next.
- Select Live.
- Click Connect Stripe.
- In Stripe, select your Stripe account and approve the permissions of the AnyTrack app.
Stripe sends you back to AnyTrack, and the Live integration becomes active. Make a payment for a low-price product, then do the steps in Validate your integration.
When you delete the Sandbox integration:
- The Event Mapping of your ad platforms does not change.
- AnyTrack makes no change in your Stripe account.
- If you changed the AnyTrack events of the Sandbox integration, change them again on the integration page of the Live integration.
Troubleshoot missing Stripe conversions
Section titled “Troubleshoot missing Stripe conversions”| Symptom | Cause | Fix |
|---|---|---|
| No event reaches AnyTrack | The payment was made in the other mode, or the integration is not active | Check the mode of the integration (Live or Sandbox) and its status. If the mode is wrong, see Switch from Sandbox to Live. If the integration is not active, connect Stripe again. |
| The event appears with no traffic source | The payment carries no click ID | Put the Payment Link on a page with the Tracking Tag. For a custom checkout, add atclid to the metadata. See Step 2. |
| Payment Link payments have no traffic source | The link already had your own client_reference_id | Remove your value from the link, so the Tracking Tag can add the click ID. |
The Events Log shows The event is not related to property id | The click ID belongs to another property | Connect the Stripe integration in that property too. |
| A payment of 0 is missing | AnyTrack skips payments with a value of 0 | No action. Trials appear as StartTrial. |
| Each payment appears twice | Another source also sends the sale: an old Zapier, Make, or webhook setup, or the integration of the platform that runs your checkout | Keep one source for each sale. Turn off the old setup (see Step 3). If a platform such as ClickFunnels runs your checkout, remove the Stripe integration. |
| A refund does not change the conversion | AnyTrack does not track refunds | See Commission Reversals and Refunds. |
Stripe Integration - Frequently Asked Questions
FAQ was last reviewed on 2026-10-13
Do I need to change my Stripe Payment Links?
buy.stripe.com link on your page, in the client_reference_id parameter. Put the link on a page that carries the Tracking Tag.How does AnyTrack attribute subscription renewals?
atclid. AnyTrack uses it for each renewal of that customer, so the renewal is attributed to the same visitor. The default event for a renewal payment is RenewalPaid.Why does the AnyTrack app need write access to my Stripe customers?
atclid, so later payments of that customer keep their attribution. This is the only data that AnyTrack writes to Stripe. It does not change payments, subscriptions, or other customer data.Is the first payment after a free trial a SubscriptionPaid or a RenewalPaid?
SubscriptionPaid. AnyTrack sends StartTrial when the trial starts, Subscribe when Stripe creates the first invoice after the trial, SubscriptionPaid when the customer pays it, and RenewalPaid for each payment after that.I built my site with Lovable, Claude Code, or Codex. How do I pass the click ID to Stripe?
I sell on ClickFunnels with Stripe. Do I need the Stripe integration?
How do I switch my Stripe integration from Sandbox to Live?
Can I connect one Stripe account to several properties?
What happens to a payment without a click ID?
Does AnyTrack track Stripe refunds?
Add the Tracking Tag to your pages so AnyTrack can attribute Stripe payments.