[HELP REQUEST] Logging/Attributing Post-Purchase Extension Line Items

Hi Team,

We’re developing a Shopify app that includes a Post-Purchase UI Extension. Our primary goal is to reliably log and attribute specific line items that are added to an order because a customer accepted an offer within this post-purchase extension. We need to store metadata like source="post-purchase-offers", type="upsell", and potentially an internal offer/sale ID against the specific order_line_items record in our database (Prisma/PlanetScale).

We’ve explored two main approaches, encountering challenges with both:

1. Using Webhooks (orders/create, orders/update)

  • Attempt: We tried processing the orders/create and orders/update webhooks (handled in pages/api/webhooks/orders/create.ts and pages/api/webhooks/orders/update.ts respectively) to identify the newly added line item and update its metadata. We attempted to pass metadata via line item properties (e.g., _platter_sale, _platter_source) added during the extension’s calculateChangeset call, and also tried storing related data in the order’s note_attributes_json (via a separate API call) for the webhook to look up.
  • Challenge: Reliably associating the correct metadata at the time the line item is first processed by the webhook has been difficult.
    • We initially faced issues potentially creating duplicate order records or failing unique constraints (P2002 error when using prisma.orders.upsert in orders/update.ts, which we’ve since changed to prisma.orders.update with a fallback).
    • There seems to be a timing issue where the webhook might process the line item before our attribution metadata (e.g., from the note_attributes_json update) is available, or the line item properties added via calculateChangeset aren’t consistently available or sufficient for the lookup logic (see extractPlatterProperties and handle lookup logic in pages/api/webhooks/orders/update.ts).

2. Using Direct API Calls from the Extension

  • Attempt: After the applyChangeset call succeeds within the post-purchase extension (checkout-extensions/post-purchase-offers/pages/post-purchase-offers.tsxhandleAcceptOffer function), we trigger fetch calls to custom API endpoints in our app (/api/log-upsell, /api/log-post-purchase, /api/store-order-metadata) to directly log the event and associate metadata (like platterSaleId, source, type, numeric lineItemId, numeric variantId) with the order/line item in our database.
  • Challenge: We initially faced issues where these fetch calls weren’t executing, likely due to using relative URLs from the sandboxed extension environment.
    • We fixed this by using absolute URLs constructed from process.env.NEXT_PUBLIC_APP_URL (set correctly in Vercel).
    • We also corrected the payload for /api/log-upsell to send required numeric IDs.
    • Current Blocker: Despite these fixes, browser console logs show that the execution within handleAcceptOffer appears to be terminating after the successful call to sign the changeset (/api/sign-changeset returns 200 OK in Network tab) but before our PRE-FETCH console logs for the logging API calls (/api/log-upsell, etc.). This suggests a potential failure during or immediately after the Shopify applyChangeset(jwt) function call, preventing our subsequent logging logic from running. We’ve added detailed [PP DEBUG] console logs throughout handleAcceptOffer to pinpoint this, but the execution doesn’t seem to reach the point after applyChangeset completes successfully. (Note: We are also seeing persistent 400 errors for /api/post-purchase/logging and /api/post-purchase/analytics in logs, but believe these might be unrelated calls from older code/deployments as they aren’t explicitly called in the current handleAcceptOffer).

Our Question:

What is the recommended best practice for reliably attributing line items added via a post-purchase extension?

  • Is the webhook approach generally preferred, and if so, are there specific techniques or standard line item properties we should use during calculateChangeset that the orders/update webhook can reliably use for attribution before potentially creating/updating the line item record without the metadata?
  • Or is the direct API call approach viable? If so, what could be causing the execution to halt after applyChangeset succeeds but before our subsequent fetch calls are logged or made? Are there common pitfalls or limitations with executing fetch calls within the post-purchase extension environment after applyChangeset?

We need a robust way to ensure that when a line item is added via the post-purchase extension, we can definitively flag that specific order_line_items record in our database with the correct source and offer context.

Any guidance or pointers would be greatly appreciated. We’re happy to provide more detailed logs or code snippets if needed.

Thanks,
Jesse

1 Like

Hey @jlin :waving_hand: - definitely get where you’re coming from here. I can’t say for certain, but if you’re trying to make direct calls from within the extension on the frontend, you could be running into CORS errors as we generally prevent external API calls from being made from directly within the user’s browser by extensions/apps.

Our recommendation would be using webhooks as the best path forward, but I do understand where you’re coming from in terms of the timing.

One option that might work for your use case is to store the time data/variant.id/ other data you need to cross reference against the line item you’ll create in the Post Purchase offer within a Shopify Metafield itself (more info here).

Then, you could then run a reconciliation job through the admin API (an orders query, for example) after the post purchase offer is done fully processing (maybe set up a bulk reconciliation job every few minutes) to grab the data you stored in the metafield before the post-purchase offer was completed.

It’s not the most elegant workaround, but thought I would recommend this as a possible avenue. Let me know if I’m understanding your use case properly here or if I can help out further - hope this helps a bit though!