Skip to content

Comments

Fix auto-tracking for SPA frameworks#365

Merged
marcospassos merged 7 commits intomasterfrom
fix-auto-tracking
Feb 11, 2026
Merged

Fix auto-tracking for SPA frameworks#365
marcospassos merged 7 commits intomasterfrom
fix-auto-tracking

Conversation

@marcospassos
Copy link
Member

Summary

In SPA frameworks like Next.js, the urlChange event fires synchronously before the framework updates the DOM. This causes two bugs: tracking stale JSON-LD data from the previous page, and missing the new page's data entirely since urlChange already fired by the time the framework renders.

This PR replaces urlChange-triggered DOM scanning with a MutationObserver that detects when new <script type="application/ld+json"> elements are added. The urlChange handler now only resets a per-page deduplication set, ensuring each entity is tracked at most once per page visit. A pageshow listener handles bfcache restoration for browser back/forward navigation.

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules
  • I have checked my code and corrected any misspellings

@marcospassos marcospassos added the bug Something isn't working label Feb 10, 2026
Copy link
Member

@Fryuni Fryuni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't this cause the opposite problem? Any framework that first changes the ld+json and then changes the URL will have the values tracked in the incorrect page.

@marcospassos
Copy link
Member Author

Won't this cause the opposite problem? Any framework that first changes the ld+json and then changes the URL will have the values tracked on the incorrect page.

This scenario is very uncommon in my opinion, but even if it happens, I think the behavior is acceptable:

  1. They change the JSON-LD → if already tracked, ignore; otherwise, track.
  2. Then they change the URL → always track (it's a new page with its own JSON-LD).

@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 10, 2026

Open in StackBlitz

npm i https://pkg.pr.new/@croct/plug@365

commit: 6e74dbd

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes auto-tracking issues in Single Page Application (SPA) frameworks by replacing synchronous URL change-based DOM scanning with an asynchronous MutationObserver pattern. Previously, the urlChange event would fire before frameworks updated the DOM, causing the plugin to track stale or missing JSON-LD data. The new implementation uses a MutationObserver to detect when JSON-LD script elements are added to the DOM, combined with per-page deduplication to ensure entities are only tracked once per page visit.

Changes:

  • Replaced synchronous urlChange-triggered DOM scanning with MutationObserver-based detection of new JSON-LD scripts
  • Added per-page deduplication using a Set to prevent tracking the same entity multiple times on a single page
  • Added pageshow event listener to handle browser back/forward cache (bfcache) restoration
  • Updated ts-jest to version 29.4.6

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 5 comments.

File Description
src/plugins/autoTracking/index.ts Added MutationObserver to watch for JSON-LD script additions, implemented deduplication via trackedEntities Set, changed urlChange handler to only clear dedup set, added pageshow handler for bfcache
test/plugins/autoTracking/index.test.ts Added comprehensive tests for MutationObserver functionality, deduplication behavior, URL change handling, and bfcache restoration with async test helper
package.json Updated ts-jest from ^29.0.3 to ^29.4.6

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

renan628
renan628 previously approved these changes Feb 10, 2026
@marcospassos
Copy link
Member Author

I just pushed a new, simpler approach: on urlChange, instead of scanning immediately, we now schedule the scan after a 1-second delay. Each new urlChange cancels the previous pending scan (debounce), and disable() also cancels it.

Scenario Before After
Initial page load Scans synchronously Scans synchronously (unchanged)
SPA navigation Scans immediately (stale DOM) Scans after 1s delay (updated DOM)
Rapid navigation Tracks every intermediate route Only tracks the final route
Plugin disabled mid-navigation Pending scan could still fire Pending scan is cancelled

Why 1 second?

JSON-LD is static metadata meant for crawlers, it's not dynamic content that changes after render. A 1-second delay gives the framework enough time to render the new route and insert updated <script type="application/ld+json"> elements, without the complexity of MutationObserver or deduplication logic.

Comment on lines +56 to +59
if (this.scanTimeout !== null) {
clearTimeout(this.scanTimeout);
this.scanTimeout = null;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conditional is only for TS to be happy. clearTimeout already ignores when it is called with null or undefined

@marcospassos marcospassos merged commit 329ea20 into master Feb 11, 2026
10 checks passed
@marcospassos marcospassos deleted the fix-auto-tracking branch February 11, 2026 12:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants