Skip to content

Prevent duplicate purchase events via localStorage deduplication - #43

Open
koenvdwetering wants to merge 1 commit into
masterfrom
claude/incoming-requests-duplicates-vuoodl
Open

Prevent duplicate purchase events via localStorage deduplication#43
koenvdwetering wants to merge 1 commit into
masterfrom
claude/incoming-requests-duplicates-vuoodl

Conversation

@koenvdwetering

Copy link
Copy Markdown

Summary

This change adds persistent browser-level deduplication for purchase events to prevent the same transaction from being tracked multiple times. Purchase events can be emitted from multiple sources (server-rendered layout events and customerData sections) and re-rendered on every success page reload, causing duplicate GTM events. This fix uses localStorage to track transaction IDs across page loads.

Key Changes

  • Added localStorage-based deduplication in both push.js and script-pusher.phtml:

    • Maintains a list of tracked transaction IDs in Tagging_GTM_PURCHASED_TRANSACTIONS localStorage key
    • Only applies to trytagging_purchase events (which carry stable ecommerce.transaction_id)
    • Checks if a transaction has already been tracked before pushing the event
    • Gracefully handles localStorage unavailability (private mode, disabled) by falling back to in-memory guard
  • Bounded storage management:

    • Keeps the transaction list limited to 50 most recent entries to prevent localStorage from growing indefinitely
    • Includes error handling for JSON parsing and storage operations
  • Version bump: Updated composer.json from 1.6.0 to 1.6.1

Implementation Details

The deduplication logic:

  1. Extracts the transaction_id from purchase events
  2. Retrieves the stored list of previously tracked transactions from localStorage
  3. Returns early if the transaction was already tracked (logs warning)
  4. Adds the new transaction ID to the list and persists it
  5. Maintains a sliding window of the 50 most recent transactions to bound storage usage

The implementation is identical in both files to ensure consistency across different template contexts (standard and Hyva theme).

https://claude.ai/code/session_01DQvtz7r6vxm64uRZ4YEKoi

The purchase event is pushed to the dataLayer by two independent
mechanisms on the success page (the server-rendered layout event via
data-layer.phtml, and the customerData "gtm-checkout" section via
generic.js). Their payloads differ, so the existing in-memory hash guard
(window.Tagging_GTM_PAST_EVENTS) does not deduplicate them. In addition,
the server-rendered event is built from checkoutSession->getLastRealOrder()
and re-fires on every reload/back-navigation of the success page, while the
hash guard resets on each page load.

Add a persistent, transaction_id-based dedup guard to both the Luma
(push.js) and Hyva (script-pusher.phtml) pushers. A trytagging_purchase is
now pushed at most once per browser per order, surviving reloads and the
dual push path, without removing either delivery path so a conversion is
never lost. Non-purchase events are unaffected (they carry no
ecommerce.transaction_id).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQvtz7r6vxm64uRZ4YEKoi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants