Skip to content

PRO-2372: capture ad attribution and forward on login#10653

Closed
michaelfward wants to merge 1 commit intomainfrom
michael/PRO-2372-devtools-ad-attribution
Closed

PRO-2372: capture ad attribution and forward on login#10653
michaelfward wants to merge 1 commit intomainfrom
michael/PRO-2372-devtools-ad-attribution

Conversation

@michaelfward
Copy link
Copy Markdown
Contributor

captures ad click IDs (li_fat_id, twclid, rdt_cid) and UTM params from the URL on every app.replay.io page load, then forwards them as query params on the /login?... redirect so the dashboard can thread them into auth0's authorizationParams. ticket: PRO-2372.

how it works

  1. new src/ui/utils/adAttribution.ts exports captureAdAttribution / readAdAttribution / clearAdAttribution. first-touch semantics: once set in localStorage, we don't overwrite.
  2. pages/_app.tsx calls captureAdAttribution() in a useEffect on mount, so it runs regardless of auth state on every page load. SSR-safe via typeof window guard.
  3. src/ui/utils/auth.ts login() reads cached attribution and appends it to the /login?origin=...&returnTo=... redirect URL.
  4. logout() clears attribution so a second user on the same browser doesn't inherit the previous signup's click ID.

rollout order

  1. depends on the dashboard PR to pick up the params and forward to auth0, and the backend PR to persist them on first auth. shipping devtools standalone is harmless - attribution just ends up in a URL param the dashboard ignores until its own PR ships.

test plan

  • npx tsc --noEmit - clean
  • hit https://app.replay.io/?li_fat_id=smoke&utm_source=linkedin
  • devtools console: localStorage.getItem('replay_ad_attribution') shows the captured JSON
  • click Sign Up: outbound /login?... URL has li_fat_id=smoke&utm_source=linkedin appended
  • log out: localStorage.replay_ad_attribution is cleared

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
devtools Ready Ready Preview, Comment Apr 23, 2026 10:53am

Request Review

@replay-io
Copy link
Copy Markdown

replay-io Bot commented Apr 23, 2026

E2E Tests

Status Complete ↗︎
Commit 013f317
Results
4 Failed
  • inspector-computed-02: Complex computed styles can be viewed (Replay 1, Replay 2, Replay 3, Replay 4)
  • jump-to-code-01: Test basic jumping functionality (Replay 1, Replay 2, Replay 3, Replay 4)
  • object_preview-04: Test scope mapping and switching between generated/original sources (Replay 1, Replay 2, Replay 3, Replay 4)
  • stepping-06: Test stepping in async frames and async call stacks (Replay 1, Replay 2, Replay 3, Replay 4)
  • ⚠️ 27 Flaky
  • async-stack: should detect async stacks outside the focus window (Replay 1, Replay 2, Replay 3)
  • authenticated/logpoints-01: Shared logpoints functionality (Replay 1, Replay 2, Replay 3, Replay 4, Replay 5, Replay 6, Replay 7, Replay 8)
  • console_async: support console evaluations in async frames (Replay 1, Replay 2)
  • console_errors: Test that errors and warnings from various sources are shown in the console (Replay 1, Replay 2)
  • cypress-03: Test Step interactions (Replay 1, Replay 2)
  • cypress-04: Test Step buttons and menu item (Replay 1, Replay 2, Replay 3)
  • cypress-05: Test DOM node preview on user action step hover (Replay 1, Replay 2)
  • file-search-01: should search files (Replay 1, Replay 2)
  • inspector-elements-01: Basic DOM tree node display (Replay 1, Replay 2)
  • inspector-elements-02_node-picker: element picker and iframe behavior (Replay 1, Replay 2)
  • jump-to-code-02: Redux J2C functionality (Replay 1, Replay 2)
  • logpoints-04: should display exceptions in the console (Replay 1, Replay 2)
  • logpoints-11: too-many-points-to-run-analysis UX (Replay 1, Replay 2, Replay 3)
  • network-01: should filter requests by type and text (Replay 1, Replay 2)
  • network-03: should sync and display the current time in relation to the network requests (Replay 1, Replay 2)
  • node_object_preview: Showing console objects in node (Replay 1, Replay 2)
  • node_stepping-01: Test stepping in async frames and async call stacks (Replay 1, Replay 2)
  • playwright-04: Test Step buttons and menu item (Replay 1, Replay 2)
  • playwright-05: Test DOM node previews on user action step hover (Replay 1, Replay 2)
  • react_devtools-01: Basic RDT behavior (Replay 1, Replay 2)
  • react_devtools-02: RDT integrations (Chromium) (Replay 1, Replay 2)
  • repaint-02: repaints on hover (Replay 1, Replay 2)
  • repaint-03: repaints on seek (Replay 1, Replay 2)
  • repaint-04: prefers nearest (<=) paint when seeking between paints (Replay 1, Replay 2, Replay 3)
  • repaint-05: prefers current time if pause creation failed outside of the focus window (Replay 1, Replay 2)
  • source-line-highlights: Test source line highlighting (Replay 1, Replay 2)
  • stacking: Element highlighter selects the correct element when they overlap (Replay 1, Replay 2)
  • 70 Passed
  • authenticated/comments-01: Test add, edit, and delete comment functionality
  • authenticated/comments-02: Test shared comments and replies (Replay 1, Replay 2)
  • authenticated/comments-03: Comment previews
  • authenticated/passport-01: Time travel
  • authenticated/passport-02: Infrared inspection
  • authenticated/passport-03: Swiss army knife
  • authenticated/passport-04: Multiplayer
  • console_dock: Should show the correct docking behavior for recordings with video
  • console_eval: support console evaluations
  • console_warp-01: should support warping to console messages
  • console_warp-02: support pausing, warping, stepping and evaluating console messages
  • console-expressions-01: should cache input eager eval and terminal expressions per instance
  • cypress-01: Basic Test Suites panel functionality
  • cypress-02: Test Step timeline behavior
  • deleted-recording: Show error message for deleted recording
  • elements-search: Element panel should support basic and advanced search modes
  • fe-1875 :: verify that steps go to the right point in time
  • focus_mode-01: should filter messages as regions based on the active focus mode
  • highlighter: element highlighter works everywhere
  • inspector-computed-01: Basic computed styles can be viewed
  • inspector-elements-03: Nested node picker and selection behavior
  • inspector-elements-04: Keyboard shortcuts should select the right DOM nodes
  • inspector-elements-05_search: element picker and iframe behavior
  • inspector-rules-01: Basic CSS rules should be viewed
  • inspector-rules-03: Shorthand CSS rules should be viewed
  • logpoints-01: log-points appear in the correct order and allow time warping
  • logpoints-02: conditional log-points
  • logpoints-03: should display event properties in the console
  • logpoints-05: should auto-complete based on log point location
  • logpoints-06: should be temporarily disabled
  • logpoints-07: should use the correct scope in auto-complete
  • logpoints-08: should support jumping directly to a hit point via the capsule input
  • logpoints-09: should support pending edits
  • logpoints-10: too-many-points-to-find UX
  • logpoints-12: should auto save when removing conditions
  • logpoints-13: Test log point in a sourcemapped file
  • network-02: should show details for the selected request
  • node_console_dock: Should show the correct docking behavior for recordings without video
  • node_console-01: Basic node console behavior
  • node_console-02: uncaught exceptions should show up
  • node_control_flow: catch, finally, generators, and async/await
  • node_logpoint-01: Basic node logpoints
  • node_quick_open_modal-01: Test basic searching functionality
  • node_spawn: Basic subprocess spawning
  • node_worker-01: make sure node workers don't cause crashes
  • object_preview-01: expressions in the console after time warping
  • object_preview-02: should allow objects in scope to be inspected
  • object_preview-03: Test previews when switching between frames and stepping
  • object_preview-05: Should support logging objects as values
  • object_preview-06: HTML elements
  • object_preview-07: inspect objects in the console while paused somewhere else
  • object_preview-08: should render ellipsis for collapsed objects with truncated properties
  • playwright-01: Basic Test Suites panel functionality
  • playwright-02: Test Step timeline behavior
  • playwright-03: Test Step interactions
  • react_devtools-03: process and display multiple React versions in page
  • react_devtools-04: Component selection is maintained when seeking to a new point
  • redux_devtools: Test Redux DevTools.
  • repaint-01: repaints the screen screen when stepping over code that modifies the DOM
  • repaint-06: repaints the screen screen when stepping over code that modifies the DOM
  • resizable-panels-01: Left side Toolbar and Video should be collapsible
  • restart-session: restart debugging session
  • scopes_rerender: Test that scopes are rerendered
  • session-destroyed: errors caused by session failure should bubble to the root
  • sourcemap_stacktrace: Test that stacktraces are sourcemapped
  • stepping-01: Test basic step-over/back functionality
  • stepping-02: Test fixes for some simple stepping bugs
  • stepping-04: Test stepping in a frame other than the top frame
  • stepping-05: Test stepping in pretty-printed code
  • stepping-07: Test quick stepping using the keyboard
  • @michaelfward
    Copy link
    Copy Markdown
    Contributor Author

    closing. re-analyzed today: devtools only serves `/recording/*` (next.js basePath). ads never deep-link to a specific shared recording, so the capture logic in `_app.tsx` almost never fires from a real ad flow. app.replay.io/ (dashboard) is where users actually land from app-level signup CTAs, and replay.io/ (landing-page) is where they land from ads per tom.

    moving the capture to where it actually happens:

    • new landing-page PR: capture on first touch, write `.replay.io` cookie with 90d max-age (matching ad CVR window)
    • reworked dashboard Prevent markup view from destroying itself #195: read the cookie + belt-and-suspenders capture for users landing directly on app.replay.io
    • backend #12932 stays as-is (with segment event name fixed)
    • extension and cli PRs closed, same reason

    if shared-recording deep-link campaigns ever become a real channel, we'd re-open a devtools PR that reads the shared `.replay.io` cookie rather than maintain duplicate localStorage capture.

    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