Conversions API for Shopify, from the shop’s orders
Someone on r/FacebookAds described the native Shopify integration with Meta as counting purchases “like 3x”. A duplicate comes from several paths for the same purchase. Basketly reads the purchase from the order through the shop’s API and sends it to Meta server-side, and the purchase balance shows how many Meta actually accepted.
The demo has sample data; the login comes to your e-mail.
Where a duplicate purchase comes from
The Pixel in the browser and a send from the server are two paths for the same purchase. Meta counts it once only when both events carry the same id. When several tools in the shop send a purchase, a duplicate is easy to get and hard to find. So Basketly always sends the purchase with one fixed id, and the Purchase balance shows shop orders next to purchases Meta accepted.
What Basketly does on Shopify
You give the shop address (*.myshopify.com), the access token of a custom app made in the shop and that app’s API secret key. The app does the rest.
- Saving checks access by reading the shop, one order and one product. A refusal is named: wrong token, frozen shop, or a missing read_orders, read_products or read_customers permission.
- With the app’s API secret key the app subscribes to orders and products (order created and updated, product created, updated and deleted) and accepts a notification only with a valid signature and the shop’s own domain. Without the key orders come with the 15-minute read.
- A paid, not cancelled order becomes a purchase: value, currency, products from the lines, e-mail, phone (hashed before sending), the buyer’s IP from the order. A cancelled, fully refunded or voided order is not sent.
- Every purchase is saved first and then sent with retries. When Meta has an outage, the purchase waits instead of getting lost.
- Shopify products (title, description, shop link, image, price and compare-at price, SKU, barcode, vendor as brand, stock) land on the Products screen with a diagnosis for Google Merchant Center and the Meta catalogue, and from there in a fixed feed.
- Shopify’s limits are respected: after a throttling refusal the job waits and returns.
Connect Shopify in 4 steps
It takes a few minutes. You need no developer, but you will add a custom app in the shop.
Create a custom app in Shopify
In the shop create a custom app with read access to orders, products and customers. Note the Admin API access token (shpat_…) and the app’s API secret key.
Add the shop in the app
In Basketly open Integrations → Data sources → Add source, choose Shopify and enter a name and the shop address. From the source’s menu open the API connection, enter the *.myshopify.com address, the token and the app’s API secret key, tick the bought statuses and confirm the legal basis for passing the data.
Connect Meta and add the guide’s attribute
Sign in with your Meta account, choose the dataset (Pixel) and keep the purchase flow from the shop to Meta. The connection guide shows the shop script and the cart attribute with the id.
Check the first purchase
Click “Fetch now”, send a Test event with the code from Events Manager and, after the first orders, open the purchase balance.
Cash on delivery and statuses
An order with the financial status PAID is bought at once. With cash on delivery Shopify usually holds PENDING, so when connecting you can tick PENDING, AUTHORIZED or PARTIALLY_PAID as bought. Cancelled, fully refunded (REFUNDED) and voided (VOIDED) orders never become a purchase. Keep Meta’s limit in mind: a purchase older than 7 days is not accepted.
Tying the purchase to the visit, and history
The connection guide adds a cart attribute with the Basketly script’s id. The purchase then carries what the script saw during the visit, but only after the buyer’s consent, because the script runs only then. The 24-month order history is read once; without the read_all_orders permission Shopify gives only the last 60 days. Up to 25 lines are read from one order, and the order total is always whole.
How to check that it works
- Test event: one click sends the newest shop purchase with the test code from Events Manager, and you see it under Test Events.
- Purchase balance: shop orders next to purchases Meta accepted, day by day, with the most common error reasons.
- Self-check: compares the dataset’s statistics in Meta with what was actually sent, and says what to fix.
- Orders: each order shows whether its purchase was accepted, failed or is waiting.
What it does not do
- It does not switch off the native Shopify integration or other apps. If one also sends the purchase server-side, you have two server paths for the same purchase: keep one, or make sure both use the same event id, and check the result in Events Manager.
- It does not replace the Pixel in the browser: events such as product views or add to cart stay on the shop side. It is a second, independent path for purchases.
- Without the Basketly script in the shop and the buyer’s consent Meta gets no ad click id, so matching the purchase to an ad can be weaker.
- It does not make Meta’s numbers equal the shop’s: Meta counts purchases by its attribution windows. Both numbers are shown side by side.
- It does not send a purchase older than 7 days and does not work without the shop’s confirmed legal basis.
No. Whatever that integration does stays on the shop side, and Basketly adds the purchase from the order as a second path. If both send the same purchase, Meta counts it once only when they carry the same event id. The server sends shopify-order-<order id>, so after connecting check in Events Manager that purchases are not doubled.
With it the app subscribes to Shopify webhooks and checks their signature, so orders arrive at once. Without it the 15-minute read still works.
Yes, when you tick the financial status that counts as bought. The purchase goes after such a change, as long as the order is not older than 7 days.
The first read goes 7 days back, because Meta does not accept older purchases. The order history is read once into Orders and Clients but never sent to Meta.
The free plan covers up to 100 orders a month, with no card and no time limit. The limit counts orders, not sends to platforms. Other plans are on the pricing page.
See also
- Meta Conversions APIPaid shop orders sent to Meta from the server, through a queue that does not drop purchases, with a result for every delivery.Read
- Self-checkOne check of your whole setup: the shop, purchases sent to Meta, logins, background jobs and automations, with a link to the fix for every problem.Read
- Basketly vs StapeStape (server-side GTM, CAPI Gateway) next to Basketly (purchases from shop orders): a table, Stape's prices from its own page with the date, when to pick which.Read
- Conversions API (CAPI)Sending events, such as purchases, to Meta from the shop’s server instead of the buyer’s browser.Read
- Pixel and Conversions API Deduplication: event_id, event_name and the 48-Hour WindowHow Meta merges the same event from the Pixel and the Conversions API: event_id, event_name, the 48-hour window, the fbp method, common mistakes and how to check.Read
- Purchase balance: how to check that shop orders really reach Meta and other platformsHow to read the day-by-day purchase balance: shop orders, purchases Basketly accepted and sends to Meta and other platforms. What each gap means and what to check.Read
Get started in under 5 minutes
Connect your shop and Meta and see how many purchases really arrive.
- Free up to 100 orders a month
- No developer needed
- Purchase balance and self-check