Stripe
A thank-you page misses purchases: the customer closes the tab, the redirect fails, a browser blocks the pixel. With the Stripe webhook, Purchase comes from Stripe itself and goes to your pixels from our servers.
This works with Payment Links, Stripe Checkout, Buy Buttons and pricing tables. There is no Stripe Connect and no OAuth: you add one webhook in your own Stripe account, and Pixelary gets no access to anything else there.
1 Add the webhook in Stripe
In the Pixelary dashboard open your site and choose Stripe. Copy the webhook URL, which looks like
https://api.pixelary.app/hooks/stripe/<site_key>.
In Stripe, open Developers → Webhooks → Add destination. Listen to events from your account with the snapshot payload, paste the URL, and select these events:
| Event | What Pixelary does |
|---|---|
| checkout.session.completed | Sends Purchase when the session is paid. |
| checkout.session.async_payment_succeeded | Sends Purchase when a delayed payment, such as a bank debit, comes through. |
| invoice.paid | Sends Purchase for a subscription renewal, only with Count subscription renewals on. |
2 Paste the signing secret
On the webhook's page in Stripe, reveal the signing secret. It starts with whsec_. Paste it on the Stripe screen in
Pixelary. It is stored encrypted and never shown again. Only the site's owner can change it.
3 There is nothing to install
Once Stripe is connected, the Pixelary script on your site does the rest. For visitors who allow ad cookies, it adds their
visitor ID to buy.stripe.com links as client_reference_id, and to
<stripe-buy-button> and <stripe-pricing-table> elements as
client-reference-id. It also tells Pixelary their ad click and browser IDs, so a purchase can match the ad that
brought them. Pixelary keeps these for 7 days.
A link or element that already has a reference of yours stays as it is, and its purchases count as not linked. The same goes for Checkout Sessions you create with Stripe's API and Payment Links on a custom domain.
4 Make a test purchase
Stripe marks test events with livemode: false. They go only to test mode: the test event code on Meta and TikTok,
and validation only on ChatGPT Ads. A pixel without a test event code is skipped, so a test purchase can never count as a real
conversion. In Live events they appear with a Stripe test label, and the Stripe screen shows
the last event received.
Avoid counting a sale twice
If a trigger on your thank-you page also sends Purchase, each sale counts twice: the webhook's copy and the trigger's copy have different event IDs, so the platforms cannot merge them. The Stripe screen warns you when an enabled trigger sends Purchase. Turn that trigger off once test purchases show up in Live events. If you send Purchase from your own code, remove that too.
A redelivery from Stripe never counts twice. Pixelary remembers each event and session it has handled, and the event ID sent to the platforms comes from the Stripe session.
Consent
A webhook has no browser, so nobody can ask the customer at that moment. What Pixelary does depends on whether the purchase matches a visit that recorded an answer:
| Purchase | What happens | What is sent |
|---|---|---|
| Matches a visit, ad data allowed | Sent | Ad click and browser IDs, IP address and user agent from the visit; hashed email and phone |
| Matches a visit, ad data refused | Not sent | Nothing, whatever your settings say |
| Link from a visitor who refused ad cookies | Not sent | Nothing, whatever your settings say |
| No matching visit, customer outside the EEA, UK and Switzerland | Sent | Hashed email only |
| No matching visit, customer in the EEA, UK or Switzerland, or country unknown | Not sent | Nothing, unless you turn on the setting below |
"Country" here is the billing country Stripe reports. A purchase has no matching visit when the customer opened the link somewhere else, such as an email, or paid more than 7 days after the click. Purchases not sent stay in Live events with the reason, so nothing disappears without a trace.
What counts as a purchase
- The value is the session's total in its currency, with zero-decimal currencies such as JPY handled.
- A free trial or a fully discounted order is not a Purchase, because nothing was paid. Live events shows it as not sent.
- A renewal is not a Purchase unless you turn on Count subscription renewals. Renewals have no visit, so the rules for purchases with no matching visit apply.
- Your filters still apply: excluded countries and "only conversions from ad clicks" stop a purchase like any other event.
- Each purchase counts as one server event on your plan. Test events count too.
What is kept
- Stripe sends the customer's email, phone and billing address to our servers. Email and phone are hashed for each platform and go no further. Pixelary does not store them, or Stripe's payload, and the event log shows only the names of the matching fields.
- Pixelary keeps what a visitor allowed, with their ad click and browser IDs, IP address and user agent, for up to 7 days in the EU, and deletes it when the purchase uses it.
- Add this to your own privacy policy: tell customers that purchase data goes to the ad platforms you use.
If nothing arrives
- Stripe's webhook page lists each delivery with its response. A 400 means the secret on the Stripe screen is not this webhook's secret, or none is saved.
- Stripe retries for up to 3 days when a delivery fails, and Pixelary answers with an error when every one of your pixels refused the event, so a short outage at a platform loses nothing.
- Make sure the destination uses the snapshot payload. Pixelary ignores thin events.
Something here doesn’t match what you see? Write to hello@pixelary.app.