Capturing product impression without making the website slow

Solution for Capturing product impression without making the website slow
is Given Below:

I am working on a website where we have thousands of products. I have to capture the impression of all products users can see in their viewport. So I created a directory and I used IntersectionObserver, and referred to it inside the HTML code of that product. The issue is that it’s causing a performing impact on the mobile site as soon as the user scrolls. How can I capture impressions without slowing my website?

export class IntersectionObserverDirective
  implements OnDestroy, OnInit, AfterViewInit {
  @Input() debounceTime = 0;
  @Input() threshold = 1;

  @Output() visible = new EventEmitter<HTMLElement>();
  isSSR: boolean = typeof window === 'undefined';

  private observer: IntersectionObserver | undefined;
  private subject$ = new Subject<{
    entry: IntersectionObserverEntry;
    observer: IntersectionObserver;
  }>();

  constructor(private element: ElementRef) {}

  ngOnInit() {
      this.createObserver();
  }

  ngAfterViewInit() {
      this.startObservingElements();
  }

  ngOnDestroy() {
      if (this.observer) {
        this.observer.disconnect();
        this.observer = undefined;
      }
  
      this.subject$.next();
      this.subject$.complete();  
  }

  private isVisible(element: HTMLElement) {
    return new Promise(resolve => {
      const observer = new IntersectionObserver(([entry]) => {
        resolve(entry.intersectionRatio === 1);
        observer.disconnect();
      });

      observer.observe(element);
    });
  }

  private createObserver() {
    const options = {
      rootMargin: '0px',
      threshold: this.threshold,
    };

    const isIntersecting = (entry: IntersectionObserverEntry) =>
      entry.isIntersecting || entry.intersectionRatio > 0;

    this.observer = new IntersectionObserver((entries, observer) => {
      entries.forEach(entry => {
        if (isIntersecting(entry)) {
          this.subject$.next({ entry, observer });
        }
      });
    }, options);
  }

  private startObservingElements() {
    if (!this.observer) {
      return;
    }

    this.observer.observe(this.element.nativeElement);

    this.subject$
      .pipe(delay(this.debounceTime), filter(Boolean))
      .subscribe(async ({ entry, observer }) => {
        const target = entry.target as HTMLElement;
        const isStillVisible = await this.isVisible(target);

        if (isStillVisible) {
          this.visible.emit(target);
          observer.unobserve(target);
        }
      });
  }
}

Just add a timeout in createObserver(). Something like this.

private createObserver() {
        const options = {
            rootMargin: '0px',
            threshold: this.threshold,
        };
        let timeouts = {};
        const isIntersecting = (entry: IntersectionObserverEntry) =>
            entry.isIntersecting || entry.intersectionRatio > 0;
        this.observer = new IntersectionObserver((entries, observer) => {
            entries.forEach(entry => {
                if (isIntersecting(entry)) {
                    timeouts[entry.target.id] = setTimeout(() => {
                        this.subject.next({ entry, observer });
                    }, 500);
                }
                else {
                    clearTimeout(timeouts[entry.target.id])
                }
            });
        }, options);
    }

Google Analytics has robust scroll triggers, among a host of other tools. You should delegate the tracking to a party which has experience. GA is more standard, it has more value to a client, and you will learn more about users.

If you hate Google and must invent your own tool from the ground up, go ahead and don’t. The scroll and cursor fire off thousands of events a second and they bubble to multiple elements. Use GA for your clicks and heatmaps!