Skip to content

fix(capture): screenshot downloads out of network logs, tint no-CORS images, user-switch identity race - #179

Closed
boehlerlukas wants to merge 1 commit into
masterfrom
fix-e2e-followups-sdk
Closed

boehlerlukas wants to merge 1 commit into
masterfrom
fix-e2e-followups-sdk

Conversation

@boehlerlukas

Copy link
Copy Markdown
Contributor

Follow-ups from the live E2E run of 10-12 (design-handoffs/e2e-live-2026-10-12/capture.md B-06/B-07, kai-intake.md bug 7). No conflict with #178 (that one only touches GleapCaptureUI.js). Not released; no version bump, build/ and published/ untouched.

1. Screenshot downloads logged as the customer's failed requests (B-06)

Broken: a classic "Mark the bug" screenshot on a page with a no-CORS image logged the SDK's own download as GET …googlelogo… → FAILED (NetworkError) in the customer's network log; Kai Resolve read it as an app failure.
Cause: ScreenCapture.js inlines images/CSS with plain XHRs, which go through the patched XMLHttpRequest. The v2 render pauses the logger, but its fetches still show up later as timing-only RESOURCE entries (Resource Timing lists failed no-CORS fetches too).
Fix: GleapNetworkIntercepter.ignoreInternalRequest(url, xhr?, since?): a marked XHR is never recorded; a marked URL's Resource Timing entries from that moment on are dropped (bounded to 300 URLs, earlier app requests to the same URL stay). Classic capture marks its XHRs; the v2 render marks every image it asks for (via fetchFn) and every other asset (context.requests) at cleanup.

2. Cross-origin images without CORS missing from v2 screenshots (B-07), partly fixed

The classic flow keeps them because the server renders the HTML snapshot. A browser canvas can't read a no-CORS image, so the only way to match that is a Gleap image proxy. No such endpoint exists, and adding one is new server work with SSRF/abuse/size limits to handle, so that part is skipped. The tab-capture path keeps these images.
This PR: an <img> the render can't download gets a neutral tint (fetch.placeholderImage) instead of an empty hole, so the screenshot doesn't look like the app lost the image. CSS background images stay transparent. The fetch option replaces modern-screenshot's defaults, so requestInit: { cache: 'force-cache' } is set again explicitly.

3. Conversation filed for the previous contact after a user switch (kai-intake bug 7)

Broken: in one browser, page for user A, reload as user B, call startFeedbackFlow within about 5 s → 2 of about 15 conversations were created on A's session.
Cause (two races):

  • On reload the cached session (A) is restored synchronously and ready, so POST /sessions (A's credentials) and POST /sessions/identify (B) are in flight together. When /sessions answers last, validateSession(A) switches back to A, and the replay doesn't fire because A is identified.
  • startFeedbackFlow / startBot / askAI posted start-… to the Messenger right away, while the identify was still in flight, so the Messenger created the conversation with A. showSurvey already waited via onContactSettled; these didn't.

Fix: contactVersion is bumped when an identify/updateContact result or a logout replaces the session. A /sessions answer for a request sent before that bump is dropped (success and 4xx alike). startFeedbackFlowWithOptions (so also startFeedbackFlow and startClassicForm), startBot/startConversation and askAI run through onContactSettled. That is immediate when nothing is in flight and capped at 5 s.

Checks

  • npm test: 31 suites, 528 tests pass, incl. 4 new GleapSession tests (late /sessions answer keeps B, a late 4xx doesn't clear B, a normal refresh still applies, a flow start waits for the identify).
  • npm run build compiles (build output reverted, not committed).
  • Browser check (local page, real Chrome) of the interceptor source: classic-style internal XHR to a no-CORS image and the v2-style fetches are absent from getRequests(), though Resource Timing lists them. The app's own XHR and its failing fetch are still logged.
  • Headless Chrome with modern-screenshot 4.7.0: the no-CORS logo area samples [255,255,255] (hole) before and [235,235,235] (tint) after, and the canvas is still exportable.

🤖 Generated with Claude Code

…ownloadable images, fix user-switch race

- Network logs: the classic screenshot's own image/CSS XHRs were logged as
  the app's requests (a no-CORS image showed as "GET … FAILED", which Kai
  read). They are now marked internal and never recorded; the v2 DOM
  render's fetches (logger already paused) are also kept out of the
  Resource Timing entries.
- v2 DOM screenshot: an <img> the browser render can't download
  (cross-origin without CORS) gets a neutral tint instead of an empty hole.
- Identity: a /sessions answer for the cached contact that lands after
  Gleap.identify() switched the user no longer switches back (or clears
  the new contact); startFeedbackFlow / startClassicForm / startBot /
  startConversation / askAI wait for an identify in flight (max 5 s,
  like showSurvey) so the conversation isn't filed for the previous
  contact.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@boehlerlukas

Copy link
Copy Markdown
Contributor Author

Combined into #180 (one PR for all live E2E fixes).

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.

1 participant