Skip to content

Investigate click-through tracking gaps: referrals at partners exceed DPLA counts #298

Description

@DominicBM

Reported Issue

A Texas hub partner reported that referrals from dp.la appearing in their own site analytics exceed the click-through counts shown in the DPLA Analytics Dashboard. This suggests DPLA is not capturing some portion of outbound clicks to partner sites.

How Click-Throughs Are Currently Tracked

Every "View Full Item" / "View Full Image" / "View Full Text" link on dp.la is given the CSS class clickThrough. A bindLinkEvent utility in dpla-frontend intercepts clicks on these links: it calls event.preventDefault(), fires a Click Through GA4 event via gtag.event(), then opens the partner URL in a new tab via window.open().

This binding happens in two places:

  • Item detail page (/item/[itemId]): bound in componentDidMount in components/ItemComponents/Content/index.js
  • Search results, lists, and topic browse pages: bound in a useEffect in components/shared/ListView/index.js, which fires after React hydration

Identified Gaps

1. Right-click / middle-click bypasses the event listener (most likely cause)

bindLinkEvent only intercepts left-click events via addEventListener("click", ...). It does not intercept:

  • Right-click → "Open link in new tab" (most browsers)
  • Middle-click (open in background tab)
  • Cmd+click / Ctrl+click (Mac/Windows equivalent)

All of these navigate the user to the partner site with Referer: dp.la, so the partner sees a referral — but DPLA never fires a Click Through event. This is the most likely explanation for the discrepancy and is structural: the current tracking architecture cannot capture these interactions.

A fix would require server-side redirect tracking (all external links route through a DPLA endpoint that logs the click, then redirects) or a mousedown listener instead of click, which fires regardless of which button is pressed.

2. Pre-hydration clicks on search results

On the search results page, the clickThrough event listener is bound inside a React useEffect, which runs after client-side hydration. Between when the server-rendered HTML arrives and when the effect fires, the "View Full Item" links are live but unbound — a fast user clicking immediately on page load could follow the link natively, generating a partner referral without a DPLA event.

3. Exhibitions — no click-through tracking

Exhibition pages (/exhibitions/...) track "View Exhibition Item" events when a user navigates to a new item within an exhibition. However, if an exhibition item has an external link to the partner site (a "View at source" style link), there is no Click Through event fired for it. Code search confirms: no clickThrough class, no bindLinkEvent call anywhere in components/ExhibitionsComponents/.

If exhibition pages surface external partner links, those clicks are untracked referrals.

4. Primary Source Sets — unclear

Code search found no clickThrough tracking within components/PrimarySourceSetsComponents/ beyond a sourceUrl prop passed to the CiteButton (used only for citation text). If PSS source item pages or teaching guide pages surface external links to partner content, those are not tracked.

Investigation Needed

  1. Quantify the right-click gap: Check if GA4 provides any signal on sessions/users that arrive at partner sites from dp.la vs. what DPLA records as click-throughs. The gap size will indicate whether right-click bypass alone explains the discrepancy.

  2. Audit exhibition and PSS pages for untracked external links: Confirm whether any exhibition or PSS page surfaces a "View at source" or equivalent link to a partner URL without a clickThrough binding.

  3. Evaluate server-side redirect tracking: Route all clickThrough links through a DPLA redirect endpoint (e.g. /out?url=...) that records the click server-side before redirecting. This would capture right-click, middle-click, and keyboard navigation, and would also allow accurate measurement of whether users actually reach the partner (vs. closing the tab before it loads). Downside: adds latency and a redirect hop.

  4. Evaluate mousedown listener: A lower-effort alternative to server-side redirects — binding on mousedown rather than click captures right-click and middle-click without the redirect infrastructure. Does not capture keyboard navigation.

/cc @megannp4

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingenhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions